qhull-2020.2/0000755060175106010010000000000013724321437011174 5ustar bbarberqhull-2020.2/Announce.txt0000644060175106010010000000425213724316555013513 0ustar bbarber Qhull 2020.2 2020/08/31 (8.0.2) http://www.qhull.org http://github.com/qhull/qhull/wiki git@github.com:qhull/qhull.git http://www.geomview.org Qhull computes convex hulls, Delaunay triangulations, Voronoi diagrams, furthest-site Voronoi diagrams, and halfspace intersections about a point. It runs in 2-d, 3-d, 4-d, or higher. It implements the Quickhull algorithm for computing convex hulls. Qhull handles round-off errors from floating point arithmetic. It can approximate a convex hull. The program includes options for hull volume, facet area, partial hulls, input transformations, randomization, tracing, multiple output formats, and execution statistics. The program can be called from within your application. You can view the results in 2-d, 3-d and 4-d with Geomview. Download Qhull: http://www.qhull.org/download git@github.com:qhull/qhull.git Reference: Barber, C. B., D.P. Dobkin, and H.T. Huhdanpaa, "The Quickhull Algorithm for Convex Hulls," ACM Trans. on Mathematical Software, 22(4):469-483, Dec. 1996. http://portal.acm.org/citation.cfm?doid=235815.235821 http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.117.405 Abstract: The convex hull of a set of points is the smallest convex set that contains the points. This article presents a practical convex hull algorithm that combines the two-dimensional Quickhull Algorithm with the general dimension Beneath-Beyond Algorithm. It is similar to the randomized, incremental algorithms for convex hull and Delaunay triangulation. We provide empirical evidence that the algorithm runs faster when the input contains non-extreme points, and that it uses less memory. Computational geometry algorithms have traditionally assumed that input sets are well behaved. When an algorithm is implemented with floating point arithmetic, this assumption can lead to serious errors. We briefly describe a solution to this problem when computing the convex hull in two, three, or four dimensions. The output is a set of "thick" facets that contain all possible exact convex hulls of the input. A variation is effective in five or more dimensions. qhull-2020.2/build/0000755060175106010010000000000013724321344012270 5ustar bbarberqhull-2020.2/build/CMakeModules/0000755060175106010010000000000013724321330014574 5ustar bbarberqhull-2020.2/build/CMakeModules/CheckLFS.cmake0000644060175106010010000001006712600413304017157 0ustar bbarber## Checks for large file support ## include(CheckIncludeFile) include(CheckSymbolExists) include(CheckTypeSize) macro(check_lfs _isenable) set(LFS_OFF_T "") set(LFS_FOPEN "") set(LFS_FSEEK "") set(LFS_FTELL "") set(LFS_PRID "") if(${_isenable}) set(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}") set(CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} -D_LARGEFILE_SOURCE -D_LARGE_FILES -D_FILE_OFFSET_BITS=64 -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS) check_include_file("sys/types.h" HAVE_SYS_TYPES_H) check_include_file("inttypes.h" HAVE_INTTYPES_H) check_include_file("stddef.h" HAVE_STDDEF_H) check_include_file("stdint.h" HAVE_STDINT_H) # LFS type1: 8 <= sizeof(off_t), fseeko, ftello check_type_size("off_t" SIZEOF_OFF_T) if(SIZEOF_OFF_T GREATER 7) check_symbol_exists("fseeko" "stdio.h" HAVE_FSEEKO) check_symbol_exists("ftello" "stdio.h" HAVE_FTELLO) if(HAVE_FSEEKO AND HAVE_FTELLO) set(LFS_OFF_T "off_t") set(LFS_FOPEN "fopen") set(LFS_FSEEK "fseeko") set(LFS_FTELL "ftello") check_symbol_exists("PRIdMAX" "inttypes.h" HAVE_PRIDMAX) if(HAVE_PRIDMAX) set(LFS_PRID "PRIdMAX") else(HAVE_PRIDMAX) check_type_size("long" SIZEOF_LONG) check_type_size("int" SIZEOF_INT) if(SIZEOF_OFF_T GREATER SIZEOF_LONG) set(LFS_PRID "\"lld\"") elseif(SIZEOF_LONG GREATER SIZEOF_INT) set(LFS_PRID "\"ld\"") else(SIZEOF_OFF_T GREATER SIZEOF_LONG) set(LFS_PRID "\"d\"") endif(SIZEOF_OFF_T GREATER SIZEOF_LONG) endif(HAVE_PRIDMAX) endif(HAVE_FSEEKO AND HAVE_FTELLO) endif(SIZEOF_OFF_T GREATER 7) # LFS type2: 8 <= sizeof(off64_t), fopen64, fseeko64, ftello64 if(NOT LFS_OFF_T) check_type_size("off64_t" SIZEOF_OFF64_T) if(SIZEOF_OFF64_T GREATER 7) check_symbol_exists("fopen64" "stdio.h" HAVE_FOPEN64) check_symbol_exists("fseeko64" "stdio.h" HAVE_FSEEKO64) check_symbol_exists("ftello64" "stdio.h" HAVE_FTELLO64) if(HAVE_FOPEN64 AND HAVE_FSEEKO64 AND HAVE_FTELLO64) set(LFS_OFF_T "off64_t") set(LFS_FOPEN "fopen64") set(LFS_FSEEK "fseeko64") set(LFS_FTELL "ftello64") check_symbol_exists("PRIdMAX" "inttypes.h" HAVE_PRIDMAX) if(HAVE_PRIDMAX) set(LFS_PRID "PRIdMAX") else(HAVE_PRIDMAX) check_type_size("long" SIZEOF_LONG) check_type_size("int" SIZEOF_INT) if(SIZEOF_OFF64_T GREATER SIZEOF_LONG) set(LFS_PRID "\"lld\"") elseif(SIZEOF_LONG GREATER SIZEOF_INT) set(LFS_PRID "\"ld\"") else(SIZEOF_OFF64_T GREATER SIZEOF_LONG) set(LFS_PRID "\"d\"") endif(SIZEOF_OFF64_T GREATER SIZEOF_LONG) endif(HAVE_PRIDMAX) endif(HAVE_FOPEN64 AND HAVE_FSEEKO64 AND HAVE_FTELLO64) endif(SIZEOF_OFF64_T GREATER 7) endif(NOT LFS_OFF_T) # LFS type3: 8 <= sizeof(__int64), _fseeki64, _ftelli64 if(NOT LFS_OFF_T) check_type_size("__int64" SIZEOF___INT64) if(SIZEOF___INT64 GREATER 7) check_symbol_exists("_fseeki64" "stdio.h" HAVE__FSEEKI64) check_symbol_exists("_ftelli64" "stdio.h" HAVE__FTELLI64) if(HAVE__FSEEKI64 AND HAVE__FTELLI64) set(LFS_OFF_T "__int64") set(LFS_FOPEN "fopen") set(LFS_FSEEK "_fseeki64") set(LFS_FTELL "_ftelli64") set(LFS_PRID "\"I64d\"") endif(HAVE__FSEEKI64 AND HAVE__FTELLI64) endif(SIZEOF___INT64 GREATER 7) endif(NOT LFS_OFF_T) set(CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}") endif(${_isenable}) if(NOT LFS_OFF_T) ## not found set(LFS_OFF_T "long") set(LFS_FOPEN "fopen") set(LFS_FSEEK "fseek") set(LFS_FTELL "ftell") set(LFS_PRID "\"ld\"") endif(NOT LFS_OFF_T) endmacro(check_lfs) qhull-2020.2/build/config.cmake.in0000644060175106010010000000007113505527220015140 0ustar bbarberinclude("${CMAKE_CURRENT_LIST_DIR}/QhullTargets.cmake") qhull-2020.2/build/libqhull-32.vcxproj0000644060175106010010000004226612647335053015762 0ustar bbarber Debug Win32 Release Win32 MinSizeRel Win32 RelWithDebInfo Win32 {AE297F0D-5402-41C0-83B1-0194B583B67E} Win32Proj Win32 libqhull DynamicLibrary false MultiByte v110 DynamicLibrary false MultiByte v110 DynamicLibrary false MultiByte v110 DynamicLibrary false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ libqhull.dir\Debug\ qhull_d .dll false true ..\bin\ libqhull.dir\Release\ qhull .dll false true ..\bin\ libqhull.dir\MinSizeRel\ qhull .dll false true ..\bin\ libqhull.dir\RelWithDebInfo\ qhull .dll false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;libqhull_EXPORTS;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;libqhull_EXPORTS;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qhull_d.lib ../src/libqhull/qhull-exports.def ../bin/qhull_d.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;libqhull_EXPORTS;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;libqhull_EXPORTS;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qhull.lib ../src/libqhull/qhull-exports.def ../bin/qhull.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;libqhull_EXPORTS;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;libqhull_EXPORTS;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qhull.lib ../src/libqhull/qhull-exports.def ../bin/qhull.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;libqhull_EXPORTS;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;libqhull_EXPORTS;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qhull.lib ../src/libqhull/qhull-exports.def ../bin/qhull.pdb Console false qhull-2020.2/build/libqhull-64.vcxproj0000644060175106010010000004214212647335053015760 0ustar bbarber Debug x64 Release x64 MinSizeRel x64 RelWithDebInfo x64 {AE297F0D-5402-41C0-83B1-0194B583B67E} x64Proj x64 libqhull DynamicLibrary false MultiByte v110 DynamicLibrary false MultiByte v110 DynamicLibrary false MultiByte v110 DynamicLibrary false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ libqhull.dir\Debug\ qhull_d .dll false true ..\bin\ libqhull.dir\Release\ qhull .dll false true ..\bin\ libqhull.dir\MinSizeRel\ qhull .dll false true ..\bin\ libqhull.dir\RelWithDebInfo\ qhull .dll false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;libqhull_EXPORTS;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;libqhull_EXPORTS;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qhull_d.lib ../src/libqhull/qhull-exports.def ../bin/qhull_d.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;libqhull_EXPORTS;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;libqhull_EXPORTS;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qhull.lib ../src/libqhull/qhull-exports.def ../bin/qhull.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;libqhull_EXPORTS;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;libqhull_EXPORTS;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qhull.lib ../src/libqhull/qhull-exports.def ../bin/qhull.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;libqhull_EXPORTS;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;libqhull_EXPORTS;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qhull.lib ../src/libqhull/qhull-exports.def ../bin/qhull.pdb Console false qhull-2020.2/build/libqhull.vcproj0000644060175106010010000003114312642311011015317 0ustar bbarber qhull-2020.2/build/qconvex-32.vcxproj0000644060175106010010000003703712647335053015631 0ustar bbarber Debug Win32 Release Win32 MinSizeRel Win32 RelWithDebInfo Win32 {14FC642B-13AD-43EE-98A1-A15D9373B9BA} Win32Proj Win32 qconvex Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ qconvex.dir\Debug\ qconvex .exe false true ..\bin\ qconvex.dir\Release\ qconvex .exe false true ..\bin\ qconvex.dir\MinSizeRel\ qconvex .exe false true ..\bin\ qconvex.dir\RelWithDebInfo\ qconvex .exe false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic_d.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qconvex.lib ../bin/qconvex.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qconvex.lib ../bin/qconvex.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qconvex.lib ../bin/qconvex.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qconvex.lib ../bin/qconvex.pdb Console false F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B qhull-2020.2/build/qconvex-64.vcxproj0000644060175106010010000003671312647335053015636 0ustar bbarber Debug x64 Release x64 MinSizeRel x64 RelWithDebInfo x64 {14FC642B-13AD-43EE-98A1-A15D9373B9BA} x64Proj x64 qconvex Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ qconvex.dir\Debug\ qconvex .exe false true ..\bin\ qconvex.dir\Release\ qconvex .exe false true ..\bin\ qconvex.dir\MinSizeRel\ qconvex .exe false true ..\bin\ qconvex.dir\RelWithDebInfo\ qconvex .exe false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic_d.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qconvex.lib ../bin/qconvex.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qconvex.lib ../bin/qconvex.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qconvex.lib ../bin/qconvex.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qconvex.lib ../bin/qconvex.pdb Console false F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B qhull-2020.2/build/qconvex.vcproj0000644060175106010010000002454112642311011015172 0ustar bbarber qhull-2020.2/build/qdelaunay-32.vcxproj0000644060175106010010000003710312647335053016123 0ustar bbarber Debug Win32 Release Win32 MinSizeRel Win32 RelWithDebInfo Win32 {6120B9C5-847B-44DF-BD51-E3DCFC5BD7D8} Win32Proj Win32 qdelaunay Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ qdelaunay.dir\Debug\ qdelaunay .exe false true ..\bin\ qdelaunay.dir\Release\ qdelaunay .exe false true ..\bin\ qdelaunay.dir\MinSizeRel\ qdelaunay .exe false true ..\bin\ qdelaunay.dir\RelWithDebInfo\ qdelaunay .exe false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic_d.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qdelaunay.lib ../bin/qdelaunay.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qdelaunay.lib ../bin/qdelaunay.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qdelaunay.lib ../bin/qdelaunay.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qdelaunay.lib ../bin/qdelaunay.pdb Console false F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B qhull-2020.2/build/qdelaunay-64.vcxproj0000644060175106010010000003675712647335053016146 0ustar bbarber Debug x64 Release x64 MinSizeRel x64 RelWithDebInfo x64 {6120B9C5-847B-44DF-BD51-E3DCFC5BD7D8} x64Proj x64 qdelaunay Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ qdelaunay.dir\Debug\ qdelaunay .exe false true ..\bin\ qdelaunay.dir\Release\ qdelaunay .exe false true ..\bin\ qdelaunay.dir\MinSizeRel\ qdelaunay .exe false true ..\bin\ qdelaunay.dir\RelWithDebInfo\ qdelaunay .exe false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic_d.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qdelaunay.lib ../bin/qdelaunay.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qdelaunay.lib ../bin/qdelaunay.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qdelaunay.lib ../bin/qdelaunay.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qdelaunay.lib ../bin/qdelaunay.pdb Console false F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B qhull-2020.2/build/qdelaunay.vcproj0000644060175106010010000002461512642311011015474 0ustar bbarber qhull-2020.2/build/qhalf-32.vcxproj0000644060175106010010000003677112647335053015245 0ustar bbarber Debug Win32 Release Win32 MinSizeRel Win32 RelWithDebInfo Win32 {A5FC7430-68C4-4F67-BC69-C231FAC40A9A} Win32Proj Win32 qhalf Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ qhalf.dir\Debug\ qhalf .exe false true ..\bin\ qhalf.dir\Release\ qhalf .exe false true ..\bin\ qhalf.dir\MinSizeRel\ qhalf .exe false true ..\bin\ qhalf.dir\RelWithDebInfo\ qhalf .exe false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic_d.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qhalf.lib ../bin/qhalf.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qhalf.lib ../bin/qhalf.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qhalf.lib ../bin/qhalf.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qhalf.lib ../bin/qhalf.pdb Console false F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B qhull-2020.2/build/qhalf-64.vcxproj0000644060175106010010000003664512647335053015252 0ustar bbarber Debug x64 Release x64 MinSizeRel x64 RelWithDebInfo x64 {A5FC7430-68C4-4F67-BC69-C231FAC40A9A} x64Proj x64 qhalf Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ qhalf.dir\Debug\ qhalf .exe false true ..\bin\ qhalf.dir\Release\ qhalf .exe false true ..\bin\ qhalf.dir\MinSizeRel\ qhalf .exe false true ..\bin\ qhalf.dir\RelWithDebInfo\ qhalf .exe false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic_d.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qhalf.lib ../bin/qhalf.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qhalf.lib ../bin/qhalf.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qhalf.lib ../bin/qhalf.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qhalf.lib ../bin/qhalf.pdb Console false F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B qhull-2020.2/build/qhalf.vcproj0000644060175106010010000002446312642311011014605 0ustar bbarber qhull-2020.2/build/qhull-32.sln0000644060175106010010000004000213723325100014342 0ustar bbarberMicrosoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qconvex", "qconvex-32.vcxproj", "{14FC642B-13AD-43EE-98A1-A15D9373B9BA}" ProjectSection(ProjectDependencies) = postProject {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B} = {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qdelaunay", "qdelaunay-32.vcxproj", "{6120B9C5-847B-44DF-BD51-E3DCFC5BD7D8}" ProjectSection(ProjectDependencies) = postProject {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B} = {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qhalf", "qhalf-32.vcxproj", "{A5FC7430-68C4-4F67-BC69-C231FAC40A9A}" ProjectSection(ProjectDependencies) = postProject {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B} = {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qhull", "qhull-32.vcxproj", "{E8BF0EA0-A09D-4155-BCEC-CC1B0DF8A67E}" ProjectSection(ProjectDependencies) = postProject {526F05C7-E54E-4673-91DC-A3AF75041688} = {526F05C7-E54E-4673-91DC-A3AF75041688} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qhull_r", "qhull_r-32.vcxproj", "{D1E7C352-C0F9-4E64-B0CB-6C4371280C86}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qhullcpp", "qhullcpp-32.vcxproj", "{939F1F43-F252-486C-BB92-3166E44713A5}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qhullstatic", "qhullstatic-32.vcxproj", "{F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qhullstatic_r", "qhullstatic_r-32.vcxproj", "{526F05C7-E54E-4673-91DC-A3AF75041688}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qvoronoi", "qvoronoi-32.vcxproj", "{7A587B07-AE31-4071-9D8B-105BFA3815C9}" ProjectSection(ProjectDependencies) = postProject {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B} = {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rbox", "rbox-32.vcxproj", "{F3F597F4-08BF-4567-8866-D8A66BB1B9BE}" ProjectSection(ProjectDependencies) = postProject {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B} = {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testqset", "testqset-32.vcxproj", "{9ECBCBA4-269F-4ED1-B359-7522F9D19DDA}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testqset_r", "testqset_r-32.vcxproj", "{ACECEFF4-E332-4AD0-A89B-0D07A78FEA6A}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "user_eg", "user_eg-32.vcxproj", "{D1F6E2EB-53DB-44FB-AC8C-EC2A339683A7}" ProjectSection(ProjectDependencies) = postProject {D1E7C352-C0F9-4E64-B0CB-6C4371280C86} = {D1E7C352-C0F9-4E64-B0CB-6C4371280C86} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "user_eg2", "user_eg2-32.vcxproj", "{5564AE35-E8FE-4039-BD33-76B920D02BC9}" ProjectSection(ProjectDependencies) = postProject {526F05C7-E54E-4673-91DC-A3AF75041688} = {526F05C7-E54E-4673-91DC-A3AF75041688} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "user_eg3", "user_eg3-32.vcxproj", "{E615D779-7F0A-4521-B7AD-B3C0D328652E}" ProjectSection(ProjectDependencies) = postProject {939F1F43-F252-486C-BB92-3166E44713A5} = {939F1F43-F252-486C-BB92-3166E44713A5} {526F05C7-E54E-4673-91DC-A3AF75041688} = {526F05C7-E54E-4673-91DC-A3AF75041688} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qhulltest-32", "qhulltest\qhulltest-32.vcxproj", "{59F000B6-1AEC-3107-979D-510DA098577A}" ProjectSection(ProjectDependencies) = postProject {939F1F43-F252-486C-BB92-3166E44713A5} = {939F1F43-F252-486C-BB92-3166E44713A5} {526F05C7-E54E-4673-91DC-A3AF75041688} = {526F05C7-E54E-4673-91DC-A3AF75041688} EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 MinSizeRel|Win32 = MinSizeRel|Win32 Release|Win32 = Release|Win32 RelWithDebInfo|Win32 = RelWithDebInfo|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {AE297F0D-5402-41C0-83B1-0194B583B67E}.Debug|Win32.ActiveCfg = Debug|Win32 {AE297F0D-5402-41C0-83B1-0194B583B67E}.Debug|Win32.Build.0 = Debug|Win32 {AE297F0D-5402-41C0-83B1-0194B583B67E}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {AE297F0D-5402-41C0-83B1-0194B583B67E}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {AE297F0D-5402-41C0-83B1-0194B583B67E}.Release|Win32.ActiveCfg = Release|Win32 {AE297F0D-5402-41C0-83B1-0194B583B67E}.Release|Win32.Build.0 = Release|Win32 {AE297F0D-5402-41C0-83B1-0194B583B67E}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {AE297F0D-5402-41C0-83B1-0194B583B67E}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {14FC642B-13AD-43EE-98A1-A15D9373B9BA}.Debug|Win32.ActiveCfg = Debug|Win32 {14FC642B-13AD-43EE-98A1-A15D9373B9BA}.Debug|Win32.Build.0 = Debug|Win32 {14FC642B-13AD-43EE-98A1-A15D9373B9BA}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {14FC642B-13AD-43EE-98A1-A15D9373B9BA}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {14FC642B-13AD-43EE-98A1-A15D9373B9BA}.Release|Win32.ActiveCfg = Release|Win32 {14FC642B-13AD-43EE-98A1-A15D9373B9BA}.Release|Win32.Build.0 = Release|Win32 {14FC642B-13AD-43EE-98A1-A15D9373B9BA}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {14FC642B-13AD-43EE-98A1-A15D9373B9BA}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {6120B9C5-847B-44DF-BD51-E3DCFC5BD7D8}.Debug|Win32.ActiveCfg = Debug|Win32 {6120B9C5-847B-44DF-BD51-E3DCFC5BD7D8}.Debug|Win32.Build.0 = Debug|Win32 {6120B9C5-847B-44DF-BD51-E3DCFC5BD7D8}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {6120B9C5-847B-44DF-BD51-E3DCFC5BD7D8}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {6120B9C5-847B-44DF-BD51-E3DCFC5BD7D8}.Release|Win32.ActiveCfg = Release|Win32 {6120B9C5-847B-44DF-BD51-E3DCFC5BD7D8}.Release|Win32.Build.0 = Release|Win32 {6120B9C5-847B-44DF-BD51-E3DCFC5BD7D8}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {6120B9C5-847B-44DF-BD51-E3DCFC5BD7D8}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {A5FC7430-68C4-4F67-BC69-C231FAC40A9A}.Debug|Win32.ActiveCfg = Debug|Win32 {A5FC7430-68C4-4F67-BC69-C231FAC40A9A}.Debug|Win32.Build.0 = Debug|Win32 {A5FC7430-68C4-4F67-BC69-C231FAC40A9A}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {A5FC7430-68C4-4F67-BC69-C231FAC40A9A}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {A5FC7430-68C4-4F67-BC69-C231FAC40A9A}.Release|Win32.ActiveCfg = Release|Win32 {A5FC7430-68C4-4F67-BC69-C231FAC40A9A}.Release|Win32.Build.0 = Release|Win32 {A5FC7430-68C4-4F67-BC69-C231FAC40A9A}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {A5FC7430-68C4-4F67-BC69-C231FAC40A9A}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {E8BF0EA0-A09D-4155-BCEC-CC1B0DF8A67E}.Debug|Win32.ActiveCfg = Debug|Win32 {E8BF0EA0-A09D-4155-BCEC-CC1B0DF8A67E}.Debug|Win32.Build.0 = Debug|Win32 {E8BF0EA0-A09D-4155-BCEC-CC1B0DF8A67E}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {E8BF0EA0-A09D-4155-BCEC-CC1B0DF8A67E}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {E8BF0EA0-A09D-4155-BCEC-CC1B0DF8A67E}.Release|Win32.ActiveCfg = Release|Win32 {E8BF0EA0-A09D-4155-BCEC-CC1B0DF8A67E}.Release|Win32.Build.0 = Release|Win32 {E8BF0EA0-A09D-4155-BCEC-CC1B0DF8A67E}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {E8BF0EA0-A09D-4155-BCEC-CC1B0DF8A67E}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {9969E173-B078-4FC0-A35E-9F3B0FDA1CE9}.Debug|Win32.ActiveCfg = Debug|Win32 {9969E173-B078-4FC0-A35E-9F3B0FDA1CE9}.Debug|Win32.Build.0 = Debug|Win32 {9969E173-B078-4FC0-A35E-9F3B0FDA1CE9}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {9969E173-B078-4FC0-A35E-9F3B0FDA1CE9}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {9969E173-B078-4FC0-A35E-9F3B0FDA1CE9}.Release|Win32.ActiveCfg = Release|Win32 {9969E173-B078-4FC0-A35E-9F3B0FDA1CE9}.Release|Win32.Build.0 = Release|Win32 {9969E173-B078-4FC0-A35E-9F3B0FDA1CE9}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {9969E173-B078-4FC0-A35E-9F3B0FDA1CE9}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {D1E7C352-C0F9-4E64-B0CB-6C4371280C86}.Debug|Win32.ActiveCfg = Debug|Win32 {D1E7C352-C0F9-4E64-B0CB-6C4371280C86}.Debug|Win32.Build.0 = Debug|Win32 {D1E7C352-C0F9-4E64-B0CB-6C4371280C86}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {D1E7C352-C0F9-4E64-B0CB-6C4371280C86}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {D1E7C352-C0F9-4E64-B0CB-6C4371280C86}.Release|Win32.ActiveCfg = Release|Win32 {D1E7C352-C0F9-4E64-B0CB-6C4371280C86}.Release|Win32.Build.0 = Release|Win32 {D1E7C352-C0F9-4E64-B0CB-6C4371280C86}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {D1E7C352-C0F9-4E64-B0CB-6C4371280C86}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {939F1F43-F252-486C-BB92-3166E44713A5}.Debug|Win32.ActiveCfg = Debug|Win32 {939F1F43-F252-486C-BB92-3166E44713A5}.Debug|Win32.Build.0 = Debug|Win32 {939F1F43-F252-486C-BB92-3166E44713A5}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {939F1F43-F252-486C-BB92-3166E44713A5}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {939F1F43-F252-486C-BB92-3166E44713A5}.Release|Win32.ActiveCfg = Release|Win32 {939F1F43-F252-486C-BB92-3166E44713A5}.Release|Win32.Build.0 = Release|Win32 {939F1F43-F252-486C-BB92-3166E44713A5}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {939F1F43-F252-486C-BB92-3166E44713A5}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B}.Debug|Win32.ActiveCfg = Debug|Win32 {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B}.Debug|Win32.Build.0 = Debug|Win32 {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B}.Release|Win32.ActiveCfg = Release|Win32 {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B}.Release|Win32.Build.0 = Release|Win32 {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {526F05C7-E54E-4673-91DC-A3AF75041688}.Debug|Win32.ActiveCfg = Debug|Win32 {526F05C7-E54E-4673-91DC-A3AF75041688}.Debug|Win32.Build.0 = Debug|Win32 {526F05C7-E54E-4673-91DC-A3AF75041688}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {526F05C7-E54E-4673-91DC-A3AF75041688}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {526F05C7-E54E-4673-91DC-A3AF75041688}.Release|Win32.ActiveCfg = Release|Win32 {526F05C7-E54E-4673-91DC-A3AF75041688}.Release|Win32.Build.0 = Release|Win32 {526F05C7-E54E-4673-91DC-A3AF75041688}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {526F05C7-E54E-4673-91DC-A3AF75041688}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {7A587B07-AE31-4071-9D8B-105BFA3815C9}.Debug|Win32.ActiveCfg = Debug|Win32 {7A587B07-AE31-4071-9D8B-105BFA3815C9}.Debug|Win32.Build.0 = Debug|Win32 {7A587B07-AE31-4071-9D8B-105BFA3815C9}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {7A587B07-AE31-4071-9D8B-105BFA3815C9}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {7A587B07-AE31-4071-9D8B-105BFA3815C9}.Release|Win32.ActiveCfg = Release|Win32 {7A587B07-AE31-4071-9D8B-105BFA3815C9}.Release|Win32.Build.0 = Release|Win32 {7A587B07-AE31-4071-9D8B-105BFA3815C9}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {7A587B07-AE31-4071-9D8B-105BFA3815C9}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {F3F597F4-08BF-4567-8866-D8A66BB1B9BE}.Debug|Win32.ActiveCfg = Debug|Win32 {F3F597F4-08BF-4567-8866-D8A66BB1B9BE}.Debug|Win32.Build.0 = Debug|Win32 {F3F597F4-08BF-4567-8866-D8A66BB1B9BE}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {F3F597F4-08BF-4567-8866-D8A66BB1B9BE}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {F3F597F4-08BF-4567-8866-D8A66BB1B9BE}.Release|Win32.ActiveCfg = Release|Win32 {F3F597F4-08BF-4567-8866-D8A66BB1B9BE}.Release|Win32.Build.0 = Release|Win32 {F3F597F4-08BF-4567-8866-D8A66BB1B9BE}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {F3F597F4-08BF-4567-8866-D8A66BB1B9BE}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {9ECBCBA4-269F-4ED1-B359-7522F9D19DDA}.Debug|Win32.ActiveCfg = Debug|Win32 {9ECBCBA4-269F-4ED1-B359-7522F9D19DDA}.Debug|Win32.Build.0 = Debug|Win32 {9ECBCBA4-269F-4ED1-B359-7522F9D19DDA}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {9ECBCBA4-269F-4ED1-B359-7522F9D19DDA}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {9ECBCBA4-269F-4ED1-B359-7522F9D19DDA}.Release|Win32.ActiveCfg = Release|Win32 {9ECBCBA4-269F-4ED1-B359-7522F9D19DDA}.Release|Win32.Build.0 = Release|Win32 {9ECBCBA4-269F-4ED1-B359-7522F9D19DDA}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {9ECBCBA4-269F-4ED1-B359-7522F9D19DDA}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {ACECEFF4-E332-4AD0-A89B-0D07A78FEA6A}.Debug|Win32.ActiveCfg = Debug|Win32 {ACECEFF4-E332-4AD0-A89B-0D07A78FEA6A}.Debug|Win32.Build.0 = Debug|Win32 {ACECEFF4-E332-4AD0-A89B-0D07A78FEA6A}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {ACECEFF4-E332-4AD0-A89B-0D07A78FEA6A}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {ACECEFF4-E332-4AD0-A89B-0D07A78FEA6A}.Release|Win32.ActiveCfg = Release|Win32 {ACECEFF4-E332-4AD0-A89B-0D07A78FEA6A}.Release|Win32.Build.0 = Release|Win32 {ACECEFF4-E332-4AD0-A89B-0D07A78FEA6A}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {ACECEFF4-E332-4AD0-A89B-0D07A78FEA6A}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {D1F6E2EB-53DB-44FB-AC8C-EC2A339683A7}.Debug|Win32.ActiveCfg = Debug|Win32 {D1F6E2EB-53DB-44FB-AC8C-EC2A339683A7}.Debug|Win32.Build.0 = Debug|Win32 {D1F6E2EB-53DB-44FB-AC8C-EC2A339683A7}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {D1F6E2EB-53DB-44FB-AC8C-EC2A339683A7}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {D1F6E2EB-53DB-44FB-AC8C-EC2A339683A7}.Release|Win32.ActiveCfg = Release|Win32 {D1F6E2EB-53DB-44FB-AC8C-EC2A339683A7}.Release|Win32.Build.0 = Release|Win32 {D1F6E2EB-53DB-44FB-AC8C-EC2A339683A7}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {D1F6E2EB-53DB-44FB-AC8C-EC2A339683A7}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {5564AE35-E8FE-4039-BD33-76B920D02BC9}.Debug|Win32.ActiveCfg = Debug|Win32 {5564AE35-E8FE-4039-BD33-76B920D02BC9}.Debug|Win32.Build.0 = Debug|Win32 {5564AE35-E8FE-4039-BD33-76B920D02BC9}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {5564AE35-E8FE-4039-BD33-76B920D02BC9}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {5564AE35-E8FE-4039-BD33-76B920D02BC9}.Release|Win32.ActiveCfg = Release|Win32 {5564AE35-E8FE-4039-BD33-76B920D02BC9}.Release|Win32.Build.0 = Release|Win32 {5564AE35-E8FE-4039-BD33-76B920D02BC9}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {5564AE35-E8FE-4039-BD33-76B920D02BC9}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {E615D779-7F0A-4521-B7AD-B3C0D328652E}.Debug|Win32.ActiveCfg = Debug|Win32 {E615D779-7F0A-4521-B7AD-B3C0D328652E}.Debug|Win32.Build.0 = Debug|Win32 {E615D779-7F0A-4521-B7AD-B3C0D328652E}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {E615D779-7F0A-4521-B7AD-B3C0D328652E}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {E615D779-7F0A-4521-B7AD-B3C0D328652E}.Release|Win32.ActiveCfg = Release|Win32 {E615D779-7F0A-4521-B7AD-B3C0D328652E}.Release|Win32.Build.0 = Release|Win32 {E615D779-7F0A-4521-B7AD-B3C0D328652E}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {E615D779-7F0A-4521-B7AD-B3C0D328652E}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {59F000B6-1AEC-3107-979D-510DA098577A}.Debug|Win32.ActiveCfg = Debug|Win32 {59F000B6-1AEC-3107-979D-510DA098577A}.MinSizeRel|Win32.ActiveCfg = Release|Win32 {59F000B6-1AEC-3107-979D-510DA098577A}.Release|Win32.ActiveCfg = Release|Win32 {59F000B6-1AEC-3107-979D-510DA098577A}.RelWithDebInfo|Win32.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal qhull-2020.2/build/qhull-32.vcxproj0000644060175106010010000003700312647335054015265 0ustar bbarber Debug Win32 Release Win32 MinSizeRel Win32 RelWithDebInfo Win32 {E8BF0EA0-A09D-4155-BCEC-CC1B0DF8A67E} Win32Proj Win32 qhull Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ qhull.dir\Debug\ qhull .exe false true ..\bin\ qhull.dir\Release\ qhull .exe false true ..\bin\ qhull.dir\MinSizeRel\ qhull .exe false true ..\bin\ qhull.dir\RelWithDebInfo\ qhull .exe false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic_rd.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qhull.lib ../bin/qhull.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic_r.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qhull.lib ../bin/qhull.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic_r.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qhull.lib ../bin/qhull.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic_r.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qhull.lib ../bin/qhull.pdb Console false 526F05C7-E54E-4673-91DC-A3AF75041688 qhull-2020.2/build/qhull-64.sln0000644060175106010010000003670213723325623014375 0ustar bbarberMicrosoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qconvex", "qconvex-64.vcxproj", "{14FC642B-13AD-43EE-98A1-A15D9373B9BA}" ProjectSection(ProjectDependencies) = postProject {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B} = {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qdelaunay", "qdelaunay-64.vcxproj", "{6120B9C5-847B-44DF-BD51-E3DCFC5BD7D8}" ProjectSection(ProjectDependencies) = postProject {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B} = {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qhalf", "qhalf-64.vcxproj", "{A5FC7430-68C4-4F67-BC69-C231FAC40A9A}" ProjectSection(ProjectDependencies) = postProject {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B} = {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qhull", "qhull-64.vcxproj", "{E8BF0EA0-A09D-4155-BCEC-CC1B0DF8A67E}" ProjectSection(ProjectDependencies) = postProject {526F05C7-E54E-4673-91DC-A3AF75041688} = {526F05C7-E54E-4673-91DC-A3AF75041688} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qhull_r", "qhull_r-64.vcxproj", "{D1E7C352-C0F9-4E64-B0CB-6C4371280C86}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qhullcpp", "qhullcpp-64.vcxproj", "{939F1F43-F252-486C-BB92-3166E44713A5}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qhullstatic", "qhullstatic-64.vcxproj", "{F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qhullstatic_r", "qhullstatic_r-64.vcxproj", "{526F05C7-E54E-4673-91DC-A3AF75041688}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qvoronoi", "qvoronoi-64.vcxproj", "{7A587B07-AE31-4071-9D8B-105BFA3815C9}" ProjectSection(ProjectDependencies) = postProject {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B} = {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rbox", "rbox-64.vcxproj", "{F3F597F4-08BF-4567-8866-D8A66BB1B9BE}" ProjectSection(ProjectDependencies) = postProject {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B} = {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testqset", "testqset-64.vcxproj", "{9ECBCBA4-269F-4ED1-B359-7522F9D19DDA}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testqset_r", "testqset_r-64.vcxproj", "{ACECEFF4-E332-4AD0-A89B-0D07A78FEA6A}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "user_eg", "user_eg-64.vcxproj", "{D1F6E2EB-53DB-44FB-AC8C-EC2A339683A7}" ProjectSection(ProjectDependencies) = postProject {D1E7C352-C0F9-4E64-B0CB-6C4371280C86} = {D1E7C352-C0F9-4E64-B0CB-6C4371280C86} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "user_eg2", "user_eg2-64.vcxproj", "{5564AE35-E8FE-4039-BD33-76B920D02BC9}" ProjectSection(ProjectDependencies) = postProject {526F05C7-E54E-4673-91DC-A3AF75041688} = {526F05C7-E54E-4673-91DC-A3AF75041688} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "user_eg3", "user_eg3-64.vcxproj", "{E615D779-7F0A-4521-B7AD-B3C0D328652E}" ProjectSection(ProjectDependencies) = postProject {939F1F43-F252-486C-BB92-3166E44713A5} = {939F1F43-F252-486C-BB92-3166E44713A5} {526F05C7-E54E-4673-91DC-A3AF75041688} = {526F05C7-E54E-4673-91DC-A3AF75041688} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qhulltest-64", "qhulltest\qhulltest-64.vcxproj", "{59F000B6-1AEC-3107-979D-510DA098577A}" ProjectSection(ProjectDependencies) = postProject {939F1F43-F252-486C-BB92-3166E44713A5} = {939F1F43-F252-486C-BB92-3166E44713A5} {526F05C7-E54E-4673-91DC-A3AF75041688} = {526F05C7-E54E-4673-91DC-A3AF75041688} EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 MinSizeRel|x64 = MinSizeRel|x64 Release|x64 = Release|x64 RelWithDebInfo|x64 = RelWithDebInfo|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {AE297F0D-5402-41C0-83B1-0194B583B67E}.Debug|x64.ActiveCfg = Debug|x64 {AE297F0D-5402-41C0-83B1-0194B583B67E}.Debug|x64.Build.0 = Debug|x64 {AE297F0D-5402-41C0-83B1-0194B583B67E}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64 {AE297F0D-5402-41C0-83B1-0194B583B67E}.MinSizeRel|x64.Build.0 = MinSizeRel|x64 {AE297F0D-5402-41C0-83B1-0194B583B67E}.Release|x64.ActiveCfg = Release|x64 {AE297F0D-5402-41C0-83B1-0194B583B67E}.Release|x64.Build.0 = Release|x64 {AE297F0D-5402-41C0-83B1-0194B583B67E}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 {AE297F0D-5402-41C0-83B1-0194B583B67E}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 {14FC642B-13AD-43EE-98A1-A15D9373B9BA}.Debug|x64.ActiveCfg = Debug|x64 {14FC642B-13AD-43EE-98A1-A15D9373B9BA}.Debug|x64.Build.0 = Debug|x64 {14FC642B-13AD-43EE-98A1-A15D9373B9BA}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64 {14FC642B-13AD-43EE-98A1-A15D9373B9BA}.MinSizeRel|x64.Build.0 = MinSizeRel|x64 {14FC642B-13AD-43EE-98A1-A15D9373B9BA}.Release|x64.ActiveCfg = Release|x64 {14FC642B-13AD-43EE-98A1-A15D9373B9BA}.Release|x64.Build.0 = Release|x64 {14FC642B-13AD-43EE-98A1-A15D9373B9BA}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 {14FC642B-13AD-43EE-98A1-A15D9373B9BA}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 {6120B9C5-847B-44DF-BD51-E3DCFC5BD7D8}.Debug|x64.ActiveCfg = Debug|x64 {6120B9C5-847B-44DF-BD51-E3DCFC5BD7D8}.Debug|x64.Build.0 = Debug|x64 {6120B9C5-847B-44DF-BD51-E3DCFC5BD7D8}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64 {6120B9C5-847B-44DF-BD51-E3DCFC5BD7D8}.MinSizeRel|x64.Build.0 = MinSizeRel|x64 {6120B9C5-847B-44DF-BD51-E3DCFC5BD7D8}.Release|x64.ActiveCfg = Release|x64 {6120B9C5-847B-44DF-BD51-E3DCFC5BD7D8}.Release|x64.Build.0 = Release|x64 {6120B9C5-847B-44DF-BD51-E3DCFC5BD7D8}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 {6120B9C5-847B-44DF-BD51-E3DCFC5BD7D8}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 {A5FC7430-68C4-4F67-BC69-C231FAC40A9A}.Debug|x64.ActiveCfg = Debug|x64 {A5FC7430-68C4-4F67-BC69-C231FAC40A9A}.Debug|x64.Build.0 = Debug|x64 {A5FC7430-68C4-4F67-BC69-C231FAC40A9A}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64 {A5FC7430-68C4-4F67-BC69-C231FAC40A9A}.MinSizeRel|x64.Build.0 = MinSizeRel|x64 {A5FC7430-68C4-4F67-BC69-C231FAC40A9A}.Release|x64.ActiveCfg = Release|x64 {A5FC7430-68C4-4F67-BC69-C231FAC40A9A}.Release|x64.Build.0 = Release|x64 {A5FC7430-68C4-4F67-BC69-C231FAC40A9A}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 {A5FC7430-68C4-4F67-BC69-C231FAC40A9A}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 {E8BF0EA0-A09D-4155-BCEC-CC1B0DF8A67E}.Debug|x64.ActiveCfg = Debug|x64 {E8BF0EA0-A09D-4155-BCEC-CC1B0DF8A67E}.Debug|x64.Build.0 = Debug|x64 {E8BF0EA0-A09D-4155-BCEC-CC1B0DF8A67E}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64 {E8BF0EA0-A09D-4155-BCEC-CC1B0DF8A67E}.MinSizeRel|x64.Build.0 = MinSizeRel|x64 {E8BF0EA0-A09D-4155-BCEC-CC1B0DF8A67E}.Release|x64.ActiveCfg = Release|x64 {E8BF0EA0-A09D-4155-BCEC-CC1B0DF8A67E}.Release|x64.Build.0 = Release|x64 {E8BF0EA0-A09D-4155-BCEC-CC1B0DF8A67E}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 {E8BF0EA0-A09D-4155-BCEC-CC1B0DF8A67E}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 {9969E173-B078-4FC0-A35E-9F3B0FDA1CE9}.Debug|x64.ActiveCfg = Debug|x64 {9969E173-B078-4FC0-A35E-9F3B0FDA1CE9}.Debug|x64.Build.0 = Debug|x64 {9969E173-B078-4FC0-A35E-9F3B0FDA1CE9}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64 {9969E173-B078-4FC0-A35E-9F3B0FDA1CE9}.MinSizeRel|x64.Build.0 = MinSizeRel|x64 {9969E173-B078-4FC0-A35E-9F3B0FDA1CE9}.Release|x64.ActiveCfg = Release|x64 {9969E173-B078-4FC0-A35E-9F3B0FDA1CE9}.Release|x64.Build.0 = Release|x64 {9969E173-B078-4FC0-A35E-9F3B0FDA1CE9}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 {9969E173-B078-4FC0-A35E-9F3B0FDA1CE9}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 {D1E7C352-C0F9-4E64-B0CB-6C4371280C86}.Debug|x64.ActiveCfg = Debug|x64 {D1E7C352-C0F9-4E64-B0CB-6C4371280C86}.Debug|x64.Build.0 = Debug|x64 {D1E7C352-C0F9-4E64-B0CB-6C4371280C86}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64 {D1E7C352-C0F9-4E64-B0CB-6C4371280C86}.MinSizeRel|x64.Build.0 = MinSizeRel|x64 {D1E7C352-C0F9-4E64-B0CB-6C4371280C86}.Release|x64.ActiveCfg = Release|x64 {D1E7C352-C0F9-4E64-B0CB-6C4371280C86}.Release|x64.Build.0 = Release|x64 {D1E7C352-C0F9-4E64-B0CB-6C4371280C86}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 {D1E7C352-C0F9-4E64-B0CB-6C4371280C86}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 {939F1F43-F252-486C-BB92-3166E44713A5}.Debug|x64.ActiveCfg = Debug|x64 {939F1F43-F252-486C-BB92-3166E44713A5}.Debug|x64.Build.0 = Debug|x64 {939F1F43-F252-486C-BB92-3166E44713A5}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64 {939F1F43-F252-486C-BB92-3166E44713A5}.MinSizeRel|x64.Build.0 = MinSizeRel|x64 {939F1F43-F252-486C-BB92-3166E44713A5}.Release|x64.ActiveCfg = Release|x64 {939F1F43-F252-486C-BB92-3166E44713A5}.Release|x64.Build.0 = Release|x64 {939F1F43-F252-486C-BB92-3166E44713A5}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 {939F1F43-F252-486C-BB92-3166E44713A5}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B}.Debug|x64.ActiveCfg = Debug|x64 {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B}.Debug|x64.Build.0 = Debug|x64 {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64 {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B}.MinSizeRel|x64.Build.0 = MinSizeRel|x64 {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B}.Release|x64.ActiveCfg = Release|x64 {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B}.Release|x64.Build.0 = Release|x64 {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 {526F05C7-E54E-4673-91DC-A3AF75041688}.Debug|x64.ActiveCfg = Debug|x64 {526F05C7-E54E-4673-91DC-A3AF75041688}.Debug|x64.Build.0 = Debug|x64 {526F05C7-E54E-4673-91DC-A3AF75041688}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64 {526F05C7-E54E-4673-91DC-A3AF75041688}.MinSizeRel|x64.Build.0 = MinSizeRel|x64 {526F05C7-E54E-4673-91DC-A3AF75041688}.Release|x64.ActiveCfg = Release|x64 {526F05C7-E54E-4673-91DC-A3AF75041688}.Release|x64.Build.0 = Release|x64 {526F05C7-E54E-4673-91DC-A3AF75041688}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 {526F05C7-E54E-4673-91DC-A3AF75041688}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 {7A587B07-AE31-4071-9D8B-105BFA3815C9}.Debug|x64.ActiveCfg = Debug|x64 {7A587B07-AE31-4071-9D8B-105BFA3815C9}.Debug|x64.Build.0 = Debug|x64 {7A587B07-AE31-4071-9D8B-105BFA3815C9}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64 {7A587B07-AE31-4071-9D8B-105BFA3815C9}.MinSizeRel|x64.Build.0 = MinSizeRel|x64 {7A587B07-AE31-4071-9D8B-105BFA3815C9}.Release|x64.ActiveCfg = Release|x64 {7A587B07-AE31-4071-9D8B-105BFA3815C9}.Release|x64.Build.0 = Release|x64 {7A587B07-AE31-4071-9D8B-105BFA3815C9}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 {7A587B07-AE31-4071-9D8B-105BFA3815C9}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 {F3F597F4-08BF-4567-8866-D8A66BB1B9BE}.Debug|x64.ActiveCfg = Debug|x64 {F3F597F4-08BF-4567-8866-D8A66BB1B9BE}.Debug|x64.Build.0 = Debug|x64 {F3F597F4-08BF-4567-8866-D8A66BB1B9BE}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64 {F3F597F4-08BF-4567-8866-D8A66BB1B9BE}.MinSizeRel|x64.Build.0 = MinSizeRel|x64 {F3F597F4-08BF-4567-8866-D8A66BB1B9BE}.Release|x64.ActiveCfg = Release|x64 {F3F597F4-08BF-4567-8866-D8A66BB1B9BE}.Release|x64.Build.0 = Release|x64 {F3F597F4-08BF-4567-8866-D8A66BB1B9BE}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 {F3F597F4-08BF-4567-8866-D8A66BB1B9BE}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 {9ECBCBA4-269F-4ED1-B359-7522F9D19DDA}.Debug|x64.ActiveCfg = Debug|x64 {9ECBCBA4-269F-4ED1-B359-7522F9D19DDA}.Debug|x64.Build.0 = Debug|x64 {9ECBCBA4-269F-4ED1-B359-7522F9D19DDA}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64 {9ECBCBA4-269F-4ED1-B359-7522F9D19DDA}.MinSizeRel|x64.Build.0 = MinSizeRel|x64 {9ECBCBA4-269F-4ED1-B359-7522F9D19DDA}.Release|x64.ActiveCfg = Release|x64 {9ECBCBA4-269F-4ED1-B359-7522F9D19DDA}.Release|x64.Build.0 = Release|x64 {9ECBCBA4-269F-4ED1-B359-7522F9D19DDA}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 {9ECBCBA4-269F-4ED1-B359-7522F9D19DDA}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 {ACECEFF4-E332-4AD0-A89B-0D07A78FEA6A}.Debug|x64.ActiveCfg = Debug|x64 {ACECEFF4-E332-4AD0-A89B-0D07A78FEA6A}.Debug|x64.Build.0 = Debug|x64 {ACECEFF4-E332-4AD0-A89B-0D07A78FEA6A}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64 {ACECEFF4-E332-4AD0-A89B-0D07A78FEA6A}.MinSizeRel|x64.Build.0 = MinSizeRel|x64 {ACECEFF4-E332-4AD0-A89B-0D07A78FEA6A}.Release|x64.ActiveCfg = Release|x64 {ACECEFF4-E332-4AD0-A89B-0D07A78FEA6A}.Release|x64.Build.0 = Release|x64 {ACECEFF4-E332-4AD0-A89B-0D07A78FEA6A}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 {ACECEFF4-E332-4AD0-A89B-0D07A78FEA6A}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 {D1F6E2EB-53DB-44FB-AC8C-EC2A339683A7}.Debug|x64.ActiveCfg = Debug|x64 {D1F6E2EB-53DB-44FB-AC8C-EC2A339683A7}.Debug|x64.Build.0 = Debug|x64 {D1F6E2EB-53DB-44FB-AC8C-EC2A339683A7}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64 {D1F6E2EB-53DB-44FB-AC8C-EC2A339683A7}.MinSizeRel|x64.Build.0 = MinSizeRel|x64 {D1F6E2EB-53DB-44FB-AC8C-EC2A339683A7}.Release|x64.ActiveCfg = Release|x64 {D1F6E2EB-53DB-44FB-AC8C-EC2A339683A7}.Release|x64.Build.0 = Release|x64 {D1F6E2EB-53DB-44FB-AC8C-EC2A339683A7}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 {D1F6E2EB-53DB-44FB-AC8C-EC2A339683A7}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 {5564AE35-E8FE-4039-BD33-76B920D02BC9}.Debug|x64.ActiveCfg = Debug|x64 {5564AE35-E8FE-4039-BD33-76B920D02BC9}.Debug|x64.Build.0 = Debug|x64 {5564AE35-E8FE-4039-BD33-76B920D02BC9}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64 {5564AE35-E8FE-4039-BD33-76B920D02BC9}.MinSizeRel|x64.Build.0 = MinSizeRel|x64 {5564AE35-E8FE-4039-BD33-76B920D02BC9}.Release|x64.ActiveCfg = Release|x64 {5564AE35-E8FE-4039-BD33-76B920D02BC9}.Release|x64.Build.0 = Release|x64 {5564AE35-E8FE-4039-BD33-76B920D02BC9}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 {5564AE35-E8FE-4039-BD33-76B920D02BC9}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 {E615D779-7F0A-4521-B7AD-B3C0D328652E}.Debug|x64.ActiveCfg = Debug|x64 {E615D779-7F0A-4521-B7AD-B3C0D328652E}.Debug|x64.Build.0 = Debug|x64 {E615D779-7F0A-4521-B7AD-B3C0D328652E}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64 {E615D779-7F0A-4521-B7AD-B3C0D328652E}.MinSizeRel|x64.Build.0 = MinSizeRel|x64 {E615D779-7F0A-4521-B7AD-B3C0D328652E}.Release|x64.ActiveCfg = Release|x64 {E615D779-7F0A-4521-B7AD-B3C0D328652E}.Release|x64.Build.0 = Release|x64 {E615D779-7F0A-4521-B7AD-B3C0D328652E}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 {E615D779-7F0A-4521-B7AD-B3C0D328652E}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 {59F000B6-1AEC-3107-979D-510DA098577A}.Debug|x64.ActiveCfg = Debug|x64 {59F000B6-1AEC-3107-979D-510DA098577A}.MinSizeRel|x64.ActiveCfg = Release|x64 {59F000B6-1AEC-3107-979D-510DA098577A}.Release|x64.ActiveCfg = Release|x64 {59F000B6-1AEC-3107-979D-510DA098577A}.RelWithDebInfo|x64.ActiveCfg = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal qhull-2020.2/build/qhull-64.vcxproj0000644060175106010010000003665712647335054015310 0ustar bbarber Debug x64 Release x64 MinSizeRel x64 RelWithDebInfo x64 {E8BF0EA0-A09D-4155-BCEC-CC1B0DF8A67E} x64Proj x64 qhull Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ qhull.dir\Debug\ qhull .exe false true ..\bin\ qhull.dir\Release\ qhull .exe false true ..\bin\ qhull.dir\MinSizeRel\ qhull .exe false true ..\bin\ qhull.dir\RelWithDebInfo\ qhull .exe false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic_rd.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qhull.lib ../bin/qhull.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic_r.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qhull.lib ../bin/qhull.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic_r.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qhull.lib ../bin/qhull.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic_r.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qhull.lib ../bin/qhull.pdb Console false 526F05C7-E54E-4673-91DC-A3AF75041688 qhull-2020.2/build/qhull.pc.in0000644060175106010010000000037213710374261014351 0ustar bbarberprefix=@CMAKE_INSTALL_PREFIX@ libdir=${prefix}/@LIB_INSTALL_DIR@ includedir=${prefix}/@INCLUDE_INSTALL_DIR@ Name: @LIBRARY_NAME@ Description: @LIBRARY_DESCRIPTION@ Version: @qhull_VERSION@ Libs: -L${libdir} -l@LIBRARY_NAME@ Cflags: -I${includedir} qhull-2020.2/build/qhull.sln0000644060175106010010000004107213723325660014143 0ustar bbarberMicrosoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qconvex", "qconvex.vcproj", "{F909F400-6805-477F-B85B-5230DED4CB55}" ProjectSection(ProjectDependencies) = postProject {5B24F2E7-EF6E-4AF6-B2CE-1E049B1A12AC} = {5B24F2E7-EF6E-4AF6-B2CE-1E049B1A12AC} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qdelaunay", "qdelaunay.vcproj", "{10EB0D60-E1A6-41FC-BD86-A4BC5814B535}" ProjectSection(ProjectDependencies) = postProject {5B24F2E7-EF6E-4AF6-B2CE-1E049B1A12AC} = {5B24F2E7-EF6E-4AF6-B2CE-1E049B1A12AC} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qhalf", "qhalf.vcproj", "{4C67E982-8B07-43B8-836E-EB7495176740}" ProjectSection(ProjectDependencies) = postProject {5B24F2E7-EF6E-4AF6-B2CE-1E049B1A12AC} = {5B24F2E7-EF6E-4AF6-B2CE-1E049B1A12AC} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qhull", "qhull.vcproj", "{6D8411B9-813D-4DE4-84B5-56C0BC381A14}" ProjectSection(ProjectDependencies) = postProject {635EC42D-5C25-4D20-B5C2-D0A0034EB9B8} = {635EC42D-5C25-4D20-B5C2-D0A0034EB9B8} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qhull_r", "qhull_r.vcproj", "{DA9B53C4-2817-4E37-9181-E61959CBB0FE}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qhullcpp", "qhullcpp.vcproj", "{7326816B-C401-4ACA-8027-03BA7A98C16B}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qhullstatic", "qhullstatic.vcproj", "{5B24F2E7-EF6E-4AF6-B2CE-1E049B1A12AC}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qhullstatic_r", "qhullstatic_r.vcproj", "{635EC42D-5C25-4D20-B5C2-D0A0034EB9B8}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qvoronoi", "qvoronoi.vcproj", "{0807C09D-455C-417A-A979-2081F170C923}" ProjectSection(ProjectDependencies) = postProject {5B24F2E7-EF6E-4AF6-B2CE-1E049B1A12AC} = {5B24F2E7-EF6E-4AF6-B2CE-1E049B1A12AC} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rbox", "rbox.vcproj", "{1B7A1D90-AEDB-42A4-A1BD-B0C5CD430BF2}" ProjectSection(ProjectDependencies) = postProject {5B24F2E7-EF6E-4AF6-B2CE-1E049B1A12AC} = {5B24F2E7-EF6E-4AF6-B2CE-1E049B1A12AC} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testqset", "testqset.vcproj", "{2D714931-0586-42C5-A0F9-1A4ECD251890}" ProjectSection(ProjectDependencies) = postProject {5B24F2E7-EF6E-4AF6-B2CE-1E049B1A12AC} = {5B24F2E7-EF6E-4AF6-B2CE-1E049B1A12AC} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testqset_r", "testqset_r.vcproj", "{8C831027-7179-451A-9C7C-805381706037}" ProjectSection(ProjectDependencies) = postProject {635EC42D-5C25-4D20-B5C2-D0A0034EB9B8} = {635EC42D-5C25-4D20-B5C2-D0A0034EB9B8} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "user_eg", "user_eg.vcproj", "{6FE77AAD-0F23-416B-ABAC-C8A0A24F1441}" ProjectSection(ProjectDependencies) = postProject {DA9B53C4-2817-4E37-9181-E61959CBB0FE} = {DA9B53C4-2817-4E37-9181-E61959CBB0FE} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "user_eg2", "user_eg2.vcproj", "{782D2A68-F0EC-4D0E-B443-017E02FB53E8}" ProjectSection(ProjectDependencies) = postProject {635EC42D-5C25-4D20-B5C2-D0A0034EB9B8} = {635EC42D-5C25-4D20-B5C2-D0A0034EB9B8} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "user_eg3", "user_eg3.vcproj", "{83203305-79D5-412C-9819-0F9AD5C34EC1}" ProjectSection(ProjectDependencies) = postProject {7326816B-C401-4ACA-8027-03BA7A98C16B} = {7326816B-C401-4ACA-8027-03BA7A98C16B} {635EC42D-5C25-4D20-B5C2-D0A0034EB9B8} = {635EC42D-5C25-4D20-B5C2-D0A0034EB9B8} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qhulltest", "qhulltest\qhulltest.vcproj", "{E12E04D0-C11C-36C0-950E-A203DCBFB37C}" ProjectSection(ProjectDependencies) = postProject {635EC42D-5C25-4D20-B5C2-D0A0034EB9B8} = {635EC42D-5C25-4D20-B5C2-D0A0034EB9B8} {7326816B-C401-4ACA-8027-03BA7A98C16B} = {7326816B-C401-4ACA-8027-03BA7A98C16B} EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 MinSizeRel|Win32 = MinSizeRel|Win32 Release|Win32 = Release|Win32 RelWithDebInfo|Win32 = RelWithDebInfo|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {51BD63AB-336E-4215-B725-21F144BCBCBC}.Debug|Win32.ActiveCfg = Debug|Win32 {51BD63AB-336E-4215-B725-21F144BCBCBC}.Debug|Win32.Build.0 = Debug|Win32 {51BD63AB-336E-4215-B725-21F144BCBCBC}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {51BD63AB-336E-4215-B725-21F144BCBCBC}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {51BD63AB-336E-4215-B725-21F144BCBCBC}.Release|Win32.ActiveCfg = Release|Win32 {51BD63AB-336E-4215-B725-21F144BCBCBC}.Release|Win32.Build.0 = Release|Win32 {51BD63AB-336E-4215-B725-21F144BCBCBC}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {51BD63AB-336E-4215-B725-21F144BCBCBC}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {F909F400-6805-477F-B85B-5230DED4CB55}.Debug|Win32.ActiveCfg = Debug|Win32 {F909F400-6805-477F-B85B-5230DED4CB55}.Debug|Win32.Build.0 = Debug|Win32 {F909F400-6805-477F-B85B-5230DED4CB55}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {F909F400-6805-477F-B85B-5230DED4CB55}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {F909F400-6805-477F-B85B-5230DED4CB55}.Release|Win32.ActiveCfg = Release|Win32 {F909F400-6805-477F-B85B-5230DED4CB55}.Release|Win32.Build.0 = Release|Win32 {F909F400-6805-477F-B85B-5230DED4CB55}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {F909F400-6805-477F-B85B-5230DED4CB55}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {10EB0D60-E1A6-41FC-BD86-A4BC5814B535}.Debug|Win32.ActiveCfg = Debug|Win32 {10EB0D60-E1A6-41FC-BD86-A4BC5814B535}.Debug|Win32.Build.0 = Debug|Win32 {10EB0D60-E1A6-41FC-BD86-A4BC5814B535}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {10EB0D60-E1A6-41FC-BD86-A4BC5814B535}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {10EB0D60-E1A6-41FC-BD86-A4BC5814B535}.Release|Win32.ActiveCfg = Release|Win32 {10EB0D60-E1A6-41FC-BD86-A4BC5814B535}.Release|Win32.Build.0 = Release|Win32 {10EB0D60-E1A6-41FC-BD86-A4BC5814B535}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {10EB0D60-E1A6-41FC-BD86-A4BC5814B535}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {4C67E982-8B07-43B8-836E-EB7495176740}.Debug|Win32.ActiveCfg = Debug|Win32 {4C67E982-8B07-43B8-836E-EB7495176740}.Debug|Win32.Build.0 = Debug|Win32 {4C67E982-8B07-43B8-836E-EB7495176740}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {4C67E982-8B07-43B8-836E-EB7495176740}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {4C67E982-8B07-43B8-836E-EB7495176740}.Release|Win32.ActiveCfg = Release|Win32 {4C67E982-8B07-43B8-836E-EB7495176740}.Release|Win32.Build.0 = Release|Win32 {4C67E982-8B07-43B8-836E-EB7495176740}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {4C67E982-8B07-43B8-836E-EB7495176740}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {6D8411B9-813D-4DE4-84B5-56C0BC381A14}.Debug|Win32.ActiveCfg = Debug|Win32 {6D8411B9-813D-4DE4-84B5-56C0BC381A14}.Debug|Win32.Build.0 = Debug|Win32 {6D8411B9-813D-4DE4-84B5-56C0BC381A14}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {6D8411B9-813D-4DE4-84B5-56C0BC381A14}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {6D8411B9-813D-4DE4-84B5-56C0BC381A14}.Release|Win32.ActiveCfg = Release|Win32 {6D8411B9-813D-4DE4-84B5-56C0BC381A14}.Release|Win32.Build.0 = Release|Win32 {6D8411B9-813D-4DE4-84B5-56C0BC381A14}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {6D8411B9-813D-4DE4-84B5-56C0BC381A14}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {9A9C8B7B-2D5A-428E-A5D6-303FAF68AB19}.Debug|Win32.ActiveCfg = Debug|Win32 {9A9C8B7B-2D5A-428E-A5D6-303FAF68AB19}.Debug|Win32.Build.0 = Debug|Win32 {9A9C8B7B-2D5A-428E-A5D6-303FAF68AB19}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {9A9C8B7B-2D5A-428E-A5D6-303FAF68AB19}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {9A9C8B7B-2D5A-428E-A5D6-303FAF68AB19}.Release|Win32.ActiveCfg = Release|Win32 {9A9C8B7B-2D5A-428E-A5D6-303FAF68AB19}.Release|Win32.Build.0 = Release|Win32 {9A9C8B7B-2D5A-428E-A5D6-303FAF68AB19}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {9A9C8B7B-2D5A-428E-A5D6-303FAF68AB19}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {DA9B53C4-2817-4E37-9181-E61959CBB0FE}.Debug|Win32.ActiveCfg = Debug|Win32 {DA9B53C4-2817-4E37-9181-E61959CBB0FE}.Debug|Win32.Build.0 = Debug|Win32 {DA9B53C4-2817-4E37-9181-E61959CBB0FE}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {DA9B53C4-2817-4E37-9181-E61959CBB0FE}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {DA9B53C4-2817-4E37-9181-E61959CBB0FE}.Release|Win32.ActiveCfg = Release|Win32 {DA9B53C4-2817-4E37-9181-E61959CBB0FE}.Release|Win32.Build.0 = Release|Win32 {DA9B53C4-2817-4E37-9181-E61959CBB0FE}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {DA9B53C4-2817-4E37-9181-E61959CBB0FE}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {7326816B-C401-4ACA-8027-03BA7A98C16B}.Debug|Win32.ActiveCfg = Debug|Win32 {7326816B-C401-4ACA-8027-03BA7A98C16B}.Debug|Win32.Build.0 = Debug|Win32 {7326816B-C401-4ACA-8027-03BA7A98C16B}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {7326816B-C401-4ACA-8027-03BA7A98C16B}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {7326816B-C401-4ACA-8027-03BA7A98C16B}.Release|Win32.ActiveCfg = Release|Win32 {7326816B-C401-4ACA-8027-03BA7A98C16B}.Release|Win32.Build.0 = Release|Win32 {7326816B-C401-4ACA-8027-03BA7A98C16B}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {7326816B-C401-4ACA-8027-03BA7A98C16B}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {5B24F2E7-EF6E-4AF6-B2CE-1E049B1A12AC}.Debug|Win32.ActiveCfg = Debug|Win32 {5B24F2E7-EF6E-4AF6-B2CE-1E049B1A12AC}.Debug|Win32.Build.0 = Debug|Win32 {5B24F2E7-EF6E-4AF6-B2CE-1E049B1A12AC}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {5B24F2E7-EF6E-4AF6-B2CE-1E049B1A12AC}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {5B24F2E7-EF6E-4AF6-B2CE-1E049B1A12AC}.Release|Win32.ActiveCfg = Release|Win32 {5B24F2E7-EF6E-4AF6-B2CE-1E049B1A12AC}.Release|Win32.Build.0 = Release|Win32 {5B24F2E7-EF6E-4AF6-B2CE-1E049B1A12AC}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {5B24F2E7-EF6E-4AF6-B2CE-1E049B1A12AC}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {635EC42D-5C25-4D20-B5C2-D0A0034EB9B8}.Debug|Win32.ActiveCfg = Debug|Win32 {635EC42D-5C25-4D20-B5C2-D0A0034EB9B8}.Debug|Win32.Build.0 = Debug|Win32 {635EC42D-5C25-4D20-B5C2-D0A0034EB9B8}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {635EC42D-5C25-4D20-B5C2-D0A0034EB9B8}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {635EC42D-5C25-4D20-B5C2-D0A0034EB9B8}.Release|Win32.ActiveCfg = Release|Win32 {635EC42D-5C25-4D20-B5C2-D0A0034EB9B8}.Release|Win32.Build.0 = Release|Win32 {635EC42D-5C25-4D20-B5C2-D0A0034EB9B8}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {635EC42D-5C25-4D20-B5C2-D0A0034EB9B8}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {0807C09D-455C-417A-A979-2081F170C923}.Debug|Win32.ActiveCfg = Debug|Win32 {0807C09D-455C-417A-A979-2081F170C923}.Debug|Win32.Build.0 = Debug|Win32 {0807C09D-455C-417A-A979-2081F170C923}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {0807C09D-455C-417A-A979-2081F170C923}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {0807C09D-455C-417A-A979-2081F170C923}.Release|Win32.ActiveCfg = Release|Win32 {0807C09D-455C-417A-A979-2081F170C923}.Release|Win32.Build.0 = Release|Win32 {0807C09D-455C-417A-A979-2081F170C923}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {0807C09D-455C-417A-A979-2081F170C923}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {1B7A1D90-AEDB-42A4-A1BD-B0C5CD430BF2}.Debug|Win32.ActiveCfg = Debug|Win32 {1B7A1D90-AEDB-42A4-A1BD-B0C5CD430BF2}.Debug|Win32.Build.0 = Debug|Win32 {1B7A1D90-AEDB-42A4-A1BD-B0C5CD430BF2}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {1B7A1D90-AEDB-42A4-A1BD-B0C5CD430BF2}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {1B7A1D90-AEDB-42A4-A1BD-B0C5CD430BF2}.Release|Win32.ActiveCfg = Release|Win32 {1B7A1D90-AEDB-42A4-A1BD-B0C5CD430BF2}.Release|Win32.Build.0 = Release|Win32 {1B7A1D90-AEDB-42A4-A1BD-B0C5CD430BF2}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {1B7A1D90-AEDB-42A4-A1BD-B0C5CD430BF2}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {2D714931-0586-42C5-A0F9-1A4ECD251890}.Debug|Win32.ActiveCfg = Debug|Win32 {2D714931-0586-42C5-A0F9-1A4ECD251890}.Debug|Win32.Build.0 = Debug|Win32 {2D714931-0586-42C5-A0F9-1A4ECD251890}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {2D714931-0586-42C5-A0F9-1A4ECD251890}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {2D714931-0586-42C5-A0F9-1A4ECD251890}.Release|Win32.ActiveCfg = Release|Win32 {2D714931-0586-42C5-A0F9-1A4ECD251890}.Release|Win32.Build.0 = Release|Win32 {2D714931-0586-42C5-A0F9-1A4ECD251890}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {2D714931-0586-42C5-A0F9-1A4ECD251890}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {8C831027-7179-451A-9C7C-805381706037}.Debug|Win32.ActiveCfg = Debug|Win32 {8C831027-7179-451A-9C7C-805381706037}.Debug|Win32.Build.0 = Debug|Win32 {8C831027-7179-451A-9C7C-805381706037}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {8C831027-7179-451A-9C7C-805381706037}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {8C831027-7179-451A-9C7C-805381706037}.Release|Win32.ActiveCfg = Release|Win32 {8C831027-7179-451A-9C7C-805381706037}.Release|Win32.Build.0 = Release|Win32 {8C831027-7179-451A-9C7C-805381706037}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {8C831027-7179-451A-9C7C-805381706037}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {6FE77AAD-0F23-416B-ABAC-C8A0A24F1441}.Debug|Win32.ActiveCfg = Debug|Win32 {6FE77AAD-0F23-416B-ABAC-C8A0A24F1441}.Debug|Win32.Build.0 = Debug|Win32 {6FE77AAD-0F23-416B-ABAC-C8A0A24F1441}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {6FE77AAD-0F23-416B-ABAC-C8A0A24F1441}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {6FE77AAD-0F23-416B-ABAC-C8A0A24F1441}.Release|Win32.ActiveCfg = Release|Win32 {6FE77AAD-0F23-416B-ABAC-C8A0A24F1441}.Release|Win32.Build.0 = Release|Win32 {6FE77AAD-0F23-416B-ABAC-C8A0A24F1441}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {6FE77AAD-0F23-416B-ABAC-C8A0A24F1441}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {782D2A68-F0EC-4D0E-B443-017E02FB53E8}.Debug|Win32.ActiveCfg = Debug|Win32 {782D2A68-F0EC-4D0E-B443-017E02FB53E8}.Debug|Win32.Build.0 = Debug|Win32 {782D2A68-F0EC-4D0E-B443-017E02FB53E8}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {782D2A68-F0EC-4D0E-B443-017E02FB53E8}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {782D2A68-F0EC-4D0E-B443-017E02FB53E8}.Release|Win32.ActiveCfg = Release|Win32 {782D2A68-F0EC-4D0E-B443-017E02FB53E8}.Release|Win32.Build.0 = Release|Win32 {782D2A68-F0EC-4D0E-B443-017E02FB53E8}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {782D2A68-F0EC-4D0E-B443-017E02FB53E8}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {83203305-79D5-412C-9819-0F9AD5C34EC1}.Debug|Win32.ActiveCfg = Debug|Win32 {83203305-79D5-412C-9819-0F9AD5C34EC1}.Debug|Win32.Build.0 = Debug|Win32 {83203305-79D5-412C-9819-0F9AD5C34EC1}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 {83203305-79D5-412C-9819-0F9AD5C34EC1}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 {83203305-79D5-412C-9819-0F9AD5C34EC1}.Release|Win32.ActiveCfg = Release|Win32 {83203305-79D5-412C-9819-0F9AD5C34EC1}.Release|Win32.Build.0 = Release|Win32 {83203305-79D5-412C-9819-0F9AD5C34EC1}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 {83203305-79D5-412C-9819-0F9AD5C34EC1}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 {E12E04D0-C11C-36C0-950E-A203DCBFB37C}.Debug|Win32.ActiveCfg = Debug|Win32 {E12E04D0-C11C-36C0-950E-A203DCBFB37C}.Debug|Win32.Build.0 = Debug|Win32 {E12E04D0-C11C-36C0-950E-A203DCBFB37C}.MinSizeRel|Win32.ActiveCfg = Release|Win32 {E12E04D0-C11C-36C0-950E-A203DCBFB37C}.MinSizeRel|Win32.Build.0 = Release|Win32 {E12E04D0-C11C-36C0-950E-A203DCBFB37C}.Release|Win32.ActiveCfg = Release|Win32 {E12E04D0-C11C-36C0-950E-A203DCBFB37C}.Release|Win32.Build.0 = Release|Win32 {E12E04D0-C11C-36C0-950E-A203DCBFB37C}.RelWithDebInfo|Win32.ActiveCfg = Release|Win32 {E12E04D0-C11C-36C0-950E-A203DCBFB37C}.RelWithDebInfo|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal qhull-2020.2/build/qhull.vcproj0000644060175106010010000002447312642311011014640 0ustar bbarber qhull-2020.2/build/qhullcpp-32.vcxproj0000644060175106010010000003406713662345301015771 0ustar bbarber Debug Win32 Release Win32 MinSizeRel Win32 RelWithDebInfo Win32 {939F1F43-F252-486C-BB92-3166E44713A5} Win32Proj Win32 qhullcpp StaticLibrary false MultiByte v110 StaticLibrary false MultiByte v110 StaticLibrary false MultiByte v110 StaticLibrary false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\lib\ qhullcpp.dir\Debug\ qhullcpp_d .lib ..\lib\ qhullcpp.dir\Release\ qhullcpp .lib ..\lib\ qhullcpp.dir\MinSizeRel\ qhullcpp .lib ..\lib\ qhullcpp.dir\RelWithDebInfo\ qhullcpp .lib ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsCpp ProgramDatabase Sync Disabled Disabled NotUsing MultiThreadedDebugDLL true Level3 WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsCpp Sync AnySuitable MaxSpeed NotUsing MultiThreadedDLL true Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsCpp Sync OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL true Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsCpp ProgramDatabase Sync OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL true Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c qhull-2020.2/build/qhullcpp-64.vcxproj0000644060175106010010000003376313662345301016000 0ustar bbarber Debug x64 Release x64 MinSizeRel x64 RelWithDebInfo x64 {939F1F43-F252-486C-BB92-3166E44713A5} x64Proj x64 qhullcpp StaticLibrary false MultiByte v110 StaticLibrary false MultiByte v110 StaticLibrary false MultiByte v110 StaticLibrary false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\lib\ qhullcpp.dir\Debug\ qhullcpp_d .lib ..\lib\ qhullcpp.dir\Release\ qhullcpp .lib ..\lib\ qhullcpp.dir\MinSizeRel\ qhullcpp .lib ..\lib\ qhullcpp.dir\RelWithDebInfo\ qhullcpp .lib ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsCpp ProgramDatabase Sync Disabled Disabled NotUsing MultiThreadedDebugDLL true Level3 WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsCpp Sync AnySuitable MaxSpeed NotUsing MultiThreadedDLL true Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsCpp Sync OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL true Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsCpp ProgramDatabase Sync OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL true Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c qhull-2020.2/build/qhullcpp.vcproj0000644060175106010010000002720013662345153015353 0ustar bbarber qhull-2020.2/build/qhullstatic-32.vcxproj0000644060175106010010000003105112647335055016473 0ustar bbarber Debug Win32 Release Win32 MinSizeRel Win32 RelWithDebInfo Win32 {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B} Win32Proj Win32 qhullstatic StaticLibrary false MultiByte v110 StaticLibrary false MultiByte v110 StaticLibrary false MultiByte v110 StaticLibrary false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\lib\ qhullstatic.dir\Debug\ qhullstatic_d .lib ..\lib\ qhullstatic.dir\Release\ qhullstatic .lib ..\lib\ qhullstatic.dir\MinSizeRel\ qhullstatic .lib ..\lib\ qhullstatic.dir\RelWithDebInfo\ qhullstatic .lib ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c qhull-2020.2/build/qhullstatic-64.vcxproj0000644060175106010010000003074512647335055016511 0ustar bbarber Debug x64 Release x64 MinSizeRel x64 RelWithDebInfo x64 {F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B} x64Proj x64 qhullstatic StaticLibrary false MultiByte v110 StaticLibrary false MultiByte v110 StaticLibrary false MultiByte v110 StaticLibrary false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\lib\ qhullstatic.dir\Debug\ qhullstatic_d .lib ..\lib\ qhullstatic.dir\Release\ qhullstatic .lib ..\lib\ qhullstatic.dir\MinSizeRel\ qhullstatic .lib ..\lib\ qhullstatic.dir\RelWithDebInfo\ qhullstatic .lib ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c qhull-2020.2/build/qhullstatic.vcproj0000644060175106010010000002371512642311011016046 0ustar bbarber qhull-2020.2/build/qhullstatic_r-32.vcxproj0000644060175106010010000003125112647335055017016 0ustar bbarber Debug Win32 Release Win32 MinSizeRel Win32 RelWithDebInfo Win32 {526F05C7-E54E-4673-91DC-A3AF75041688} Win32Proj Win32 qhullstatic_r StaticLibrary false MultiByte v110 StaticLibrary false MultiByte v110 StaticLibrary false MultiByte v110 StaticLibrary false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\lib\ qhullstatic_r.dir\Debug\ qhullstatic_rd .lib ..\lib\ qhullstatic_r.dir\Release\ qhullstatic_r .lib ..\lib\ qhullstatic_r.dir\MinSizeRel\ qhullstatic_r .lib ..\lib\ qhullstatic_r.dir\RelWithDebInfo\ qhullstatic_r .lib ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c qhull-2020.2/build/qhullstatic_r-64.vcxproj0000644060175106010010000003114512647335055017025 0ustar bbarber Debug x64 Release x64 MinSizeRel x64 RelWithDebInfo x64 {526F05C7-E54E-4673-91DC-A3AF75041688} x64Proj x64 qhullstatic_r StaticLibrary false MultiByte v110 StaticLibrary false MultiByte v110 StaticLibrary false MultiByte v110 StaticLibrary false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\lib\ qhullstatic_r.dir\Debug\ qhullstatic_rd .lib ..\lib\ qhullstatic_r.dir\Release\ qhullstatic_r .lib ..\lib\ qhullstatic_r.dir\MinSizeRel\ qhullstatic_r .lib ..\lib\ qhullstatic_r.dir\RelWithDebInfo\ qhullstatic_r .lib ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c qhull-2020.2/build/qhullstatic_r.vcproj0000644060175106010010000002412512642311011016363 0ustar bbarber qhull-2020.2/build/qhull_p-32.vcxproj0000644060175106010010000004245612647335054015614 0ustar bbarber Debug Win32 Release Win32 MinSizeRel Win32 RelWithDebInfo Win32 {9969E173-B078-4FC0-A35E-9F3B0FDA1CE9} Win32Proj Win32 qhull_p DynamicLibrary false MultiByte v110 DynamicLibrary false MultiByte v110 DynamicLibrary false MultiByte v110 DynamicLibrary false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ qhull_p.dir\Debug\ qhull_pd .dll false true ..\bin\ qhull_p.dir\Release\ qhull_p .dll false true ..\bin\ qhull_p.dir\MinSizeRel\ qhull_p .dll false true ..\bin\ qhull_p.dir\RelWithDebInfo\ qhull_p .dll false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;qh_QHpointer;qhull_p_EXPORTS;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;qh_QHpointer;qhull_p_EXPORTS;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qhull_pd.lib ../src/libqhull/qhull_p-exports.def ../bin/qhull_pd.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;qh_QHpointer;qhull_p_EXPORTS;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;qh_QHpointer;qhull_p_EXPORTS;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qhull_p.lib ../src/libqhull/qhull_p-exports.def ../bin/qhull_p.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;qh_QHpointer;qhull_p_EXPORTS;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;qh_QHpointer;qhull_p_EXPORTS;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qhull_p.lib ../src/libqhull/qhull_p-exports.def ../bin/qhull_p.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;qh_QHpointer;qhull_p_EXPORTS;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;qh_QHpointer;qhull_p_EXPORTS;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qhull_p.lib ../src/libqhull/qhull_p-exports.def ../bin/qhull_p.pdb Console false qhull-2020.2/build/qhull_p-64.vcxproj0000644060175106010010000004233212647335054015612 0ustar bbarber Debug x64 Release x64 MinSizeRel x64 RelWithDebInfo x64 {9969E173-B078-4FC0-A35E-9F3B0FDA1CE9} x64Proj x64 qhull_p DynamicLibrary false MultiByte v110 DynamicLibrary false MultiByte v110 DynamicLibrary false MultiByte v110 DynamicLibrary false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ qhull_p.dir\Debug\ qhull_pd .dll false true ..\bin\ qhull_p.dir\Release\ qhull_p .dll false true ..\bin\ qhull_p.dir\MinSizeRel\ qhull_p .dll false true ..\bin\ qhull_p.dir\RelWithDebInfo\ qhull_p .dll false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;qh_QHpointer;qhull_p_EXPORTS;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;qh_QHpointer;qhull_p_EXPORTS;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qhull_pd.lib ../src/libqhull/qhull_p-exports.def ../bin/qhull_pd.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;qh_QHpointer;qhull_p_EXPORTS;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;qh_QHpointer;qhull_p_EXPORTS;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qhull_p.lib ../src/libqhull/qhull_p-exports.def ../bin/qhull_p.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;qh_QHpointer;qhull_p_EXPORTS;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;qh_QHpointer;qhull_p_EXPORTS;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qhull_p.lib ../src/libqhull/qhull_p-exports.def ../bin/qhull_p.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;qh_QHpointer;qhull_p_EXPORTS;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;qh_QHpointer;qhull_p_EXPORTS;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qhull_p.lib ../src/libqhull/qhull_p-exports.def ../bin/qhull_p.pdb Console false qhull-2020.2/build/qhull_p.vcproj0000644060175106010010000003135012642311011015147 0ustar bbarber qhull-2020.2/build/qhull_r-32.vcxproj0000644060175106010010000004247512647335054015617 0ustar bbarber Debug Win32 Release Win32 MinSizeRel Win32 RelWithDebInfo Win32 {D1E7C352-C0F9-4E64-B0CB-6C4371280C86} Win32Proj Win32 qhull_r DynamicLibrary false MultiByte v110 DynamicLibrary false MultiByte v110 DynamicLibrary false MultiByte v110 DynamicLibrary false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ qhull_r.dir\Debug\ qhull_rd .dll false true ..\bin\ qhull_r.dir\Release\ qhull_r .dll false true ..\bin\ qhull_r.dir\MinSizeRel\ qhull_r .dll false true ..\bin\ qhull_r.dir\RelWithDebInfo\ qhull_r .dll false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;qhull_r_EXPORTS;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;qhull_r_EXPORTS;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qhull_rd.lib ../src/libqhull_r/qhull_r-exports.def ../bin/qhull_rd.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;qhull_r_EXPORTS;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;qhull_r_EXPORTS;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qhull_r.lib ../src/libqhull_r/qhull_r-exports.def ../bin/qhull_r.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;qhull_r_EXPORTS;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;qhull_r_EXPORTS;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qhull_r.lib ../src/libqhull_r/qhull_r-exports.def ../bin/qhull_r.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;qhull_r_EXPORTS;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;qhull_r_EXPORTS;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qhull_r.lib ../src/libqhull_r/qhull_r-exports.def ../bin/qhull_r.pdb Console false qhull-2020.2/build/qhull_r-64.vcxproj0000644060175106010010000004235112647335055015616 0ustar bbarber Debug x64 Release x64 MinSizeRel x64 RelWithDebInfo x64 {D1E7C352-C0F9-4E64-B0CB-6C4371280C86} x64Proj x64 qhull_r DynamicLibrary false MultiByte v110 DynamicLibrary false MultiByte v110 DynamicLibrary false MultiByte v110 DynamicLibrary false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ qhull_r.dir\Debug\ qhull_rd .dll false true ..\bin\ qhull_r.dir\Release\ qhull_r .dll false true ..\bin\ qhull_r.dir\MinSizeRel\ qhull_r .dll false true ..\bin\ qhull_r.dir\RelWithDebInfo\ qhull_r .dll false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;qhull_r_EXPORTS;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;qhull_r_EXPORTS;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qhull_rd.lib ../src/libqhull_r/qhull_r-exports.def ../bin/qhull_rd.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;qhull_r_EXPORTS;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;qhull_r_EXPORTS;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qhull_r.lib ../src/libqhull_r/qhull_r-exports.def ../bin/qhull_r.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;qhull_r_EXPORTS;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;qhull_r_EXPORTS;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qhull_r.lib ../src/libqhull_r/qhull_r-exports.def ../bin/qhull_r.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;qhull_r_EXPORTS;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;qhull_r_EXPORTS;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qhull_r.lib ../src/libqhull_r/qhull_r-exports.def ../bin/qhull_r.pdb Console false qhull-2020.2/build/qhull_r.vcproj0000644060175106010010000003137012642311011015153 0ustar bbarber qhull-2020.2/build/qvoronoi-32.vcxproj0000644060175106010010000003706212647335055016022 0ustar bbarber Debug Win32 Release Win32 MinSizeRel Win32 RelWithDebInfo Win32 {7A587B07-AE31-4071-9D8B-105BFA3815C9} Win32Proj Win32 qvoronoi Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ qvoronoi.dir\Debug\ qvoronoi .exe false true ..\bin\ qvoronoi.dir\Release\ qvoronoi .exe false true ..\bin\ qvoronoi.dir\MinSizeRel\ qvoronoi .exe false true ..\bin\ qvoronoi.dir\RelWithDebInfo\ qvoronoi .exe false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic_d.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qvoronoi.lib ../bin/qvoronoi.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qvoronoi.lib ../bin/qvoronoi.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qvoronoi.lib ../bin/qvoronoi.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qvoronoi.lib ../bin/qvoronoi.pdb Console false F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B qhull-2020.2/build/qvoronoi-64.vcxproj0000644060175106010010000003673612647335055016036 0ustar bbarber Debug x64 Release x64 MinSizeRel x64 RelWithDebInfo x64 {7A587B07-AE31-4071-9D8B-105BFA3815C9} x64Proj x64 qvoronoi Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ qvoronoi.dir\Debug\ qvoronoi .exe false true ..\bin\ qvoronoi.dir\Release\ qvoronoi .exe false true ..\bin\ qvoronoi.dir\MinSizeRel\ qvoronoi .exe false true ..\bin\ qvoronoi.dir\RelWithDebInfo\ qvoronoi .exe false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic_d.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qvoronoi.lib ../bin/qvoronoi.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qvoronoi.lib ../bin/qvoronoi.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/qvoronoi.lib ../bin/qvoronoi.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/qvoronoi.lib ../bin/qvoronoi.pdb Console false F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B qhull-2020.2/build/qvoronoi.vcproj0000644060175106010010000002457012642311011015365 0ustar bbarber qhull-2020.2/build/rbox-32.vcxproj0000644060175106010010000003674612647335055015130 0ustar bbarber Debug Win32 Release Win32 MinSizeRel Win32 RelWithDebInfo Win32 {F3F597F4-08BF-4567-8866-D8A66BB1B9BE} Win32Proj Win32 rbox Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ rbox.dir\Debug\ rbox .exe false true ..\bin\ rbox.dir\Release\ rbox .exe false true ..\bin\ rbox.dir\MinSizeRel\ rbox .exe false true ..\bin\ rbox.dir\RelWithDebInfo\ rbox .exe false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic_d.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/rbox.lib ../bin/rbox.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/rbox.lib ../bin/rbox.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/rbox.lib ../bin/rbox.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/rbox.lib ../bin/rbox.pdb Console false F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B qhull-2020.2/build/rbox-64.vcxproj0000644060175106010010000003662212647335055015126 0ustar bbarber Debug x64 Release x64 MinSizeRel x64 RelWithDebInfo x64 {F3F597F4-08BF-4567-8866-D8A66BB1B9BE} x64Proj x64 rbox Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ rbox.dir\Debug\ rbox .exe false true ..\bin\ rbox.dir\Release\ rbox .exe false true ..\bin\ rbox.dir\MinSizeRel\ rbox .exe false true ..\bin\ rbox.dir\RelWithDebInfo\ rbox .exe false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic_d.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/rbox.lib ../bin/rbox.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/rbox.lib ../bin/rbox.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/rbox.lib ../bin/rbox.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/rbox.lib ../bin/rbox.pdb Console false F9AF9BC6-2CA5-4E0C-982B-CF7974723A0B qhull-2020.2/build/rbox.vcproj0000644060175106010010000002443412642311011014462 0ustar bbarber qhull-2020.2/build/testqset-32.vcxproj0000644060175106010010000003710212647335056016016 0ustar bbarber Debug Win32 Release Win32 MinSizeRel Win32 RelWithDebInfo Win32 {9ECBCBA4-269F-4ED1-B359-7522F9D19DDA} Win32Proj Win32 testqset Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ testqset.dir\Debug\ testqset .exe false true ..\bin\ testqset.dir\Release\ testqset .exe false true ..\bin\ testqset.dir\MinSizeRel\ testqset .exe false true ..\bin\ testqset.dir\RelWithDebInfo\ testqset .exe false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/testqset.lib ../bin/testqset.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/testqset.lib ../bin/testqset.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/testqset.lib ../bin/testqset.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/testqset.lib ../bin/testqset.pdb Console false qhull-2020.2/build/testqset-64.vcxproj0000644060175106010010000003675612647335056016041 0ustar bbarber Debug x64 Release x64 MinSizeRel x64 RelWithDebInfo x64 {9ECBCBA4-269F-4ED1-B359-7522F9D19DDA} x64Proj x64 testqset Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ testqset.dir\Debug\ testqset .exe false true ..\bin\ testqset.dir\Release\ testqset .exe false true ..\bin\ testqset.dir\MinSizeRel\ testqset .exe false true ..\bin\ testqset.dir\RelWithDebInfo\ testqset .exe false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/testqset.lib ../bin/testqset.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/testqset.lib ../bin/testqset.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/testqset.lib ../bin/testqset.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/testqset.lib ../bin/testqset.pdb Console false qhull-2020.2/build/testqset.vcproj0000644060175106010010000002527112642311011015364 0ustar bbarber qhull-2020.2/build/testqset_r-32.vcxproj0000644060175106010010000003717412647335056016350 0ustar bbarber Debug Win32 Release Win32 MinSizeRel Win32 RelWithDebInfo Win32 {ACECEFF4-E332-4AD0-A89B-0D07A78FEA6A} Win32Proj Win32 testqset_r Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ testqset_r.dir\Debug\ testqset_r .exe false true ..\bin\ testqset_r.dir\Release\ testqset_r .exe false true ..\bin\ testqset_r.dir\MinSizeRel\ testqset_r .exe false true ..\bin\ testqset_r.dir\RelWithDebInfo\ testqset_r .exe false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/testqset_r.lib ../bin/testqset_r.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/testqset_r.lib ../bin/testqset_r.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/testqset_r.lib ../bin/testqset_r.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/testqset_r.lib ../bin/testqset_r.pdb Console false qhull-2020.2/build/testqset_r-64.vcxproj0000644060175106010010000003705012647335056016346 0ustar bbarber Debug x64 Release x64 MinSizeRel x64 RelWithDebInfo x64 {ACECEFF4-E332-4AD0-A89B-0D07A78FEA6A} x64Proj x64 testqset_r Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ testqset_r.dir\Debug\ testqset_r .exe false true ..\bin\ testqset_r.dir\Release\ testqset_r .exe false true ..\bin\ testqset_r.dir\MinSizeRel\ testqset_r .exe false true ..\bin\ testqset_r.dir\RelWithDebInfo\ testqset_r .exe false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/testqset_r.lib ../bin/testqset_r.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/testqset_r.lib ../bin/testqset_r.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/testqset_r.lib ../bin/testqset_r.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/testqset_r.lib ../bin/testqset_r.pdb Console false qhull-2020.2/build/testqset_r.vcproj0000644060175106010010000002537312642311011015710 0ustar bbarber qhull-2020.2/build/user_eg-32.vcxproj0000644060175106010010000003716412647335056015603 0ustar bbarber Debug Win32 Release Win32 MinSizeRel Win32 RelWithDebInfo Win32 {D1F6E2EB-53DB-44FB-AC8C-EC2A339683A7} Win32Proj Win32 user_eg Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ user_eg.dir\Debug\ user_eg .exe false true ..\bin\ user_eg.dir\Release\ user_eg .exe false true ..\bin\ user_eg.dir\MinSizeRel\ user_eg .exe false true ..\bin\ user_eg.dir\RelWithDebInfo\ user_eg .exe false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;qh_dllimport;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;qh_dllimport;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhull_rd.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/user_eg.lib ../bin/user_eg.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;qh_dllimport;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;qh_dllimport;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhull_r.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/user_eg.lib ../bin/user_eg.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;qh_dllimport;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;qh_dllimport;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhull_r.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/user_eg.lib ../bin/user_eg.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;qh_dllimport;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;qh_dllimport;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhull_r.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/user_eg.lib ../bin/user_eg.pdb Console false D1E7C352-C0F9-4E64-B0CB-6C4371280C86 qhull-2020.2/build/user_eg-64.vcxproj0000644060175106010010000003704012647335056015601 0ustar bbarber Debug x64 Release x64 MinSizeRel x64 RelWithDebInfo x64 {D1F6E2EB-53DB-44FB-AC8C-EC2A339683A7} x64Proj x64 user_eg Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ user_eg.dir\Debug\ user_eg .exe false true ..\bin\ user_eg.dir\Release\ user_eg .exe false true ..\bin\ user_eg.dir\MinSizeRel\ user_eg .exe false true ..\bin\ user_eg.dir\RelWithDebInfo\ user_eg .exe false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;qh_dllimport;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;qh_dllimport;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhull_rd.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/user_eg.lib ../bin/user_eg.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;qh_dllimport;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;qh_dllimport;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhull_r.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/user_eg.lib ../bin/user_eg.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;qh_dllimport;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;qh_dllimport;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhull_r.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/user_eg.lib ../bin/user_eg.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;qh_dllimport;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;qh_dllimport;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhull_r.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/user_eg.lib ../bin/user_eg.pdb Console false D1E7C352-C0F9-4E64-B0CB-6C4371280C86 qhull-2020.2/build/user_eg.vcproj0000644060175106010010000002467212642311011015145 0ustar bbarber qhull-2020.2/build/user_eg2-32.vcxproj0000644060175106010010000003707512647335056015666 0ustar bbarber Debug Win32 Release Win32 MinSizeRel Win32 RelWithDebInfo Win32 {5564AE35-E8FE-4039-BD33-76B920D02BC9} Win32Proj Win32 user_eg2 Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ user_eg2.dir\Debug\ user_eg2 .exe false true ..\bin\ user_eg2.dir\Release\ user_eg2 .exe false true ..\bin\ user_eg2.dir\MinSizeRel\ user_eg2 .exe false true ..\bin\ user_eg2.dir\RelWithDebInfo\ user_eg2 .exe false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic_rd.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/user_eg2.lib ../bin/user_eg2.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic_r.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/user_eg2.lib ../bin/user_eg2.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic_r.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/user_eg2.lib ../bin/user_eg2.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic_r.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/user_eg2.lib ../bin/user_eg2.pdb Console false 526F05C7-E54E-4673-91DC-A3AF75041688 qhull-2020.2/build/user_eg2-64.vcxproj0000644060175106010010000003675112647335056015673 0ustar bbarber Debug x64 Release x64 MinSizeRel x64 RelWithDebInfo x64 {5564AE35-E8FE-4039-BD33-76B920D02BC9} x64Proj x64 user_eg2 Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ user_eg2.dir\Debug\ user_eg2 .exe false true ..\bin\ user_eg2.dir\Release\ user_eg2 .exe false true ..\bin\ user_eg2.dir\MinSizeRel\ user_eg2 .exe false true ..\bin\ user_eg2.dir\RelWithDebInfo\ user_eg2 .exe false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsC ProgramDatabase Disabled Disabled NotUsing MultiThreadedDebugDLL Level3 WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic_rd.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/user_eg2.lib ../bin/user_eg2.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsC AnySuitable MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic_r.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/user_eg2.lib ../bin/user_eg2.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsC OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic_r.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/user_eg2.lib ../bin/user_eg2.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsC ProgramDatabase OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullstatic_r.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/user_eg2.lib ../bin/user_eg2.pdb Console false 526F05C7-E54E-4673-91DC-A3AF75041688 qhull-2020.2/build/user_eg2.vcproj0000644060175106010010000002460112642311012015220 0ustar bbarber qhull-2020.2/build/user_eg3-32.vcxproj0000644060175106010010000003773412647335056015671 0ustar bbarber Debug Win32 Release Win32 MinSizeRel Win32 RelWithDebInfo Win32 {E615D779-7F0A-4521-B7AD-B3C0D328652E} Win32Proj Win32 user_eg3 Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ user_eg3.dir\Debug\ user_eg3 .exe false true ..\bin\ user_eg3.dir\Release\ user_eg3 .exe false true ..\bin\ user_eg3.dir\MinSizeRel\ user_eg3 .exe false true ..\bin\ user_eg3.dir\RelWithDebInfo\ user_eg3 .exe false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsCpp ProgramDatabase Sync Disabled Disabled NotUsing MultiThreadedDebugDLL true Level3 WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullcpp_d.lib;..\lib\qhullstatic_rd.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/user_eg3.lib ../bin/user_eg3.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsCpp Sync AnySuitable MaxSpeed NotUsing MultiThreadedDLL true Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullcpp.lib;..\lib\qhullstatic_r.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/user_eg3.lib ../bin/user_eg3.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsCpp Sync OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL true Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullcpp.lib;..\lib\qhullstatic_r.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/user_eg3.lib ../bin/user_eg3.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsCpp ProgramDatabase Sync OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL true Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:X86 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullcpp.lib;..\lib\qhullstatic_r.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/user_eg3.lib ../bin/user_eg3.pdb Console false 939F1F43-F252-486C-BB92-3166E44713A5 526F05C7-E54E-4673-91DC-A3AF75041688 qhull-2020.2/build/user_eg3-64.vcxproj0000644060175106010010000003761012647335056015667 0ustar bbarber Debug x64 Release x64 MinSizeRel x64 RelWithDebInfo x64 {E615D779-7F0A-4521-B7AD-B3C0D328652E} x64Proj x64 user_eg3 Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 Application false MultiByte v110 <_ProjectFileVersion>10.0.20506.1 ..\bin\ user_eg3.dir\Debug\ user_eg3 .exe false true ..\bin\ user_eg3.dir\Release\ user_eg3 .exe false true ..\bin\ user_eg3.dir\MinSizeRel\ user_eg3 .exe false true ..\bin\ user_eg3.dir\RelWithDebInfo\ user_eg3 .exe false true ..\src;%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsCpp ProgramDatabase Sync Disabled Disabled NotUsing MultiThreadedDebugDLL true Level3 WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullcpp_d.lib;..\lib\qhullstatic_rd.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/user_eg3.lib ../bin/user_eg3.pdb Console false ..\src;%(AdditionalIncludeDirectories) Release/ CompileAsCpp Sync AnySuitable MaxSpeed NotUsing MultiThreadedDLL true Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullcpp.lib;..\lib\qhullstatic_r.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/user_eg3.lib ../bin/user_eg3.pdb Console false ..\src;%(AdditionalIncludeDirectories) MinSizeRel/ CompileAsCpp Sync OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL true Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullcpp.lib;..\lib\qhullstatic_r.lib %(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) ../lib/user_eg3.lib ../bin/user_eg3.pdb Console false ..\src;%(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsCpp ProgramDatabase Sync OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL true Level3 WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) ..\src;%(AdditionalIncludeDirectories) ..\src;%(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c /machine:x64 /debug %(AdditionalOptions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\lib\qhullcpp.lib;..\lib\qhullstatic_r.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) ../lib/user_eg3.lib ../bin/user_eg3.pdb Console false 939F1F43-F252-486C-BB92-3166E44713A5 526F05C7-E54E-4673-91DC-A3AF75041688 qhull-2020.2/build/user_eg3.vcproj0000644060175106010010000002472512642311012015230 0ustar bbarber qhull-2020.2/CMakeLists.txt0000644060175106010010000006421413724313423013737 0ustar bbarber# CMakeLists.txt -- CMake configuration file for qhull, qhull6, and related programs # # CMake options # BUILD_SHARED_LIBS=OFF -- Do not build libqhull_r.so # BUILD_STATIC_LIBS=OFF -- Do not build libqhullcpp.a, libqhullstatic_r.a, libqhullstatic.a, and user_eg3 # CMAKE_INSTALL_PREFIX=path -- Prefix for the install directories # LINK_APPS_SHARED=ON -- Link qconvex,etc. to libqhull_r instead of libqhullstatic_r # # 32-bit vs. 64-bit # Qhull uses less memory when built as 32-bit code # On 64-bit hosts, consider building with -DCMAKE_CXX_FLAGS=-m32 -DCMAKE_C_FLAGS=-m32 # # Additional build targets # libqhull -- Deprecated, shared library for non-reentrant Qhull (use libqhull_r or libqhullstatic) # qhull_p -- Deprecated, shared library for qh_QHpointer and non-reentrant Qhull (use libqhull_r) # qhullp -- Same as qhull using qh_QHpointer and libqhull_p # user_egp -- Same as user_eg using qh_QHpointer and libqhull_p # # For qhulltest, use the Qt build (src/qhull-all.pro) # # To install CMake # Download from http://www.cmake.org/download/ # # To find the available targets for CMake -G "..." # cmake --help # # To build with MSYS, MSYS2, mingw, mingw-w64, or GitForWindows # cd build && cmake -G "MSYS Makefiles" .. && cmake .. # make # make install # # To build Qhull with Visual Studio projects, run cmake twice # To install bin/doc/include/lib in the current directory # mkdir -p build-cmake && cd build-cmake && cmake -G "Visual Studio 11 2012" .. && cmake -DCMAKE_INSTALL_PREFIX=.. .. # mkdir -p build-cmake && cd build-cmake && cmake -G "Visual Studio 11 2012 Win64" .. && cmake -DCMAKE_INSTALL_PREFIX=.. .. # To install into Program Files/qhull # mkdir -p build-cmake && cd build-cmake && cmake -G "Visual Studio 11 2012" .. && cmake .. # mkdir -p build-cmake && cd build-cmake && cmake -G "Visual Studio 11 2012 Win64" .. && cmake .. # To build for Visual Studio 2005 and install into Program Files/qhull # mkdir -p build-cmake && cd build-cmake && cmake -G "Visual Studio 8 2005" .. && cmake .. # mkdir -p build-cmake && cd build-cmake && cmake -G "Visual Studio 8 2005 Win64" .. && cmake .. # Double click build-cmake/qhull-all.sln # Build INSTALL to copy files into C:/Program Files/qhull # # To uninstall on unix or MSYS/mingw # make uninstall # # Notes on Visual Studio projects # You may need to copy bin/msvcr80.dll into C:/Program Files/qhull/bin # If using library debug targets, please rename with '_d' (e.g., qhullstatic_d.lib) # # Troubleshooting # "No CMAKE_C_COMPILER could be found" # cmake was not able to find the build environment specified (e.g., Visual Studio 11) # # Qhull ships with CMake-derived sln and proj files for DevStudio 8 2005 # See eg/make-vcproj.sh # Change to relative paths # Remove ZERO_CHECK, ALL_BUILD, and INSTALL projects # Change targets to bin/ and lib/ directories # Disable incremental linking and ilk files (LinkIncremental="1") # Disable Run-Time Type Info (rtti) # Remove src/libqhullcpp from most of the AdditionalIncludeDirectories # Remove CMAKE_INTDIR from PreprocessorDefinitions # Adjust target names and destinations (e.g., lib/libqhullstatic_rd.a) # # $Id: //main/2019/qhull/CMakeLists.txt#21 $$Change: 3039 $ # $DateTime: 2020/09/03 21:26:22 $$Author: bbarber $ project(qhull) cmake_minimum_required(VERSION 3.0) # Define qhull_VERSION in README.txt, Announce.txt, qh-get.htm, CMakeLists.txt # qhull-zip.sh (twice), qhull-wiki.md, qhull-news.htm, File_id.diz, index.htm # qhull-warn.pri (VERSION), qhull-exports.def (VERSION), qhull_p-exports.def, qhull_r-exports.def set(qhull_VERSION2 "2020.2 2020/08/31") # not used, See global.c, global_r.c, rbox.c, rbox_r.c set(qhull_VERSION "8.0.2") # Advance every release # SOVERSION -- qhull 2003 = empty, 2009 = 5, 2010-2012 = 6, 2015-2019 = 7, 2020 = 8.0 # Increase SOVERSION if ABI breaks (abi-compliance-checker) set(qhull_SOVERSION 8.0) # For SOVERSION # If MSYS, set CMAKE_INSTALL_PREFIX to /usr/local; if WINDOWS, '..' if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) if(MSYS) execute_process( COMMAND sh -c 'cd / && pwd -W' OUTPUT_VARIABLE MSYS_PWD ERROR_VARIABLE MSYS_ERR ) if(MSYS_ERR STREQUAL "") string(REPLACE "\n" "" MSYS_ROOT ${MSYS_PWD}) set(CMAKE_INSTALL_PREFIX "${MSYS_ROOT}/usr/local" CACHE PATH "Install to ${MSYS_ROOT}/usr/local" FORCE) else() message(STATUS "Use default MAKE_INSTALL_PREFIX due to ${MSYS_ERR}") endif() endif() endif() include(build/CMakeModules/CheckLFS.cmake) option(WITH_LFS "Enable Large File Support" ON) check_lfs(WITH_LFS) # Build shared and static libs by default # If LINK_APPS_SHARED=ON, link applications to libqhull_r.so include(CMakeDependentOption) option(BUILD_STATIC_LIBS "Build static libraries" ON) option(BUILD_SHARED_LIBS "Build shared library" ON) set(_NO_STATIC_LIBS NOCACHE INTERNAL (NOT ${BUILD_STATIC_LIBS})) cmake_dependent_option(LINK_APPS_SHARED "Use shared library for linking applications" _NO_STATIC_LIBS "BUILD_SHARED_LIBS;BUILD_STATIC_LIBS" ${BUILD_SHARED_LIBS} ) if(INCLUDE_INSTALL_DIR) else() set(INCLUDE_INSTALL_DIR include) endif() if(LIB_INSTALL_DIR) else() set(LIB_INSTALL_DIR lib) endif() if(BIN_INSTALL_DIR) else() set(BIN_INSTALL_DIR bin) endif() if(MAN_INSTALL_DIR) else() set(MAN_INSTALL_DIR share/man/man1) endif() if(DOC_INSTALL_DIR) else() set(DOC_INSTALL_DIR share/doc/qhull) endif() message(STATUS) message(STATUS "========== qhull Build Information ==========") message(STATUS "Build Version: ${qhull_VERSION}") message(STATUS "Install Prefix (CMAKE_INSTALL_PREFIX): ${CMAKE_INSTALL_PREFIX}") message(STATUS "Binary Directory (BIN_INSTALL_DIR): ${BIN_INSTALL_DIR}") message(STATUS "Library Directory (LIB_INSTALL_DIR): ${LIB_INSTALL_DIR}") message(STATUS "Include Directory (INCLUDE_INSTALL_DIR): ${INCLUDE_INSTALL_DIR}") message(STATUS "Documentation Directory (DOC_INSTALL_DIR): ${DOC_INSTALL_DIR}") message(STATUS "Man Pages Directory (MAN_INSTALL_DIR): ${MAN_INSTALL_DIR}") message(STATUS "Build Type (CMAKE_BUILD_TYPE): ${CMAKE_BUILD_TYPE}") message(STATUS "Build static libraries: ${BUILD_STATIC_LIBS}") message(STATUS "Build shared library: ${BUILD_SHARED_LIBS}") message(STATUS "Use shared library for linking apps: ${LINK_APPS_SHARED}") message(STATUS "To override these options, add -D{OPTION_NAME}=... to the cmake command") message(STATUS " Build the debug targets -DCMAKE_BUILD_TYPE=Debug") message(STATUS) message(STATUS "To build and install qhull, enter \"make\" and \"make install\"") message(STATUS "To smoketest qhull, enter \"ctest\"") message(STATUS) # --------------------------------------- # Define library source files and variables # # Files for individual targets are defined with the target # --------------------------------------- # Order libqhull object files by frequency of execution. Small files at end. # Non-reentrant Qhull set( libqhull_HEADERS src/libqhull/libqhull.h src/libqhull/geom.h src/libqhull/io.h src/libqhull/mem.h src/libqhull/merge.h src/libqhull/poly.h src/libqhull/qhull_a.h src/libqhull/qset.h src/libqhull/random.h src/libqhull/stat.h src/libqhull/user.h ) set( libqhull_SOURCES src/libqhull/global.c src/libqhull/stat.c src/libqhull/geom2.c src/libqhull/poly2.c src/libqhull/merge.c src/libqhull/libqhull.c src/libqhull/geom.c src/libqhull/poly.c src/libqhull/qset.c src/libqhull/mem.c src/libqhull/random.c src/libqhull/usermem.c src/libqhull/userprintf.c src/libqhull/io.c src/libqhull/user.c src/libqhull/rboxlib.c src/libqhull/userprintf_rbox.c ${libqhull_HEADERS} ) set( testqset_HEADERS src/libqhull/mem.h src/libqhull/qset.h ) set( testqset_SOURCES src/libqhull/qset.c src/libqhull/mem.c src/libqhull/usermem.c src/testqset/testqset.c ${testqset_HEADERS} ) # Reeentrant Qhull set( libqhullr_HEADERS src/libqhull_r/libqhull_r.h src/libqhull_r/geom_r.h src/libqhull_r/io_r.h src/libqhull_r/mem_r.h src/libqhull_r/merge_r.h src/libqhull_r/poly_r.h src/libqhull_r/qhull_ra.h src/libqhull_r/qset_r.h src/libqhull_r/random_r.h src/libqhull_r/stat_r.h src/libqhull_r/user_r.h ) set( libqhullr_SOURCES src/libqhull_r/global_r.c src/libqhull_r/stat_r.c src/libqhull_r/geom2_r.c src/libqhull_r/poly2_r.c src/libqhull_r/merge_r.c src/libqhull_r/libqhull_r.c src/libqhull_r/geom_r.c src/libqhull_r/poly_r.c src/libqhull_r/qset_r.c src/libqhull_r/mem_r.c src/libqhull_r/random_r.c src/libqhull_r/usermem_r.c src/libqhull_r/userprintf_r.c src/libqhull_r/io_r.c src/libqhull_r/user_r.c src/libqhull_r/rboxlib_r.c src/libqhull_r/userprintf_rbox_r.c ${libqhullr_HEADERS} ) set( testqsetr_HEADERS src/libqhull_r/mem_r.h src/libqhull_r/qset_r.h ) set( testqsetr_SOURCES src/libqhull_r/qset_r.c src/libqhull_r/mem_r.c src/libqhull_r/usermem_r.c src/testqset_r/testqset_r.c ${testqsetr_HEADERS} ) # C++ interface to reentrant Qhull set( libqhullcpp_HEADERS src/libqhullcpp/Coordinates.h src/libqhullcpp/functionObjects.h src/libqhullcpp/PointCoordinates.h src/libqhullcpp/Qhull.h src/libqhullcpp/QhullError.h src/libqhullcpp/QhullFacet.h src/libqhullcpp/QhullFacetList.h src/libqhullcpp/QhullFacetSet.h src/libqhullcpp/QhullHyperplane.h src/libqhullcpp/QhullIterator.h src/libqhullcpp/QhullLinkedList.h src/libqhullcpp/QhullPoint.h src/libqhullcpp/QhullPoints.h src/libqhullcpp/QhullPointSet.h src/libqhullcpp/QhullQh.h src/libqhullcpp/QhullRidge.h src/libqhullcpp/QhullSet.h src/libqhullcpp/QhullSets.h src/libqhullcpp/QhullStat.h src/libqhullcpp/QhullUser.h src/libqhullcpp/QhullVertex.h src/libqhullcpp/QhullVertexSet.h src/libqhullcpp/RboxPoints.h src/libqhullcpp/RoadError.h src/libqhullcpp/RoadLogEvent.h src/qhulltest/RoadTest.h ) set( libqhullcpp_SOURCES src/libqhullcpp/Coordinates.cpp src/libqhullcpp/PointCoordinates.cpp src/libqhullcpp/Qhull.cpp src/libqhullcpp/QhullFacet.cpp src/libqhullcpp/QhullFacetList.cpp src/libqhullcpp/QhullFacetSet.cpp src/libqhullcpp/QhullHyperplane.cpp src/libqhullcpp/QhullPoint.cpp src/libqhullcpp/QhullPointSet.cpp src/libqhullcpp/QhullPoints.cpp src/libqhullcpp/QhullQh.cpp src/libqhullcpp/QhullRidge.cpp src/libqhullcpp/QhullSet.cpp src/libqhullcpp/QhullStat.cpp src/libqhullcpp/QhullUser.cpp src/libqhullcpp/QhullVertex.cpp src/libqhullcpp/QhullVertexSet.cpp src/libqhullcpp/RboxPoints.cpp src/libqhullcpp/RoadError.cpp src/libqhullcpp/RoadLogEvent.cpp ${libqhullcpp_HEADERS} ) # Documentation files (index.htm refers to html/...) set( doc_FILES README.txt REGISTER.txt Announce.txt COPYING.txt index.htm ) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src) set(qhull_CPP qhullcpp) set(qhull_STATIC qhullstatic) set(qhull_STATICR qhullstatic_r) set(qhull_SHAREDR qhull_r) set(qhull_SHARED libqhull) # Temporarily avoid name conflict with qhull executable set(qhull_SHAREDP qhull_p) # libqhull and qhull_p are deprecated, use qhull_r instead set(qhull_TARGETS_APPLICATIONS qhull rbox qconvex qdelaunay qvoronoi qhalf) set(qhull_TARGETS_STATIC ${qhull_CPP} ${qhull_STATIC} ${qhull_STATICR}) set(qhull_TARGETS_SHARED ${qhull_SHAREDR}) set( qhull_TARGETS_TEST # Unused testqset testqset_r user_eg user_eg2 user_eg3 ) set( qhull_TARGETS_DEPRECATED # Unused $(qhull_SHARED) $(qhull_SHAREDP) qhullp user_egp ) # --------------------------------------- # Define shared library for reentrant qhull (installed) # --------------------------------------- add_library(${qhull_SHAREDR} SHARED ${libqhullr_SOURCES} src/libqhull_r/qhull_r-exports.def) set_target_properties(${qhull_SHAREDR} PROPERTIES SOVERSION ${qhull_SOVERSION} VERSION ${qhull_VERSION} OUTPUT_NAME "${qhull_SHAREDR}$<$:d>") if(UNIX) target_link_libraries(${qhull_SHAREDR} m) if(APPLE) set_target_properties(${qhull_SHAREDR} PROPERTIES INSTALL_NAME_DIR "${LIB_INSTALL_DIR}") else() set_target_properties(${qhull_SHAREDR} PROPERTIES INSTALL_RPATH "${LIB_INSTALL_DIR}" INSTALL_RPATH_USE_LINK_PATH TRUE BUILD_WITH_INSTALL_RPATH FALSE) endif() endif(UNIX) # --------------------------------------- # Define deprecated shared library for non-reentrant qhull # --------------------------------------- add_library(${qhull_SHARED} SHARED ${libqhull_SOURCES} src/libqhull/qhull-exports.def) set_target_properties(${qhull_SHARED} PROPERTIES EXCLUDE_FROM_ALL TRUE SOVERSION ${qhull_SOVERSION} VERSION ${qhull_VERSION} OUTPUT_NAME "qhull$<$:_d>") if(UNIX) target_link_libraries(${qhull_SHARED} m) if(APPLE) set_target_properties(${qhull_SHARED} PROPERTIES INSTALL_NAME_DIR "${LIB_INSTALL_DIR}") else() set_target_properties(${qhull_SHARED} PROPERTIES INSTALL_RPATH "${LIB_INSTALL_DIR}" INSTALL_RPATH_USE_LINK_PATH TRUE BUILD_WITH_INSTALL_RPATH FALSE) endif() endif(UNIX) # --------------------------------------- # Define deprecated shared library for non-reentrant qhull with qh_QHpointer # --------------------------------------- add_library(${qhull_SHAREDP} SHARED ${libqhull_SOURCES} src/libqhull/qhull_p-exports.def) set_target_properties(${qhull_SHAREDP} PROPERTIES EXCLUDE_FROM_ALL TRUE COMPILE_DEFINITIONS "qh_QHpointer" SOVERSION ${qhull_SOVERSION} VERSION ${qhull_VERSION} OUTPUT_NAME "${qhull_SHAREDP}$<$:d>") if(UNIX) target_link_libraries(${qhull_SHAREDP} m) if(APPLE) set_target_properties(${qhull_SHAREDP} PROPERTIES INSTALL_NAME_DIR "${LIB_INSTALL_DIR}") else() set_target_properties(${qhull_SHAREDP} PROPERTIES INSTALL_RPATH "${LIB_INSTALL_DIR}" INSTALL_RPATH_USE_LINK_PATH TRUE BUILD_WITH_INSTALL_RPATH FALSE) endif() endif(UNIX) # --------------------------------------- # Define static libraries qhullstatic (non-reentrant) and qhullstatic_r (reentrant) # --------------------------------------- add_library(${qhull_STATIC} STATIC ${libqhull_SOURCES}) set_target_properties(${qhull_STATIC} PROPERTIES VERSION ${qhull_VERSION} OUTPUT_NAME "${qhull_STATIC}$<$:_d>") add_library(${qhull_STATICR} STATIC ${libqhullr_SOURCES}) set_target_properties(${qhull_STATICR} PROPERTIES VERSION ${qhull_VERSION} OUTPUT_NAME "${qhull_STATICR}$<$:d>") if(UNIX) target_link_libraries(${qhull_STATIC} m) target_link_libraries(${qhull_STATICR} m) endif(UNIX) # --------------------------------------- # Define C++ static library qhullcpp # Do not create libqhullcpp as a shared library. # Qhull C++ classes may change layout and size. # Qhull C programs use setjmp/longjmp for error handling. # --------------------------------------- add_library(${qhull_CPP} STATIC ${libqhullcpp_SOURCES}) set_target_properties(${qhull_CPP} PROPERTIES VERSION ${qhull_VERSION} OUTPUT_NAME "${qhull_CPP}$<$:_d>" POSITION_INDEPENDENT_CODE "TRUE") # --------------------------------------- # if BUILD_STATIC_LIBS=OFF or BUILD_SHARED_LIBS=OFF # Exclude library builds from "make all" # --------------------------------------- if(NOT ${BUILD_STATIC_LIBS}) set_target_properties(${qhull_STATIC} PROPERTIES EXCLUDE_FROM_ALL TRUE) set_target_properties(${qhull_STATICR} PROPERTIES EXCLUDE_FROM_ALL TRUE) set_target_properties(${qhull_CPP} PROPERTIES EXCLUDE_FROM_ALL TRUE) endif() if(NOT ${BUILD_SHARED_LIBS}) set_target_properties(${qhull_SHARED} PROPERTIES EXCLUDE_FROM_ALL TRUE) set_target_properties(${qhull_SHAREDR} PROPERTIES EXCLUDE_FROM_ALL TRUE) set_target_properties(${qhull_SHAREDP} PROPERTIES EXCLUDE_FROM_ALL TRUE) endif() # --------------------------------------- # Define options for linking to shared libaries # --------------------------------------- if(MSVC) set(qconvex_DEFINES qh_dllimport) set(qdelaunay_DEFINES qh_dllimport) set(qhalf_DEFINES qh_dllimport) set(qhull_DEFINES qh_dllimport) set(qvoronoi_DEFINES qh_dllimport) set(rbox_DEFINES qh_dllimport) set(user_eg_DEFINES qh_dllimport) set(user_eg2_DEFINES qh_dllimport) set(user_egp_DEFINES qh_QHpointer_dllimport qh_QHpointer) set(qhullp_DEFINES qh_QHpointer_dllimport qh_QHpointer) else() set(qconvex_DEFINES ) set(qdelaunay_DEFINES ) set(qhalf_DEFINES ) set(qhull_DEFINES ) set(qvoronoi_DEFINES ) set(rbox_DEFINES ) set(user_eg_DEFINES ) set(user_eg2_DEFINES ) set(user_egp_DEFINES qh_QHpointer) set(qhullp_DEFINES qh_QHpointer) endif() # --------------------------------------- # Define qhull applications # # By default, qhull is linked to reentrant qhull (more flexible) # the other applications are linked to non-reentrant qhull (somewhat faster) # # If LINK_APPS_SHARED, applications are linked to reentrant qhull # --------------------------------------- if(${LINK_APPS_SHARED}) add_executable(qconvex src/qconvex/qconvex_r.c) target_link_libraries(qconvex ${qhull_SHAREDR}) set_target_properties(qconvex PROPERTIES COMPILE_DEFINITIONS "${qconvex_DEFINES}") add_executable(qdelaunay src/qdelaunay/qdelaun_r.c) target_link_libraries(qdelaunay ${qhull_SHAREDR}) set_target_properties(qdelaunay PROPERTIES COMPILE_DEFINITIONS "${qdelaunay_DEFINES}") add_executable(qhalf src/qhalf/qhalf_r.c) target_link_libraries(qhalf ${qhull_SHAREDR}) set_target_properties(qhalf PROPERTIES COMPILE_DEFINITIONS "${qhalf_DEFINES}") add_executable(qhull src/qhull/unix_r.c) target_link_libraries(qhull ${qhull_SHAREDR}) set_target_properties(qhull PROPERTIES COMPILE_DEFINITIONS "${qhull_DEFINES}") add_executable(qvoronoi src/qvoronoi/qvoronoi_r.c) target_link_libraries(qvoronoi ${qhull_SHAREDR}) set_target_properties(qvoronoi PROPERTIES COMPILE_DEFINITIONS "${qvoronoi_DEFINES}") add_executable(rbox src/rbox/rbox_r.c) target_link_libraries(rbox ${qhull_SHAREDR}) set_target_properties(rbox PROPERTIES COMPILE_DEFINITIONS "${rbox_DEFINES}") else() if(NOT ${BUILD_STATIC_LIBS}) message(FATAL_ERROR, " Nothing to build -- BUILD_SHARED_LIBS=OFF and BUILD_STATIC_LIBS=OFF") endif() add_executable(qconvex src/qconvex/qconvex.c) target_link_libraries(qconvex ${qhull_STATIC}) add_executable(qdelaunay src/qdelaunay/qdelaun.c) target_link_libraries(qdelaunay ${qhull_STATIC}) add_executable(qhalf src/qhalf/qhalf.c) target_link_libraries(qhalf ${qhull_STATIC}) add_executable(qhull src/qhull/unix_r.c) target_link_libraries(qhull ${qhull_STATICR}) add_executable(qvoronoi src/qvoronoi/qvoronoi.c) target_link_libraries(qvoronoi ${qhull_STATIC}) add_executable(rbox src/rbox/rbox.c) target_link_libraries(rbox ${qhull_STATIC}) endif() # #@# 20 # --------------------------------------- # Define testqset linked to qset.o, mem.o, and usermem.o # Define testqset_r linked to qset_r.o, mem_r.o, and usermem.o # --------------------------------------- add_executable(testqset ${testqset_SOURCES}) add_executable(testqset_r ${testqsetr_SOURCES}) # --------------------------------------- # Define user_eg linked to reentrant qhull shared library # --------------------------------------- add_executable(user_eg src/user_eg/user_eg_r.c) if(${BUILD_SHARED_LIBS}) target_link_libraries(user_eg ${qhull_SHAREDR}) set_target_properties(user_eg PROPERTIES COMPILE_DEFINITIONS "${user_eg_DEFINES}") else() target_link_libraries(user_eg ${qhull_STATICR}) endif() # --------------------------------------- # Define user_eg2 linked to reentrant qhull static library # --------------------------------------- add_executable(user_eg2 src/user_eg2/user_eg2_r.c) if(${BUILD_STATIC_LIBS}) target_link_libraries(user_eg2 ${qhull_STATICR}) else() target_link_libraries(user_eg2 ${qhull_SHAREDR}) set_target_properties(user_eg2 PROPERTIES COMPILE_DEFINITIONS "${user_eg2_DEFINES}") endif() # --------------------------------------- # Define user_eg3 linked to qhullcpp and qhullstatic_r static libraries # # user_eg3 is not defined for shared libraries # user_eg3 and qhullcpp must be compiled with the same compiler for setjmp/longjmp # --------------------------------------- if(${BUILD_STATIC_LIBS}) add_executable(user_eg3 src/user_eg3/user_eg3_r.cpp) # qhull_STATICR must be last, otherwise qh_fprintf,etc. are not loaded from qhull_CPP target_link_libraries(user_eg3 ${qhull_CPP} ${qhull_STATICR}) endif() # --------------------------------------- # qhullp is qhull/unix.c linked to unsuported qh_QHpointer libqhull_p # Included for testing qh_QHpointer # --------------------------------------- add_executable(qhullp EXCLUDE_FROM_ALL src/qhull/unix.c) target_link_libraries(qhullp ${qhull_SHAREDP}) set_target_properties(qhullp PROPERTIES COMPILE_DEFINITIONS "${qhullp_DEFINES}") # --------------------------------------- # user_egp is user_eg/user_eg.c linked to unsuported qh_QHpointer libqhull_p # Included for compatibility with qhull-2012.1 # --------------------------------------- add_executable(user_egp EXCLUDE_FROM_ALL src/user_eg/user_eg.c) target_link_libraries(user_egp ${qhull_SHAREDP}) set_target_properties(user_egp PROPERTIES COMPILE_DEFINITIONS "${user_egp_DEFINES}") # --------------------------------------- # Define test # --------------------------------------- enable_testing() add_test(NAME testqset COMMAND ./testqset 10000) add_test(NAME testqset_r COMMAND ./testqset_r 10000) add_test(NAME smoketest COMMAND sh -c "./rbox D4 | ./qhull Tv") add_test(NAME rbox-10-qhull COMMAND sh -c "./rbox 10 | ./qhull Tv") add_test(NAME rbox-10-qconvex COMMAND sh -c "./rbox 10 | ./qconvex Tv") add_test(NAME rbox-10-qdelaunay COMMAND sh -c "./rbox 10 | ./qdelaunay Tv") add_test(NAME rbox-10-qhalf COMMAND sh -c "./rbox 10 | ./qconvex FQ FV n Tv | ./qhalf Tv") add_test(NAME rbox-10-qvoronoi COMMAND sh -c "./rbox 10 | ./qvoronoi Tv") add_test(NAME user_eg COMMAND sh -c "./user_eg") add_test(NAME user_eg2 COMMAND sh -c "./user_eg2") if(${BUILD_STATIC_LIBS}) add_test(NAME user_eg3 COMMAND sh -c "./user_eg3 rbox '10 D2' '2 D2' qhull 's p' facets") endif() # --------------------------------------- # Define install # --------------------------------------- set(qhull_TARGETS_INSTALL ${qhull_TARGETS_APPLICATIONS}) if (BUILD_SHARED_LIBS) list(APPEND qhull_TARGETS_INSTALL ${qhull_TARGETS_SHARED}) endif() if (BUILD_STATIC_LIBS) list(APPEND qhull_TARGETS_INSTALL ${qhull_TARGETS_STATIC}) endif() install(TARGETS ${qhull_TARGETS_INSTALL} EXPORT QhullTargets RUNTIME DESTINATION ${BIN_INSTALL_DIR} LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR} INCLUDES DESTINATION include) include(CMakePackageConfigHelpers) write_basic_package_version_file( "${CMAKE_CURRENT_BINARY_DIR}/QhullExport/QhullConfigVersion.cmake" VERSION ${qhull_VERSION} COMPATIBILITY AnyNewerVersion ) export(EXPORT QhullTargets FILE "${CMAKE_CURRENT_BINARY_DIR}/QhullExport/QhullTargets.cmake" NAMESPACE Qhull:: ) configure_file(${PROJECT_SOURCE_DIR}/build/config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/QhullExport/QhullConfig.cmake" @ONLY ) set(ConfigPackageLocation lib/cmake/Qhull) install(EXPORT QhullTargets FILE QhullTargets.cmake NAMESPACE Qhull:: DESTINATION ${ConfigPackageLocation} ) install( FILES "${CMAKE_CURRENT_BINARY_DIR}/QhullExport/QhullConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/QhullExport/QhullConfigVersion.cmake" DESTINATION ${ConfigPackageLocation} COMPONENT Devel ) set(PkgConfigLocation lib/pkgconfig) foreach(pkgconfig IN ITEMS "${qhull_SHAREDR};Qhull reentrant shared library" "${qhull_STATIC};Qhull static library" "${qhull_STATICR};Qhull reentrant static library" "${qhull_CPP};Qhull C++ library") list(GET pkgconfig 0 LIBRARY_NAME) if(LIBRARY_NAME STREQUAL "libqhull") set(LIBRARY_NAME "qhull") endif() if(CMAKE_BUILD_TYPE STREQUAL "Debug") string(REGEX REPLACE "_(.)$" "_\\1d" LIBRARY_NAME ${LIBRARY_NAME}) string(REGEX REPLACE "([^d])$" "\\1_d" LIBRARY_NAME ${LIBRARY_NAME}) endif() list(GET pkgconfig 1 LIBRARY_DESCRIPTION) configure_file(build/qhull.pc.in ${LIBRARY_NAME}.pc @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${LIBRARY_NAME}.pc DESTINATION ${PkgConfigLocation} COMPONENT Devel) endforeach() install(FILES ${libqhull_HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR}/libqhull) install(FILES src/libqhull/DEPRECATED.txt DESTINATION ${INCLUDE_INSTALL_DIR}/libqhull) install(FILES ${libqhullr_HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR}/libqhull_r) install(FILES ${libqhullcpp_HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR}/libqhullcpp) install(FILES html/qhull.man DESTINATION ${MAN_INSTALL_DIR} RENAME qhull.1) install(FILES html/rbox.man DESTINATION ${MAN_INSTALL_DIR} RENAME rbox.1) install(FILES ${doc_FILES} DESTINATION ${DOC_INSTALL_DIR}) install(DIRECTORY html/ DESTINATION ${DOC_INSTALL_DIR}/html) install(FILES src/Changes.txt DESTINATION ${DOC_INSTALL_DIR}/src) add_custom_target(uninstall COMMENT "uninstall Qhull by deleting files in install_manifest.txt" COMMAND cat install_manifest.txt | tr -d \"\\r\" | xargs -r rm ) qhull-2020.2/COPYING.txt0000644060175106010010000000327013661634224013050 0ustar bbarber Qhull, Copyright (c) 1993-2020 C.B. Barber Arlington, MA and The National Science and Technology Research Center for Computation and Visualization of Geometric Structures (The Geometry Center) University of Minnesota email: qhull@qhull.org This software includes Qhull from C.B. Barber and The Geometry Center. Files derived from Qhull 1.0 are copyrighted by the Geometry Center. The remaining files are copyrighted by C.B. Barber. Qhull is free software and may be obtained via http from www.qhull.org. 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@qhull.org; the authors may or may not act on them as they desire. qhull-2020.2/eg/0000755060175106010010000000000013724321350011561 5ustar bbarberqhull-2020.2/eg/make-qhull_qh.sh0000755060175106010010000001320313723545401014653 0ustar bbarber#!/bin/bash # # make-qhull_qh.sh [libqhull_r] [sed-only] [files] -- Derive src/qhull-qh/ from src/libqhull_r with 'qh' macros # # $Id: //main/2019/qhull/eg/make-qhull_qh.sh#3 $$Change: 3037 $ # $DateTime: 2020/09/03 17:28:32 $$Author: bbarber $ if [[ "$1" == "" || "$1" == "--help" ]]; then echo echo "eg/make-qhull_qh.sh -- convert reentrant Qhull files for comparison to non-reentrant Qhull files" echo echo " eg/make-qhull_qh.sh libqhull_r" echo " converts 'qh->' to macro 'qh' for src/libqhull_r, src/qhalf, etc." echo " the default default destination directory is 'src/qhull_qh'" echo " errors if the destination directory already exists" echo " override via 'DEST=destination eg/make-qhull_qh.sh ...'" echo echo " eg/make-qhull_qh.sh " echo " specify the source directory list" echo echo " eg/make-qhull_qh.sh sed-only src/qhull_qh" echo " reconvert files in src/qhull_qh via sed scripts" echo " requires file '_QH_CONVERTED_FILES' as a safety check" echo exit 0 fi # set -v SEDONLY=0 if [[ "$1" == "libqhull_r" ]]; then SOURCES="src/libqhull_r src/qconvex src/qdelaunay src/qhalf src/qhull src/qvoronoi src/rbox src/testqset_r src/user_eg src/user_eg2" DEST=${DEST:-src/qhull_qh} if [[ $# -gt 1 ]]; then echo "eg/make-qhull_qh.sh: 'libqhull_r' does not take source directories. It converts qhull files in '$SOURCES' to '$DEST'" exit 1 fi elif [[ "$1" == "sed-only" ]]; then SEDONLY=1 if [[ $# -ne 2 ]]; then echo "eg/make-qhull_qh.sh: 'sed-only' requires the destination directory, 'src/qhull_qh' exit 1 fi DEST=$2 if [[ ! -f $DEST/_QH_CONVERTED_FILES ]]; then echo "eg/make-qhull_qh.sh: 'sed-only' is missing '$DEST/_QH_CONVERTED_FILES'. Run 'eg/make-qhull_qh.sh libqhull_r' first. exit 1 fi else SOURCES="$@" DEST=${DEST:-src/qhull_qh} fi if [[ $SEDONLY -ne 1 ]]; then if [[ -d $DEST ]]; then echo "To rebuild '$DEST' from '$SOURCES'" if [[ "$DEST" == "src/qhull_qh" ]]; then echo " make cleanall; eg/make-qhull_qh.sh $@" else echo " rm -rf '$DEST'; eg/make-qhull_qh.sh $@" fi exit 1 fi for F in $SOURCES; do if [[ ! -d $F && ! -r $F ]]; then echo "eg/make-qhull_qh.sh: source '$F' not found. Execute make-qhull_qh.sh from a Qhull directory with $SOURCES" exit 1 fi done echo eg/make-qhull_qh.sh: Create "'$DEST/' from '$SOURCES'" mkdir $DEST || exit 1 echo -e "eg/make-qhull_qh.sh created '$DEST' to compare reentrant with non-reentrant Qhull" >$DEST/README.txt echo -e "\nSource directories and files -- $SOURCES" >>$DEST/README.txt echo -e "\n'make cleanall' deletes 'src/qhull_qh/'\n" >>$DEST/README.txt date >>$DEST/README.txt touch $DEST/_QH_CONVERTED_FILES for X in $SOURCES; do if [[ -d $X ]]; then for F in $X/*_r.* $X/*_ra.* $X/*.def; do if [[ -f $F ]]; then G="$(echo ${F##*/} | sed -e 's/_r\././' -e 's/_ra\./_a./')" # echo "$F => $DEST/$G" cp -p $F $DEST/$G || exit 1 fi done if [[ -f $X/Makefile && ! -f $DEST/Makefile ]]; then cp -p $X/Makefile $DEST/ || exit 1 fi if [[ -f $X/index.htm && ! -f $DEST/index.htm ]]; then cp -p $X/index.htm $DEST/ || exit 1 fi elif [[ -f $X ]]; then G="$(echo ${X##*/} | sed -e 's/_r\././' -e 's/_ra\./_a./')" # echo "$X => $DEST/$G" cp -p $X $DEST/$G || exit 1 fi done fi echo Convert 'qh->' to 'qh ', etc. if [[ -w $DEST/Makefile ]]; then sed -i -r \ -e 's/_r$//' \ -e 's/_r / /g' \ -e 's|_r/|/|g' \ -e 's/_r\.a/.a/g' \ -e 's/_r\.c/.c/g' \ -e 's/_r\.h/.h/g' \ -e 's/_r\.o/.o/g' \ -e 's/_ra\.h/_a.h/g' \ $DEST/Makefile || exit 1 fi for F in $DEST/*.c $DEST/*.h; do sed -i -r \ -e 's/\(qhT \*qh, /(/' \ -e ' /ifdef __cplusplus/,/^$/ d' \ -e 's/\(qhT \*qh(.*)\)/(void\1)/' \ -e 's/_r$//' \ -e 's/_r([ /:])/\1/g' \ -e 's/_r\.c/.c/g' \ -e 's/_r\.h/.h/g' \ -e 's/_r\.o/.o/g' \ -e 's/_ra\.h/_a.h/g' \ -e 's/ \|\| \!qh\)/)/' \ -e 's/_rbox\(qh, qh->/_rbox(rbox./' \ -e ' /QHULL_UNUSED\(qh\)/ d' \ -e 's/qh->rbox_([^c])/rbox.\1/g' \ -e 's/\(qh, (.*) \)$/( \1 )/' \ -e 's/\(qh, (.*) \) \{ \.\.\. \}$/( \1 ) { ... }/' \ -e 's/\(qh *\)$/( )/' \ -e 's/\(qhB?, /(/g' \ -e 's/\(qhB?\)/()/g' \ -e 's/\(qh /(/g' \ -e 's/qh->qhmem/qhmem/g' \ -e 's/qh->qhstat\./qhstat /g' \ -e 's/qh->/qh /g' \ -e 's/qhull_r-/qhull-/g' \ -e "s/Needed for qhT in libqhull.h/Needed for qhT in libqhull_r.h. Here for compatibility/" \ -e ' /ifdef __cplusplus/,/^$/ d' \ -e ' /qh may be NULL/ d' \ -e ' /For libqhull_r,/ d' \ -e ' /reentrant only/ d' \ -e ' /assumes qh defined/ d' \ -e ' /^ *\/\*.*\.cpp -- / d' \ $F # sed requires space before search expressions, /.../ if which u2d >/dev/null 2>&1; then u2d $F fi done for F in $DEST/*.htm; do sed -i -r \ -e 's|_r/|/|g' \ -e 's/_r\.c/.c/g' \ -e 's/_r\.h/.h/g' \ -e 's/_ra\.h/_a.h/g' \ $F if which u2d >/dev/null 2>&1; then u2d $F fi done echo -e "\nCompare '$DEST' to 'src/libqhull', 'src/qdelaunay', etc. Do not ignore minor differences." qhull-2020.2/eg/make-vcproj.sh0000755060175106010010000003560313471257542014357 0ustar bbarber#!/bin/bash # # make-vcproj.sh YYMMDD -- Make sln and vcproj files from CMakeLists.txt and qhull-all.pro # eg/make-vcproj.sh qhull-x -- Derive src/qhull-x/ from src/libqhull_r # # Design # CMake vcproj files includes absolute paths and does not handle 'd' annotatios for debug versions # Remove CMake targets # Change absolute paths to '../..' # Append '_d' to debug products # Write targets to '../lib/' and ../bin/' # # $Id: //main/2019/qhull/eg/make-vcproj.sh#1 $$Change: 2661 $ # $DateTime: 2019/05/24 20:09:58 $$Author: bbarber $ if [[ "$1" != "" && "$1" != "Win64" && "$1" != "qhull-x" && "$1" != "sed-only" ]]; then echo "eg/make-vcproj.sh Win64|sed-only|qhull-x" echo "Written for 'sed 4.0.7', 'Visual Studio 11 2012 Win64', and 'Visual Studio 8 2005'" echo "Other variations are likely to fail" exit fi if [[ "$1" == "qhull-x" ]]; then set -v win64=1 if [[ ! -w build/qhull.sln || ! -r build/qhull-64.vcxproj || ! -d src/libqhull_r ]]; then echo "Excute 'eg/make-vcproj.sh qhull-x' from qhull directory with build/qhull.sln, build/qhull-64.vcxproj, src/libqhull_r" exit fi SOURCEDIR=. SOURCE=$SOURCEDIR/src/libqhull_r SOURCE2=$SOURCEDIR/src/qhull SOURCE3=$SOURCEDIR/src/rbox DEST=/c/bash/local/qhull/src/qhull-x DEST2=$DEST # SOURCE=../qhull-y/src/libqhull_r # SOURCE2=src/qhull # DEST=src/qhull-x # DEST2=../../../qhull/$DEST # relative to SOURCE if [[ -d $DEST ]]; then echo "To rebuild $DEST from $SOURCE and $SOURCE2 -- rm -r $DEST; eg/make-vcproj.sh qhull-x" else echo Create $DEST from $SOURCE and $SOURCE2 mkdir $DEST || exit 1 pushd $SOURCE || exit 1 sed -e 's/_r/_x/g' -e 's/_xbox/_rbox/g' Makefile >$DEST2/Makefile || exit 1 for F in *_r.c; do G=${F%_r.c}_x.c; echo $G; cp -p $F $DEST2/$G || exit 1 done for F in *_r.h; do G=${F%_r.h}_x.h; echo $G; cp -p $F $DEST2/$G || exit 1 done for F in *_ra.h; do G=${F%_ra.h}_xa.h; echo $G; cp -p $F $DEST2/$G || exit 1 done popd pushd $SOURCE2 || exit 1 for F in *_r.c; do G=${F%_r.c}_x.c; echo $G; cp -p $F $DEST2/$G || exit 1 done popd pushd $SOURCE3 || exit 1 for F in *_r.c; do G=${F%_r.c}_x.c; echo $G; cp -p $F $DEST2/$G || exit 1 done popd echo "Substitute *_x for *_r" sed -i 's/_r\.h/_x.h/' $DEST/* sed -i 's/_ra\.h/_xa.h/' $DEST/* sed -i 's|libqhull_r/libqhull_x|libqhull_x|' $DEST/* sed -i 's|libqhull_r/random_x|random_x|' $DEST/* echo "Restrict Makefile to qhull-x and rbox" sed -i ' /^all. / s/qhull_links//' $DEST/Makefile sed -i ' /-f .*exe/ s/qconvex.*exe/core rbox qhull-x *.exe/' $DEST/Makefile sed -i ' /-p .*BINDIR/ s/qconvex.*rbox/qhull-x/' $DEST/Makefile sed -i ' /-o qhull/ s/qhull/qhull-x/' $DEST/Makefile sed -i '\|\./qhull| s/qhull/qhull-x/' $DEST/Makefile sed -i 's|\.\./qconvex.*|unix_x.c|' $DEST/Makefile sed -i ' /^qhull_all. / s/qconvex.*testqset_x.o/unix_x.o rbox_x.o/' $DEST/Makefile for D in qconvex qdelaunay qhalf qvoronoi user_eg testqset libqhullstatic DOCDIR INCDIR LIBDIR MANDIR; do sed -i " /$D/ d" $DEST/Makefile done sed -i " /ln -s / d" $DEST/Makefile fi pushd build/ || exit 1 SOURCE=../src/qhull-x VCXPROJ=qhull-x-64.vcxproj GUID=3192557A-C34A-426E-A51B-2BCE463EAD02 VCXPROJ2=qhull-64.vcxproj GUID2=E8BF0EA0-A09D-4155-BCEC-CC1B0DF8A67E echo Create $VCXPROJ from $VCXPROJ2 if ! grep $GUID qhull-64.sln >/dev/null; then echo add GUID for $VCXPROJ to qhull-64.sln -- $GUID fi cp $VCXPROJ2 $VCXPROJ || exit 1 grep $GUID2 $VCXPROJ2 >/dev/null || (echo unknown GUID for $VCXPROJ2 -- $GUID2; exit 1) sed -i s/$GUID2/$GUID/g $VCXPROJ sed -i 's/ProjectReference Include=.*/ProjectReference>/' $VCXPROJ sed -i 's/.*//' $VCXPROJ # need to delete 3 lines sed -i -r 's/;...lib.qhullstatic_rd?.lib//' $VCXPROJ sed -i 's/qhull/qhull-x/g' $VCXPROJ # Since qhull pulls object files from libqhullstatic_r.lib, order unknown, may be in specified order for F in $SOURCE/*_x.h; do sed -i " /ClCompile.*_r.c/ i " $VCXPROJ done for F in $SOURCE/*_x.c; do sed -i " /ClCompile.*_r.c/ i " $VCXPROJ done sed -i ' /_r.c/ d' $VCXPROJ popd exit elif [[ "$1" == "Win64" ]]; then if [[ "$2" != "" && "$2" != "sed-only" ]]; then echo "eg/make-vcproj.sh [Win64] [sed-only]" exit fi win64=1 else win64=0 fi if [[ "$1" == "sed-only" || "$2" == "sed-only" ]]; then echo Skip creating buildvc/ and buildqt/ else # else execute to 'fi ... sed-only' if [[ ! -f CMakeLists.txt || ! -f src/qhull-all.pro ]]; then echo "Excute eg/make-vcproj.sh from qhull directory with CMakeLists.txt and src/qhull-all.pro" exit fi echo "Set up build directories..." if [[ ! -d build-prev ]]; then echo "Backup previous build" cp -r build build-prev && rm -rf build fi rm -rf buildvc buildqt mkdir -p build mkdir -p build/qhulltest mkdir -p buildvc mkdir -p buildqt echo "Create vcproj files with cmake and qmake..." if [[ $win64 -eq 1 ]]; then echo Running -- cmake -G "Visual Studio 11 2012 Win64" cd buildvc && cmake -G "Visual Studio 11 2012 Win64" .. && cmake .. else echo Running -- cmake -G "Visual Studio 8 2005" cd buildvc && cmake -G "Visual Studio 8 2005" .. && cmake .. fi cd .. cd buildqt && qmake -tp vc -r ../src/qhull-all.pro cd .. if [[ ! -f CMakeLists.txt ]]; then echo "Missing CMakeLists.txt. Cannot run cmake" exit elif [[ (! -f buildvc/qhull.vcproj && ! -f buildvc/qhull.vcxproj) || (! -f buildqt/qhulltest/qhulltest.vcproj && ! -f buildqt/qhulltest/qhulltest.vcxproj) ]]; then echo "qmake and cmake did not build vcproj or vcxproj files in buildvc/ and buildqt/" exit fi echo echo 'Create build/*.vcproj by converting absolute paths to relative paths' echo Removes INSTALL/ALL_BUILD/ZERO_CHECK/RUN_TESTS projects echo Turn off LinkIncremental and RuntimeTypeInfo echo Add 'd' flags to debug lib/dll files... echo 'Delete CMake... and other instances of CMake' echo 'WARN: These sed replacements depend on how CMake creates vcproj or vcxproj files. It is likely to change.' fi # Skipped if 'sed-only' for f in buildvc/*.vc*proj buildqt/qhulltest/*.vc*proj; do echo -n $f if [[ ! ${f##*INSTALL*} || ! ${f##*ALL_BUILD*} || ! ${f##*ZERO_CHECK*} || ! ${f##*RUN_TESTS*} ]]; then echo " removed" continue fi if [[ $win64 -eq 1 ]]; then ext=${f##*.} base=${f#*\/} base=${base%.*} dest=build/$base-64.$ext echo " => $dest" # sed requires a blank or \ before address ranges # sed requires a \/ for s|...|...| ! # the ConfigurationType clauses depend on Debug being first sed -r \ -e ' /CustomBuild.*CMake/,/CustomBuild/ d' \ -e ' /ZERO_CHECK/,/ProjectReference/ d' \ -e ' />qhulltest/ s|[cC]:\\bash\\local\\qhull|..\\..|g' \ -e ' />qhulltest/ s|[cC]:\/bash\/local\/qhull|..\/..|g' \ -e 's|[cC]:\\bash\\local\\qhull|..|g' \ -e 's|[cC]:\/bash\/local\/qhull|..|g' \ -e '\|CMake| d' \ -e '\|VCWebServiceProxyGeneratorTool| d' \ -e 's/;CMAKE_INTDIR=[^;]*;/;/' \ -e 's/;[a-zA-Z]*\\([_a-z0-9]*\.lib[;<])/;..\\lib\\\1/g' \ -e ' /LinkIncremental/ s/true/false/' \ -e 's/buildvc/build/g' \ -e 's/buildqt/build/g' \ -e 's/c:\\qt\\[0-9]\.[0-9]\.[0-9]/\$(QTDIR)/g' \ -e 's|..\/build\/[a-zA-Z]*[\\/]([_a-z0-9]*.pdb)|..\/bin\/\1|g' \ -e 's|..\/build\/[a-zA-Z]*[\\/]([_a-z0-9]*.exe)|..\/bin\/\1|g' \ -e 's|..\/build\/[a-zA-Z]*[\\/]([_a-z0-9]*.lib)|..\/lib\/\1|g' \ -e 's|..\/build\/[a-zA-Z]*[\\/]([_a-z0-9]*.dll)|..\/bin\/\1|g' \ -e 's| [a-zA-Z]*[\\/]([_a-z0-9]*\.lib)| ..\\lib\\\1|g' \ -e 's/"([_a-z0-9]*.exe)/"..\\bin\\\1/g' \ -e ' /ConfigurationType>Application/,/ClInclude/ s/(OutDir.*\.\.)[\\a-zA-Z]*DynamicLibrary/,/ClInclude/ s/(OutDir.*\.\.)[\\a-zA-Z]*DynamicLibrary/,/ImportLibrary/ s/(ImportLibrary.*_[rp])\.libDynamicLibrary/,/ImportLibrary/ s/(ImportLibrary.*[^d])\.libDynamicLibrary/,/TargetName.*Debug/ s/(TargetName.*_[pr])DynamicLibrary/,/TargetName.*Debug/ s/(TargetName.*Debug.*[^d])DynamicLibrary/,/ProgramDataBaseFile/ s/(ProgramDataBaseFile.*_[pr])\.pdb/\1d.pdb/' \ -e ' /ConfigurationType>DynamicLibrary/,/ProgramDataBaseFile/ s/(ProgramDataBaseFile.*[^d])\.pdb/\1_d.pdb/' \ -e ' /ConfigurationType>StaticLibrary/,/ClInclude/ s/(OutDir.*\.\.)[\\a-zA-Z]*StaticLibrary/,/ImportLibrary/ s/(ImportLibrary.*_[rp])\.libStaticLibrary/,/ImportLibrary/ s/(ImportLibrary.*[^d])\.libStaticLibrary/,/TargetName.*Debug/ s/(TargetName.*_[pr])StaticLibrary/,/TargetName.*Debug/ s/(TargetName.*Debug.*[^d])StaticLibrary/,/ProgramDataBaseFile/ s/(ProgramDataBaseFile.*_[pr])\.pdb/\1d.pdb/' \ -e ' /ConfigurationType>StaticLibrary/,/ProgramDataBaseFile/ s/(ProgramDataBaseFile.*[^d])\.pdb/\1_d.pdb/' \ -e ' /ItemDefinitionGroup.*Debug/,/AdditionalDependencies/ s/(AdditionalDependencies.*_r)\.lib/\1d.lib/g' \ -e ' /ItemDefinitionGroup.*Debug/,/AdditionalDependencies/ s/(AdditionalDependencies.*qhull[a-z]*[^d])\.lib/\1_d.lib/g' \ -e ' /AdditionalDependencies/ s/;[a-zA-Z]*\\/;..\\lib\\/g' \ -e 's/[cC]:\\[qQ]t\\[qQt0-9.\\]*msvc[_0-9]*/\$(QTDIR)/g' \ -e 's/[cC]:\\[qQ]t\\[qQt0-9.\\]*/\$(QTDIR)\\..\\/g' \ -e 's/([|>])Win32/\1x64/' \ -e 's/machine:X86/machine:x64/' \ -e 's/\.vcxproj/-64.vcxproj/' \ $f | awk '//{ next } / $dest else dest=build/${f##*\/} # sed requires a blank or \ before address ranges sed -r -e 's|[cC]:\\bash\\local\\qhull|..|g' \ -e 's|[cC]:/bash/local/qhull|..|g' \ -e '\|CMake| d' \ -e '\|VCWebServiceProxyGeneratorTool| d' \ -e 's/;CMAKE_INTDIR=..quot;[A-Za-z]*..quot;//' \ -e 's/LinkIncremental="2"/LinkIncremental="1"/' \ -e 's/RuntimeLibrary[=]/RuntimeTypeInfo="false" RuntimeLibrary=/' \ -e 's/.*RuntimeTypeInfo."TRUE".*//' \ -e 's/buildvc/build/g' \ -e 's/buildqt/build/g' \ -e 's/\.\.\\\.\./../g' \ -e 's|\.\./\.\.|..|g' \ -e 's/c:\\qt\\[0-9]\.[0-9]\.[0-9]/\$(QTDIR)/g' \ -e 's|..\\build\\[a-zA-Z]*[\\/]([_a-z0-9]*.pdb)|..\\bin\\\1|g' \ -e 's|..\\build\\[a-zA-Z]*[\\/]([_a-z0-9]*.exe)|..\\bin\\\1|g' \ -e 's|..\\build\\[a-zA-Z]*[\\/]([_a-z0-9]*.lib)|..\\lib\\\1|g' \ -e 's|..\\build\\[a-zA-Z]*[\\/]([_a-z0-9]*.dll)|..\\bin\\\1|g' \ -e 's| [a-zA-Z]*[\\/]([_a-z0-9]*\.lib)| ..\\lib\\\1|g' \ -e 's/"([_a-z0-9]*.exe)/"..\\bin\\\1/g' \ -e ' /Name="Debug/,/OutputFile/ s/(OutputFile.*_[rp])\.(dll|lib)"/\1d.\2"/' \ -e ' /Name="Debug/,/OutputFile/ s/(OutputFile.*[^d])\.(dll|lib)"/\1_d.\2"/' \ -e ' /Name="Debug/,/ImportLibrary/ s/(ImportLibrary.*_[rp])\.lib"/\1d.lib"/' \ -e ' /Name="Debug/,/ImportLibrary/ s/(ImportLibrary.*[^d])\.lib"/\1_d.lib"/' \ -e ' /Name="Debug/,/AdditionalDependencies/ s/(AdditionalDependencies.*_[rp])\.lib/\1d.lib/' \ -e ' /Name="Debug/,/AdditionalDependencies/ s/(AdditionalDependencies.*qhull[a-z]*[^d])\.lib/\1_d.lib/' \ -e ' /Name="Debug/,/ProgramDatabaseFile/ s/(ProgramDatabaseFile.*_r)\.pdb/\1d.pdb/' \ -e ' /Name="Debug/,/ProgramDatabaseFile/ s/(ProgramDatabaseFile.*qhull[a-z]*[^d])\.pdb/\1_d.pdb/' \ -e 's/[cC]:\\Qt\\[0-9.]*/\$(QTDIR)/g' \ -e 's/\.vcxproj/-32.vcxproj/' \ $f | awk '//{ next } / $dest fi # grep -E '\.\.[\\/]|_[a-z]?d[^a-z]' $dest done echo echo Create build/qhull.sln or build/qhull-64.sln from buildvc/qhull.sln if [[ $win64 -eq 1 ]]; then echo Create qhull-64.sln sed -r \ -e '\|Project.*ALL_BUILD|,\|EndProject$| d' \ -e '\|Project.*INSTALL|,\|EndProject$| d' \ -e '\|Project.*ZERO_CHECK|,\|EndProject$| d' \ -e '\|Project.*RUN_TESTS|,\|EndProject$| d' \ -e '\|ProjectDependencies|,\| = | s/^.* = \{.*$//' \ -e 's/\.vcxproj/-64.vcxproj/' \ buildvc/qhull.sln >build/qhull-64.sln echo Create qhull-32.sln from qhull-64 with 32 GUIDs # Need to keep the original GUIDs. Otherwise get -- can't locate project '' sed -r \ -e 's/-64\.vcxproj/-32.vcxproj/' \ -e 's/([|>])x64/\1Win32/g' \ build/qhull-64.sln >build/qhull-32.sln echo Create *-32.vcxproj with 32 GUIDs for f in build/*-64.vcxproj build/qhulltest/*-64.vcxproj; do dest=${f%64.vcxproj}32.vcxproj sed -r \ -e 's/([|>])x64/\1Win32/' \ -e 's/machine:x64/machine:X86/' \ $f >$dest done echo Convert vcxproj/sln files to DOS format for f in build/*.vcxproj build/*-32.sln build/*-64.sln; do u2d $f done else sed -e '\|Project.*ALL_BUILD|,\|EndProject$| d' \ -e '\|Project.*INSTALL|,\|EndProject$| d' \ -e '\|Project.*ZERO_CHECK|,\|EndProject$| d' \ -e '\|Project.*RUN_TESTS|,\|EndProject$| d' \ buildvc/qhull.sln >build/qhull.sln echo Convert vcproj/sln files to DOS format for f in build/*.vcproj build/*.sln; do u2d $f done fi echo echo 'Add qhulltest.vcproj to qhull.sln' echo ' Open qhull.sln with DevStudio' echo ' Add build/qhulltest/qhulltest.vcproj or qhulltest-64.vcxproj' echo ' Add dependencies on qhullcpp (user_eg3, qhulltest)' echo ' Add dependencies on qhullstatic (rbox, qconvex, etc)' echo ' Add dependencies on qhullstatic_r (qhull, user_eg2)' echo ' Add dependencies on libqhull_r (user_eg) and qhullstatic_r' echo ' Remove qhulltest via Configuration Manager from Release,Debug,etc. Qt is optional' echo echo 'Update Perforce for build/...vcproj, otherwise qhull-zip.sh will revert the files' qhull-2020.2/eg/Qhull-go.bat0000644060175106010010000000074511663056726013763 0ustar bbarber: Qhull-go.bat invoked as cmd.com from QHULL-GO @echo off echo. echo ========= Qhull with rbox, qconvex, qdelaunay, qvoronoi, qhalf ============ echo. echo Use arrow keys to repeat and edit commands. echo. echo Double-click window bar for full height, or echo "right-click > Properties > Layout > Window Size > Height > 50 " echo. echo Type 'qconvex' for synopsis and examples. echo. echo ========= echo. title Qhull cd bin %comspec% qhull-2020.2/eg/qhull-zip.sh0000755060175106010010000005531013724313107014052 0ustar bbarber#!/bin/sh # # qhull-zip.sh version -- Make zip and tgz files for Qhull release # # requires road-script.sh from http://www.qhull.org/road/ # for check_err_log, log_step, log_note, exit_err, exit_if_fail, etc. # # wzzip from http://www.winzip.com/wzcline.htm # can not use path with $zip_file # odd error messages if can't locate directory # # $Id: //main/2019/qhull/eg/qhull-zip.sh#39 $$Change: 3039 $ # $DateTime: 2020/09/03 21:26:22 $$Author: bbarber $ if [[ $# -ne 3 ]]; then echo 'Missing date stamp -- eg/qhull-zip.sh 2020 2020.2 8.0.2' echo 'Build Release Win32 binaries -- build/... from Perforce, make cleanall, retarget vcxproj files, restart DevStudio' echo 'Check libqhull_r and libqhull are the same. See qh_code.htm#convert' exit fi versionyear=$1 version=$2 versionunix=$3 echo $TMP err_program=qhull-zip err_log=$TMP/qhull-zip.log [[ -e $HOME/bash/etc/road-script.sh ]] && source $HOME/bash/etc/road-script.sh \ || source /etc/road-script.sh check_err_log $LINENO "$err_log" check_err_log $LINENO "$err_step_log" log_step $LINENO "Logging to $err_log\n... and $err_step_log" log_note $LINENO "Find Qhull directory" if [[ ! -d qhull/eg && ! -d ../qhull/eg && -d ../../qhull/eg ]]; then exit_err $LINENO "qhull/eg directory not found at or above $PWD" fi if [[ ! -d qhull/eg ]]; then if [[ -d ../qhull/eg ]]; then cd .. else cd ../.. # Tested above fi fi root_dir=$(pwd) echo root_dir= $root_dir TEMP_DIR="$TMP/qhull-zip-$(ro_today2)" TEMP_FILE="$TMP/qhull-zip-$(ro_today2).txt" qhull_zip_file=qhull-$version.zip # no path or spaces qhull_tgz_file=qhull-$versionyear-src-$versionunix.tgz qhullmd5_file=qhull-$version.md5sum exit_if_fail $LINENO "rm -f $qhull_zip_file $qhull_tgz_file $qhullmd5_file" if [[ -e /bin/msysinfo || -e /bin/msys-z.dll ]]; then ############################# log_step $LINENO "Check for DevStudio 32-bit release build without q_test2" ############################# ls -l qhull/bin/*.exe qhull/bin/*.dll qhull/bin/rbox 4 D2 | qhull/bin/qhull Tsz | grep "size in bytes" qhull/bin/rbox 4 D2 | qhull/bin/qhull Tsz | grep "size in bytes" | grep "ridge 20" exit_if_err $LINENO "Not a 32-bit build (expecting 'ridge 20')" if grep eg/q_test2 qhull/Makefile; then exit_err $LINENO "Change eg/q_test2 to eg/q_test in Makefile.testall" fi log_step $LINENO "Check 'p4 diff se' for modified files" if (p4 diff -se qhull/... | grep -v vcxp | grep qhull); then exit_err $LINENO "Submit modified files to Perforce" fi if [[ -d src/qhull_qh ]]; then exit_err $LINENO "Delete src/qhull_qh/" fi fi ############################# log_step $LINENO "Check files" ############################# exit_if_fail $LINENO "cd qhull" if ! grep "if 0 .* QHULL_CRTDBG" src/libqhull/user.h >/dev/null; then exit_err $LINENO "QHULL_CRTDBG is defined in src/libqhull/user.h" elif ! grep "if 0 .* QHULL_CRTDBG" src/libqhull_r/user_r.h >/dev/null; then exit_err $LINENO "QHULL_CRTDBG is defined in src/libqhull_r/user_r.h" elif ! grep "^#define qh_QHpointer 0" src/libqhull/user.h >/dev/null; then exit_err $LINENO "qh_QHpointer is defined in src/libqhull/user.h" fi if (od -a Makefile src/libqhull/Makefile src/libqhull_r/Makefile build/*.pc.in html/*.man eg/*.sh eg/q_eg eg/q_egtest eg/q_test | grep cr >/dev/null); then for f in Makefile src/*/Makefile build/*.pc.in html/*.man eg/*.sh eg/q_eg eg/q_egtest eg/q_test; do echo $f; od -a $f | grep cr | head -1; done exit_err $LINENO "A UNIX file contains DOS line endings. Use d2u and binary type" fi NOT_OK=$(grep -h "^ " Makefile src/libqhull/Makefile src/libqhull_r/Makefile | grep -vE '^[ \t]+[$()a-zA-Z_/]+\.[oh]|bin/testqset_r qtest') if [[ -n "$NOT_OK" ]]; then exit_err $LINENO "A Makefile contains a leading space instead of tabs:\n$NOT_OK" fi TXTFILES=$(find *.diz *.htm *.txt html/ src/ working/qhull-news.html -type f -name '*.c' -o -name '*.cpp' -o -name '*.def' -o -name '*.diz' -o -name '*.h' -o -name '*.htm*' -o -name '*.txt' -o -name '*.pri' -o -name '*.pro' -o -name '*.txt' -o -name '*.txt' -o -name '*.xml') NOT_OK=$(for f in $TXTFILES; do if (od -a $f | grep '[^r0-9 ] *nl' >/dev/null); then echo $f; fi; done) if [[ -n "$NOT_OK" ]]; then exit_err $LINENO "Text files with Unix line endings:\n$NOT_OK\nu2d *.diz *.htm *.txt html/*.txt html/*.htm html/*.xml src/*.pr* src/*.txt src/*/*.c;\nu2d src/*/*.cpp src/*/*.def src/*/*.h src/*/*.htm src/*/*.pro src/*/*.txt working/qhull-news.html" fi exit_if_fail $LINENO "cd .." ############################# log_step $LINENO "Check environment" ############################# [[ $(type -p md5sum) ]] || exit_err $LINENO "md5sum is missing" [[ $(cp --help || grep '[-]-parents') ]] || exit_err $LINENO "cp does not have --parents option" ############################# log_step $LINENO "Define functions" ############################# function check_zip_file #zip_file { local zip_file=$1 local HERE=$(ro_here) log_note $HERE "Check $zip_file" ls -l $zip_file >>$err_log exit_if_err $HERE "Did not create $zip_file" wzunzip -ybc -t $zip_file | grep -E -v -e '( OK|Zip)' >>$err_log exit_if_err $HERE "Error while checking $zip_file" } function check_tgz_file #tgz_file { local tgz_file=$1 local HERE=$(ro_here) log_note $HERE "Check $tgz_file" ls -l $tgz_file >>$err_log exit_if_err $HERE "Did not create $tgz_file" tar -tzf $tgz_file >/dev/null 2>>$err_log exit_if_err $HERE "Can not extract -- tar -tzf $tgz_file" } function convert_to_unix #dir $qhull_2ufiles -- convert files to Unix, preserving modtime from $root_dir { local temp_dir=$1 local HERE=$(ro_here) log_note $HERE "Convert files to unix format in $1" for f in $(find $temp_dir -type f | grep -E '^([^.]*|.*\.(ac|am|bashrc|c|cfg|cpp|css|d|dpatch|h|htm|html|man|pl|pri|pro|profile|sh|sql|termcap|txt|xml|xsd|xsl))$'); do exit_if_fail $HERE "d2u '$f' && touch -r '$root_dir/${f#$temp_dir/}' '$f'" done for f in $qhull_2ufiles; do exit_if_fail $HERE "d2u '$temp_dir/$f' && touch -r '$root_dir/$f' '$temp_dir/$f'" done } function create_md5sum #md5_file -- create md5sum of current directory { local md5_file=$1 local HERE=$(ro_here) log_step $HERE "Compute $md5_file" exit_if_fail $HERE "rm -f $md5_file" find . -type f | sed 's|^\./||' | LC_COLLATE=C sort | xargs md5sum >>$md5_file exit_if_err $HERE "md5sum failed" log_note $HERE "$(md5sum $md5_file)" } function findf #name [path] { find . -type f -name "*$2*" -not -path "*.git*" | egrep -i "${1:-.}" } ############################# log_step $LINENO "Configure $0 for $(pwd)/qhull" ############################# md5_zip_file=qhull-$version-zip.md5sum md5_tgz_file=qhull-$versionyear-src-$versionunix-tgz.md5sum # recursive qhull_dirs="qhull/build/CMakeModules qhull/eg qhull/html qhull/src" qhull_files="qhull/build/*.sln qhull/build/*.vcproj qhull/build/qhulltest/*.vcproj \ qhull/build/*.vcxproj qhull/build/config.cmake.in qhull/build/qhulltest/*.vcxproj \ qhull/Announce.txt qhull/CMakeLists.txt qhull/COPYING.txt qhull/File_id.diz \ qhull/build/qhull.pc.in qhull/build/README-build.txt qhull/QHULL-GO.lnk \ qhull/README.txt qhull/REGISTER.txt qhull/index.htm qhull/Makefile \ qhull/bin/qconvex.exe qhull/bin/qdelaunay.exe qhull/bin/qhalf.exe \ qhull/bin/qhull.exe qhull/bin/*qhull_r.dll qhull/bin/qvoronoi.exe \ qhull/bin/rbox.exe qhull/bin/user_eg.exe qhull/bin/user_eg2.exe \ qhull/bin/testqset_r.exe \ qhull/bin/user_eg3.exe qhull/bin/testqset.exe qhull/bin/msvcr80.dll" qhull_ufiles="$qhull_dirs qhull/build/*.sln qhull/build/*.vcproj \ qhull/build/*.vcxproj qhull/build/config.cmake.in \ qhull/Announce.txt qhull/CMakeLists.txt qhull/COPYING.txt \ qhull/File_id.diz qhull/build/qhull.pc.in qhull/QHULL-GO.lnk qhull/README.txt \ qhull/REGISTER.txt qhull/index.htm qhull/Makefile" qhull_d2ufiles="Makefile src/libqhull/Makefile src/libqhull_r/Makefile \ qhull/build/config.cmake.in \ src/*/DEPRECATED.txt src/*/*.pro src/*/*.htm html/*.htm html/*.txt \ src/libqhull/MBorland eg/q_eg eg/q_egtest eg/q_test " if [[ -e /bin/msysinfo || -e /bin/msys-z.dll ]]; then ############################# log_step $LINENO "Check qhull_files for zip directory" ############################# ls -l $qhull_files $qhull_dirs >>$err_log exit_if_err $LINENO "Missing files for zip directory. Release build only" fi ############################# log_step $LINENO "Clean distribution directories" ############################# rm -r qhull/build/* p4 sync -f qhull/build/... exit_if_err $LINENO "Can not 'p4 sync -f qhull.sln *.vcproj'" rm qhull/build/user_egp.vcproj qhull/build/qhullp.vcproj cd qhull && make clean exit_if_err $LINENO "Can not 'make clean'" cd .. # Includes many files from 'cleanall' (Makefile) rm -f qhull/src/qhull-all.pro.user* qhull/src/libqhull/BCC32tmp.cfg rm -f qhull/eg/eg.* qhull/eg/qhull-benchmark.log qhull/eg/qhull-benchmark-show.log rm -f qhull/bin/qhulltest.exe qhull/bin/qhulltest qhull/bin/qhullp.exe rm -f qhull/bin/user_egp.exe qhull/bin/libqhull_*.dll rm -f qhull/src/libqhull/*.exe qhull/src/libqhull/*.a qhull/src/libqhull/*.dll rm -f qhull/src/libqhull_r/*.exe qhull/src/libqhull_r/*.a qhull/src/libqhull_r/*.dll rm -f qhull/src/libqhull/qconvex.c qhull/src/libqhull/unix.c rm -f qhull/src/libqhull/qdelaun.c qhull/src/libqhull/qhalf.c rm -f qhull/src/libqhull/qvoronoi.c qhull/src/libqhull/rbox.c rm -f qhull/src/libqhull/user_eg.c qhull/src/libqhull/user_eg2.c rm -f qhull/src/libqhull/testqset.c rm -f qhull/src/libqhull_r/qconvex_r.c qhull/src/libqhull_r/unix_r.c rm -f qhull/src/libqhull_r/qdelaun_r.c qhull/src/libqhull_r/qhalf_r.c rm -f qhull/src/libqhull_r/qvoronoi_r.c qhull/src/libqhull_r/rbox_r.c rm -f qhull/src/libqhull_r/user_eg_r.c qhull/src/libqhull_r/user_eg2_r.c rm -f qhull/src/libqhull_r/testqset_r.c find qhull/ -type f -name x -o -name 'x.*' -o -name '*.x' | xargs -r rm set noglob if [[ (-e /bin/msysinfo || -e /bin/msys-z.dll) && $(type -p wzzip) && $(type -p wzunzip) ]]; then ############################# log_step $LINENO "Build zip directory as $TEMP_DIR/qhull" ############################# ls -l $qhull_files $qhull_dirs >>$err_log exit_if_err $LINENO "Missing files for zip directory. Release build only" log_note $LINENO "Copy \$qhull_files \$qhull_dirs to $TEMP_DIR/qhull" exit_if_fail $LINENO "rm -rf $TEMP_DIR && mkdir $TEMP_DIR" exit_if_fail $LINENO "cp -r -p --parents $qhull_files $qhull_dirs $TEMP_DIR" ############################# log_step $LINENO "Write md5sum to $md5_tgz_file" ############################# exit_if_fail $LINENO "pushd $TEMP_DIR/qhull" create_md5sum $md5_zip_file exit_if_fail $LINENO "cp -p $md5_zip_file $root_dir" ############################# log_step $LINENO "Write $qhull_zip_file" ############################# log_note $LINENO "Write \$qhull_files to $qhull_zip_file" exit_if_fail $LINENO "cd .. && mv qhull qhull-$version && md5sum qhull-$version/$md5_zip_file >>$root_dir/$qhullmd5_file" wzzip -P -r -u $qhull_zip_file qhull-$version >>$err_log exit_if_err $LINENO "wzzip does not exist or error while zipping files" check_zip_file $qhull_zip_file exit_if_fail $LINENO "popd" exit_if_fail $LINENO "mv $TEMP_DIR/$qhull_zip_file ." fi ############################# log_step $LINENO "Build tgz directory as $TEMP_DIR/qhull" ############################# log_note $LINENO "Archive these files as $qhull_tgz_file" ls -l $qhull_ufiles >>$err_log exit_if_err $LINENO "Missing files for tgz" exit_if_fail $LINENO "rm -rf $TEMP_DIR && mkdir -p $TEMP_DIR" exit_if_fail $LINENO "cp -r -p --parents $qhull_ufiles $TEMP_DIR" if [[ $IS_WINDOWS && $(type -p d2u) ]]; then log_step $LINENO "Convert to Unix line endings" convert_to_unix "$TEMP_DIR" fi ############################# log_step $LINENO "Write md5sum to $md5_tgz_file" ############################# exit_if_fail $LINENO "pushd $TEMP_DIR && cd qhull" create_md5sum $md5_tgz_file exit_if_fail $LINENO "cp -p $md5_tgz_file $root_dir" exit_if_fail $LINENO "cd .. && mv qhull qhull-$version && md5sum qhull-$version/$md5_tgz_file >>$root_dir/$qhullmd5_file" ############################# log_step $LINENO "Write $qhull_tgz_file" ############################# exit_if_fail $LINENO "tar -zcf $root_dir/$qhull_tgz_file * && popd" check_tgz_file $qhull_tgz_file log_note $LINENO "md5sum of zip and tgz files" for f in $qhull_zip_file $qhull_tgz_file; do if [[ -r $f ]]; then exit_if_fail $LINENO "md5sum $f >>$qhullmd5_file" fi done ############################# log_step $LINENO "Extract zip and tgz files to $TEMP_DIR" ############################# exit_if_fail $LINENO "rm -rf $TEMP_DIR" if [[ -r $root_dir/$qhull_zip_file ]]; then exit_if_fail $LINENO "mkdir -p $TEMP_DIR/zip && cd $TEMP_DIR/zip" log_step $LINENO "Current directory is /c/Git/$TEMP_DIR/zip" exit_if_fail $LINENO "wzunzip -yb -d $root_dir/$qhull_zip_file" log_step $LINENO "Search for date stamps into zip/Dates.txt" find . -type f | grep -vE '/bin/|q_benchmark|q_test' | xargs grep '\-20' | grep -v -E '(page=|ISBN|sql-2005|utility-2000|written 2002-2003|tail -n -20|Spinellis|WEBSIDESTORY|D:06-5-2007|server-2005)' >Dates.txt find . -type f | grep -vE '/bin/|q_benchmark|q_test' | xargs grep -i 'qhull *20' >>Dates.txt find . -type f | grep -vE '/bin/|q_benchmark|q_test' | xargs grep -E 'SO=|SO |VERSION|FIXUP' >>Dates.txt log_step $LINENO "Search for error codes into zip/Errors-matched.txt" (find */src -type f) | grep -vE '_test\.cpp|\.log|Changes\.txt' | xargs grep -Eh ', [67][0-9][0-9][0-9]|"QH[67][0-9]|qh_fprintf_stderr\([67][0-9][0-9][0-9]' | sed -r 's/^[^Q67]*QH//' | sed -r 's/^.*qh_fprintf_stderr\(//' | sed -r 's/^[^67]*(errfile|ferr|fp|stderr), //' | sed 's/\\n"[,\)].*/ EOL/' | sed -r 's/_r([: ])/\1/' | sort >Errors.txt (cat Errors.txt | sed 's/, .*//'; for ((i=6001; i<6400; i++)); do echo $i; done; for ((i=7001; i<7200; i++)); do echo $i; done) | sort | uniq -c | grep -v '^ *3 ' | sed -r 's/^[^0-9]*([0-9]) (.*)/\2 \1 NOT-MATCHED/' >Errors-not-matched.txt cat Errors.txt | grep -v 'EOL$' | sort -u >Errors-matched.txt log_step $LINENO "Search for mismatched '*_r.h' references to zip/FileRef.txt" grep -E '[^_][^_][^ *][.][ch]($|[^a-z>])|/libqhull/' */src/*/*_r.* */src/*/*_ra.* */src/libqhull_r/Makefile | grep -vE 'float.h|/html/| l.h.s. |libqhullcpp|mem.c for a standalone|qglobal.h|QhullError.|QhullSet.|string.h|unused.h|user.h and user_r.h' >FileRef.txt grep -E '_r[.]|_ra[.]|/libqhull_r/' */src/qconvex/qconvex.c */src/qconvex/qconvex.c */src/qdelaunay/qdelaun.c */src/qhalf/qhalf.c */src/qvoronoi/qvoronoi.c */src/testqset/* | grep -vE 'user.h and user_r.h' >>FileRef.txt log_step $LINENO "Search for mismatched option links in htm files to Links-single.txt" findf htm | xargs grep 'qh-opt.*\#' | tee Links-all.txt | sed -r -e 's/^[^:]*://' -e 's/qh-opt/\nqh-opt/g' | grep 'qh-opt.*<' | sed -r -e 's/<.*//' | LC_ALL=C sort | uniq -c >Links-counts.txt grep ' 1 ' Links-counts.txt >Links-single.txt log_step $LINENO "Search for other internal links to Links-check-other.txt" findf htm | xargs grep -E 'http[^#]*htm#|href="?#|name=' | tee Links-other.txt | sed -e 's/#/\n#/g' -e 's/name="/\n#/g' -e 's/name=/\nname=/g' | grep -E '^#|name=' | sed -r -e 's/[" ].*//' | grep -vE ';|#[1-9][0-9]|#3dd|#[Hdv]$|[0-9][0-9]$|[a-z]T$|QJ$|convex|option|startup|voronoi|name=(as_q|num|sitesearch)' | LC_ALL=C sort | uniq -c | grep ' 1 ' >Links-check-other.txt log_step $LINENO "Search for mismatched link quotes" findf htm | xargs grep -E '"' | sed -e 's/"[^"]*"//g' | grep '"' | grep -vE 'html/qhull|html/rbox|working/debian' > Links-check-quotes.txt fi if [[ -r $root_dir/$qhull_tgz_file ]]; then exit_if_fail $LINENO "mkdir -p $TEMP_DIR/tgz && cd $TEMP_DIR/tgz" log_step $LINENO "Current directory is $TEMP_DIR/tgz" exit_if_fail $LINENO "tar -zxf $root_dir/$qhull_tgz_file" fi log_step $LINENO "Check Changes.txt" head -60 */src/Changes.txt | tail -17 ############################# log_step $LINENO "=====================================================================" log_step $LINENO "Check *qhull-zip-.../zip/Dates.txt and rbox.c for timestamps that need updating" log_step $LINENO "Check *qhull-zip-.../zip/Errors-matched.txt for mismatched codes, errors not ending in NL, errors on multiple lines, and recently missing codes" log_step $LINENO " OK (\\n in error message) -- counters 6429,7027,.., 6023, 6233, 6237, 7089" log_step $LINENO "Check *qhull-zip-.../zip/Errors-not-matched.txt for unused error codes (count==1, without text) or multiply-defined codes (count>2, 7079 OK)" log_step $LINENO "Check *qhull-zip-.../zip/Links-single.txt for single use option links (matched names OK) in Links-all.txt" log_step $LINENO "Check *qhull-zip-.../zip/Links-check-other.txt for unknown tags in Links-other.txt" log_step $LINENO "Check *qhull-zip-.../zip/Links-check-quotes.txt for quotes that cross a line" log_step $LINENO "Check q_egtest examples in Geomview" log_step $LINENO "Check for 16 projects in Release mode, including qhulltest" log_step $LINENO "Check build dependencies for programs." log_step $LINENO "Check source dependencies and help prompts once a release" log_step $LINENO " prompts: see qhull-zip.sh for command" # N=qvoronoi; ($N . | grep -vE '^$|^Except|^Qhull' | sed 's/ */\n/g'; $N - | grep -vE '^ *#|^Qhull|0 roundoff|comments|options:' | sed 's/^ *//') | grep -vE '^$' | sort >x.1 log_step $LINENO " check QhullFacet/qh_printfacetheader, QhullRidge/qh_printridge, QhullVertex/qh_printvertex" log_step $LINENO " check for internal errors while merging with pinched vertices, see qhull-zip.sh for command" # ../eg/qtest.sh 10 '10000 s C1,2e-13 D3' 'd Q14' | grep -vE 'topology|precision|CPU|Maximum' log_step $LINENO " check solution for ' = ' (comments OK)" log_step $LINENO "Test qhull with 32-bit devstudio release, compare and update with q_test-ok.txt" log_step $LINENO " make testall 2>&1 | tee eg/q_test.x" log_step $LINENO "Test CMake build" log_step $LINENO " cd $TEMP_DIR/tgz/qhull*/build" log_step $LINENO " cmake -G \"MSYS Makefiles\" .. && cmake .." log_step $LINENO " make" log_step $LINENO " mkdir -p ../bin/ && cp -p lib*.dll *.exe ../bin/" log_step $LINENO " cd ..; make test" log_step $LINENO "Test Linux compile" log_step $LINENO " cd .. && scp $qhull_tgz_file qhull@qhull.org:" log_step $LINENO " rm -rf qhull-$version; tar zxf $qhull_tgz_file && cd qhull-$version && make >../make.x 2>&1" log_step $LINENO " more ../make.x" log_step $LINENO " export DESTDIR=.; make install; cd usr/local/lib" log_step $LINENO " make test" log_step $LINENO " eg/q_test >eg/q_test.x 2>&1" log_step $LINENO "Update 'Qhull wiki.md', qhull-news.htm (#problems, #bugs), qh-code.htm#enhance" log_step $LINENO "Test qhull and compare to q_test-ok.txt" log_step $LINENO " cd $TEMP_DIR/zip/qhull* && make testall >/d/bash/local/qhull/eg/q_test.x 2>&1" log_step $LINENO "Build and test 64-bit qhulltest. Compare to eg/qhulltest-ok.txt" log_step $LINENO " cd /d/bash/local/qhull && bin/qhulltest --all >eg/qhulltest.x 2>&1" log_step $LINENO "Compare source directories: Copy 'qhull/' to 'downloads/qhull-YYYY/'" log_step $LINENO " If comparing 2020 to 2019 -- find qhull-2020 -type f ! -path "./.git*" ! -path "*working*" | xargs sed -i 's/2020/2019/g'" log_step $LINENO "Benchmark qhull. Compare to eg/q_benchmark-ok.txt" log_step $LINENO " cd $TEMP_DIR/zip/qhull* && make benchmark >/d/bash/local/qhull/eg/q_benchmark.x 2>&1" log_step $LINENO "Build qhull with gcc" log_step $LINENO " cd $TEMP_DIR/zip/qhull* && make SO=dll" log_step $LINENO " cp -p lib/libqhull*.dll bin && make testall >/d/bash/local/qhull/eg/q_test-make.x 2>&1" log_step $LINENO "Create qhull_qh and compare with libqhull, qconvex, etc. See qh_code.htm#convert" log_step $LINENO " eg/make-qhull_qh.sh libqhull_r" log_step $LINENO " Ignore 'Id: //.*' and 'DateTime: 20.*' Edit>FullRefresh" log_step $LINENO " Compare qhull*exports.def and add new functions" log_step $LINENO "Build and test libqhull. user_eg3 not built" log_step $LINENO " make cleanall && cd src/libqhull && make cleanall && make && cp *.exe ../../bin && cd ../.. && make test && ls -l bin/qhull.exe" log_step $LINENO " make testall >/d/bash/local/qhull/eg/q_test-libqhull.x 2>&1" log_step $LINENO "Build and test libqhull with qh_QHpointer" log_step $LINENO " e src/libqhull/user.h" log_step $LINENO " make cleanall && cd src/libqhull && make cleanall && make && cp *.exe ../../bin && cd ../.. && make test && ls -l bin/qhull.exe" log_step $LINENO " bin/rbox c | bin/qhull FO Tz | grep QHpointer" log_step $LINENO " make testall 2>&1 | tee eg/q_test-qh_QHpointer.x" log_step $LINENO "Build and test libqhull_r. user_eg3 not built" log_step $LINENO " make cleanall && cd src/libqhull_r && make cleanall && make && cp *.exe ../../bin && cd ../.. && make test && ls -l bin/qhull.exe" log_step $LINENO " make testall >/d/bash/local/qhull/eg/q_test-libqhull_r.x 2>&1" log_step $LINENO "Build and test libqhull_r with qh_NOmem" log_step $LINENO "Build and test libqhull_r with qh_NOmerge" log_step $LINENO "Build and test libqhull_r with qh_NOtrace" log_step $LINENO "Build and test libqhull_r with qh_KEEPstatistics 0" log_step $LINENO "Build and check Makefile/qhullx. user_eg* not built" log_step $LINENO " make cleanall && make qhullx && make test && ls -l bin/qhull.exe" log_step $LINENO "Benchmark libqhull_r with gcc" log_step $LINENO " make benchmark >/d/bash/local/qhull/eg/q_benchmark-libqhull_r.x 2>&1" log_step $LINENO "Check Qhull-go (double-click)" log_step $LINENO "Compare Changes.txt with previous release" log_step $LINENO "Compare README.txt with previous release" log_step $LINENO "Compare previous zip release, Dates.txt, and md5sum" log_step $LINENO "Compare zip and tgz for CRLF vs LF" log_step $LINENO " C:/Git$TEMP_DIR/" log_step $LINENO "Compare qh_prompt* for unix_r.c,qconvex.c,etc." log_step $LINENO "Check html links with Firefox Link Analyzer (fast but doesn't check #..." log_step $LINENO " Replace old links with web.archive.org (archive.is)" log_step $LINENO "Check all files for FIXUP comments, including Makefile, html, etc." log_step $LINENO "Extract zip to download/ and compare directories" log_step $LINENO "Retest 32-bit release builds and 64-bit qhulltest" log_step $LINENO "Check for 32-bit release executables from DevStudio (<500K and 'Ts' 32-bit allocations)" log_step $LINENO "Check for virus with Windows Defender" log_step $LINENO "Check object dependencies with 'objdump -p user_eg.exe'" log_step $LINENO "Copy tarballs to qhull.org" log_step $LINENO " cd .. && ls -l qhull-2020.2* qhull*8.0.2*" log_step $LINENO " scp -p qhull-2020.2* qhull*8.0.2* qhull@qhull.org:web/download/" log_step $LINENO "Add md5sums to end of qh-get.htm" log_step $LINENO "Add release labels to git" log_step $LINENO "Finished successfully" ############################# qhull-2020.2/eg/qhulltest-ok.txt0000644060175106010010000013117013706715524014773 0ustar bbarber********* Start testing of orgQhull::PointCoordinates_test ********* Config: Using QtTest library 5.11.2, Qt 5.11.2 (x86_64-little_endian-llp64 shared (dynamic) release build; by MSVC 2017) PASS : orgQhull::PointCoordinates_test::initTestCase() PASS : orgQhull::PointCoordinates_test::t_construct_q() PASS : orgQhull::PointCoordinates_test::t_construct_qh() PASS : orgQhull::PointCoordinates_test::t_convert() INFO : Caught QH10063 Qhull error: can not change PointCoordinates dimension (from 3 to 2) PASS : orgQhull::PointCoordinates_test::t_getset() PASS : orgQhull::PointCoordinates_test::t_element() PASS : orgQhull::PointCoordinates_test::t_foreach() PASS : orgQhull::PointCoordinates_test::t_search() PASS : orgQhull::PointCoordinates_test::t_modify() PASS : orgQhull::PointCoordinates_test::t_append_points() PointCoordinates 0-d 0 0 PointCoordinates 1,2 3,1 2,3 2 3 1 2 3 1 2 3 PASS : orgQhull::PointCoordinates_test::t_io() PASS : orgQhull::PointCoordinates_test::cleanupTestCase() Totals: 12 passed, 0 failed, 0 skipped, 0 blacklisted, 2ms ********* Finished testing of orgQhull::PointCoordinates_test ********* ********* Start testing of orgQhull::Qhull_test ********* Config: Using QtTest library 5.11.2, Qt 5.11.2 (x86_64-little_endian-llp64 shared (dynamic) release build; by MSVC 2017) PASS : orgQhull::Qhull_test::initTestCase() INFO : Caught QH10023 Qhull error: checkIfQhullInitialized failed. Call runQhull() first. area delta 0. qFuzzyCompare delta 3.41421e-12 PASS : orgQhull::Qhull_test::t_construct() Expecting summary of halfspace intersection Halfspace intersection by the convex hull of 4 points in 2-d: Number of halfspaces: 4 Number of non-redundant halfspaces: 4 Number of intersection points: 4 Statistics for: normals of square | qhull H Number of points processed: 4 Number of hyperplanes created: 5 Number of distance tests for qhull: 3 CPU seconds to compute hull (after input): 0 Expecting no output from qh_fprintf() in Qhull.cpp Expecting output from ~Qhull Qhull messages at ~Qhull() Halfspace intersection by the convex hull of 4 points in 2-d: Number of halfspaces: 4 Number of non-redundant halfspaces: 4 Number of intersection points: 4 Statistics for: normals of square | qhull H Number of points processed: 4 Number of hyperplanes created: 5 Number of distance tests for qhull: 3 CPU seconds to compute hull (after input): 0 PASS : orgQhull::Qhull_test::t_attribute() INFO : Caught QH6029 qhull option error: option 'Fd' is not used with this program. It may be used with qhull. While executing: | Options selected for Qhull 2020.2.r 2020/07/24: run-id 225630356 _maxoutside 0 INFO : Error stream without output stream QH6029 qhull option error: option 'Fd' is not used with this program. It may be used with qhull. While executing: | Options selected for Qhull 2020.2.r 2020/07/24: run-id 225630356 _maxoutside 0 INFO : Caught QH6029INFO : Error output sent to output stream without error stream QH6023 qhull input error: feasible point is not clearly inside halfspace feasible point: 0 0 halfspace: -0.5 -0.5 at offset: 0.5 and distance: 0.5 The halfspace was at index 1 While executing: rbox "c" | qhull Tz H0 Options selected for Qhull 2020.2.r 2020/07/24: run-id 225630356 Tz-stdout Halfspace-about 0 _maxoutside 0 INFO : Caught QH6023INFO : No error stream or output stream INFO : Caught QH6029 qhull option error: option 'Fd' is not used with this program. It may be used with qhull. While executing: | Options selected for Qhull 2020.2.r 2020/07/24: run-id 225630356 _maxoutside 0 PASS : orgQhull::Qhull_test::t_message() Convex hull of 8 points in 3-d: Number of vertices: 8 Number of facets: 6 Number of non-simplicial facets: 6 Statistics for: rbox "c" | qhull s Number of points processed: 8 Number of hyperplanes created: 11 Number of distance tests for qhull: 34 Number of distance tests for merging: 90 Number of distance tests for checking: 48 Number of merged facets: 6 CPU seconds to compute hull (after input): 0 Convex hull of 8 points in 3-d: Number of vertices: 8 Number of facets: 6 Number of non-simplicial facets: 6 Statistics for: rbox "c" | qhull Number of points processed: 8 Number of hyperplanes created: 11 Number of distance tests for qhull: 34 Number of distance tests for merging: 90 Number of distance tests for checking: 48 Number of merged facets: 6 CPU seconds to compute hull (after input): 0 PASS : orgQhull::Qhull_test::t_getSet() PASS : orgQhull::Qhull_test::t_getQh() PASS : orgQhull::Qhull_test::t_getValue() PASS : orgQhull::Qhull_test::t_foreach() Expecting vertexList and facetList of a 3-d diamond. 3 6 8 12 0 0 -0.5 0 0 0.5 0 -0.5 0 0 0.5 0 -0.5 0 0 0.5 0 0 3 2 0 4 3 0 2 5 3 1 2 4 3 2 1 5 3 3 0 5 3 0 3 4 3 1 3 5 3 3 1 4 Expecting the same output using std::vector and Qhull classes 3 6 8 12 0 0 -0.5 0 0 0.5 0 -0.5 0 0 0.5 0 -0.5 0 0 0.5 0 0 3 2 0 4 3 0 2 5 3 1 2 4 3 2 1 5 3 3 0 5 3 0 3 4 3 1 3 5 3 3 1 4 Expecting normals of a 3-d diamond. 4 8 -0.5773502691896258 -0.5773502691896258 -0.5773502691896258 -0.2886751345948129 0.5773502691896258 -0.5773502691896258 -0.5773502691896258 -0.2886751345948129 -0.5773502691896258 -0.5773502691896258 0.5773502691896258 -0.2886751345948129 0.5773502691896258 -0.5773502691896258 0.5773502691896258 -0.2886751345948129 0.5773502691896258 0.5773502691896258 -0.5773502691896258 -0.2886751345948129 -0.5773502691896258 0.5773502691896258 -0.5773502691896258 -0.2886751345948129 0.5773502691896258 0.5773502691896258 0.5773502691896258 -0.2886751345948129 -0.5773502691896258 0.5773502691896258 0.5773502691896258 -0.2886751345948129 PASS : orgQhull::Qhull_test::t_diamond() PASS : orgQhull::Qhull_test::cleanupTestCase() Totals: 10 passed, 0 failed, 0 skipped, 0 blacklisted, 6ms ********* Finished testing of orgQhull::Qhull_test ********* ********* Start testing of orgQhull::Coordinates_test ********* Config: Using QtTest library 5.11.2, Qt 5.11.2 (x86_64-little_endian-llp64 shared (dynamic) release build; by MSVC 2017) PASS : orgQhull::Coordinates_test::initTestCase() PASS : orgQhull::Coordinates_test::t_construct() PASS : orgQhull::Coordinates_test::t_convert() PASS : orgQhull::Coordinates_test::t_element() PASS : orgQhull::Coordinates_test::t_readonly() PASS : orgQhull::Coordinates_test::t_operator() PASS : orgQhull::Coordinates_test::t_const_iterator() PASS : orgQhull::Coordinates_test::t_iterator() PASS : orgQhull::Coordinates_test::t_foreach() PASS : orgQhull::Coordinates_test::t_search() PASS : orgQhull::Coordinates_test::t_readwrite() Coordinates 1-2-3 1 2 3 PASS : orgQhull::Coordinates_test::t_io() PASS : orgQhull::Coordinates_test::cleanupTestCase() Totals: 13 passed, 0 failed, 0 skipped, 0 blacklisted, 1ms ********* Finished testing of orgQhull::Coordinates_test ********* ********* Start testing of orgQhull::PointCoordinates_test ********* Config: Using QtTest library 5.11.2, Qt 5.11.2 (x86_64-little_endian-llp64 shared (dynamic) release build; by MSVC 2017) PASS : orgQhull::PointCoordinates_test::initTestCase() PASS : orgQhull::PointCoordinates_test::t_construct_q() PASS : orgQhull::PointCoordinates_test::t_construct_qh() PASS : orgQhull::PointCoordinates_test::t_convert() INFO : Caught QH10063 Qhull error: can not change PointCoordinates dimension (from 3 to 2) PASS : orgQhull::PointCoordinates_test::t_getset() PASS : orgQhull::PointCoordinates_test::t_element() PASS : orgQhull::PointCoordinates_test::t_foreach() PASS : orgQhull::PointCoordinates_test::t_search() PASS : orgQhull::PointCoordinates_test::t_modify() PASS : orgQhull::PointCoordinates_test::t_append_points() PointCoordinates 0-d 0 0 PointCoordinates 1,2 3,1 2,3 2 3 1 2 3 1 2 3 PASS : orgQhull::PointCoordinates_test::t_io() PASS : orgQhull::PointCoordinates_test::cleanupTestCase() Totals: 12 passed, 0 failed, 0 skipped, 0 blacklisted, 1ms ********* Finished testing of orgQhull::PointCoordinates_test ********* ********* Start testing of orgQhull::QhullFacet_test ********* Config: Using QtTest library 5.11.2, Qt 5.11.2 (x86_64-little_endian-llp64 shared (dynamic) release build; by MSVC 2017) PASS : orgQhull::QhullFacet_test::initTestCase() PASS : orgQhull::QhullFacet_test::t_construct_qh() PASS : orgQhull::QhullFacet_test::t_constructConvert() rbox c | qhull Qt QR0 QR1595644756 distanceEpsilon 1.19523e-15 18 19 22 24 26 27 30 31 34 35 38 39 39 38 35 34 31 30 27 26 24 22 19 18 InnerPlane: 0.554312 -0.805806 -0.208361 -0.5 innerOffset+0.5 1.22125e-15 Hyperplane: 0.554312 -0.805806 -0.208361 -0.5 offset+0.5 -1.11022e-16 OuterPlane: 0.554312 -0.805806 -0.208361 -0.5 outerOffset+0.5 -2.55351e-15 Center: 0.277156 -0.402903 -0.104181 InnerPlane: 0.554312 -0.805806 -0.208361 -0.5 innerOffset+0.5 1.22125e-15 Hyperplane: 0.554312 -0.805806 -0.208361 -0.5 offset+0.5 -1.11022e-16 OuterPlane: 0.554312 -0.805806 -0.208361 -0.5 outerOffset+0.5 -2.55351e-15 Center: 0.277156 -0.402903 -0.104181 InnerPlane: -0.51438 -0.528475 0.675372 -0.5 innerOffset+0.5 1.38778e-15 Hyperplane: -0.51438 -0.528475 0.675372 -0.5 offset+0.5 1.66533e-16 OuterPlane: -0.51438 -0.528475 0.675372 -0.5 outerOffset+0.5 -2.22045e-15 Center: -0.25719 -0.264237 0.337686 InnerPlane: -0.51438 -0.528475 0.675372 -0.5 innerOffset+0.5 1.38778e-15 Hyperplane: -0.51438 -0.528475 0.675372 -0.5 offset+0.5 1.66533e-16 OuterPlane: -0.51438 -0.528475 0.675372 -0.5 outerOffset+0.5 -2.22045e-15 Center: -0.25719 -0.264237 0.337686 InnerPlane: 0.654333 0.26719 0.70743 -0.5 innerOffset+0.5 1.11022e-15 Hyperplane: 0.654333 0.26719 0.70743 -0.5 offset+0.5 -1.11022e-16 OuterPlane: 0.654333 0.26719 0.70743 -0.5 outerOffset+0.5 -2.55351e-15 Center: 0.327167 0.133595 0.353715 InnerPlane: 0.654333 0.26719 0.70743 -0.5 innerOffset+0.5 1.11022e-15 Hyperplane: 0.654333 0.26719 0.70743 -0.5 offset+0.5 -1.11022e-16 OuterPlane: 0.654333 0.26719 0.70743 -0.5 outerOffset+0.5 -2.55351e-15 Center: 0.327167 0.133595 0.353715 InnerPlane: -0.654333 -0.26719 -0.70743 -0.5 innerOffset+0.5 1.16573e-15 Hyperplane: -0.654333 -0.26719 -0.70743 -0.5 offset+0.5 -2.22045e-16 OuterPlane: -0.654333 -0.26719 -0.70743 -0.5 outerOffset+0.5 -2.66454e-15 Center: -0.327167 -0.133595 -0.353715 InnerPlane: -0.654333 -0.26719 -0.70743 -0.5 innerOffset+0.5 1.16573e-15 Hyperplane: -0.654333 -0.26719 -0.70743 -0.5 offset+0.5 -2.22045e-16 OuterPlane: -0.654333 -0.26719 -0.70743 -0.5 outerOffset+0.5 -2.66454e-15 Center: -0.327167 -0.133595 -0.353715 InnerPlane: -0.554312 0.805806 0.208361 -0.5 innerOffset+0.5 1.16573e-15 Hyperplane: -0.554312 0.805806 0.208361 -0.5 offset+0.5 -2.22045e-16 OuterPlane: -0.554312 0.805806 0.208361 -0.5 outerOffset+0.5 -2.66454e-15 Center: -0.277156 0.402903 0.104181 InnerPlane: -0.554312 0.805806 0.208361 -0.5 innerOffset+0.5 1.16573e-15 Hyperplane: -0.554312 0.805806 0.208361 -0.5 offset+0.5 -2.22045e-16 OuterPlane: -0.554312 0.805806 0.208361 -0.5 outerOffset+0.5 -2.66454e-15 Center: -0.277156 0.402903 0.104181 InnerPlane: 0.51438 0.528475 -0.675372 -0.5 innerOffset+0.5 1.33227e-15 Hyperplane: 0.51438 0.528475 -0.675372 -0.5 offset+0.5 1.11022e-16 OuterPlane: 0.51438 0.528475 -0.675372 -0.5 outerOffset+0.5 -2.33147e-15 Center: 0.25719 0.264237 -0.337686 InnerPlane: 0.51438 0.528475 -0.675372 -0.5 innerOffset+0.5 1.33227e-15 Hyperplane: 0.51438 0.528475 -0.675372 -0.5 offset+0.5 1.11022e-16 OuterPlane: 0.51438 0.528475 -0.675372 -0.5 outerOffset+0.5 -2.33147e-15 Center: 0.25719 0.264237 -0.337686 rbox c | qhull d Qz Qt QR0 QR1595644756 distanceEpsilon 1.73695e-15 rbox c | qhull v Qz QR0 QR1595644756 distanceEpsilon 1.73695e-15 Voronoi vertex: -1.11022e-16 -2.77556e-17 6.93889e-18 Is it within 400 * distanceEpsilon (6.9478e-13) of the origin? PASS : orgQhull::QhullFacet_test::t_getSet() Points and facets. Facet vertices in counter-clockwise order (option 'o') 2 4 4 4 -0.5 -0.5 -0.5 0.5 0.5 -0.5 0.5 0.5 2 0 2 2 1 0 2 2 3 2 3 1 Facets and vertices in counter-clockwise order (f.nextFacet2d) f4 v1 p0 f5 v2 p2 f2 v4 p3 f1 v3 p1 Extreme points in counter-clockwise order (option 'Fx') 4 0 2 3 1 PASS : orgQhull::QhullFacet_test::t_getSet2d() PASS : orgQhull::QhullFacet_test::t_value() PASS : orgQhull::QhullFacet_test::t_foreach() - f1 - flags: bottom tested - merges: 1 - normal: -0 -0 -1 - offset: -0.5 - center: 0 0 -0.5 - vertices: p6(v6) p2(v3) p4(v2) p0(v1) - neighboring facets: f2 f3 f10 f9 - ridges: - r4 tested simplicialtop simplicialbot vertices: p2(v3) p0(v1) between f1 and f3 - r3 tested simplicialtop simplicialbot vertices: p4(v2) p0(v1) between f2 and f1 - r1 tested simplicialtop vertices: p6(v6) p4(v2) between f9 and f1 - r2 tested simplicialbot vertices: p6(v6) p2(v3) between f1 and f10 With a message - f1 - flags: bottom tested - merges: 1 - normal: -0 -0 -1 - offset: -0.5 - center: 0 0 -0.5 - vertices: p6(v6) p2(v3) p4(v2) p0(v1) - neighboring facets: f2 f3 f10 f9 - ridges: - r4 tested simplicialtop simplicialbot vertices: p2(v3) p0(v1) between f1 and f3 - r3 tested simplicialtop simplicialbot vertices: p4(v2) p0(v1) between f2 and f1 - r1 tested simplicialtop vertices: p6(v6) p4(v2) between f9 and f1 - r2 tested simplicialbot vertices: p6(v6) p2(v3) between f1 and f10 Print header for the same facet - f1 - flags: bottom tested - merges: 1 - normal: -0 -0 -1 - offset: -0.5 - center: 0 0 -0.5 - vertices: p6(v6) p2(v3) p4(v2) p0(v1) - neighboring facets: f2 f3 f10 f9 Print each component - flags: bottom tested - center: 0 0 -0.5 - ridges: - r4 tested simplicialtop simplicialbot vertices: p2(v3) p0(v1) between f1 and f3 - r3 tested simplicialtop simplicialbot vertices: p4(v2) p0(v1) between f2 and f1 - r1 tested simplicialtop vertices: p6(v6) p4(v2) between f9 and f1 - r2 tested simplicialbot vertices: p6(v6) p2(v3) between f1 and f10 PASS : orgQhull::QhullFacet_test::t_io() PASS : orgQhull::QhullFacet_test::cleanupTestCase() Totals: 9 passed, 0 failed, 0 skipped, 0 blacklisted, 3ms ********* Finished testing of orgQhull::QhullFacet_test ********* ********* Start testing of orgQhull::QhullFacetList_test ********* Config: Using QtTest library 5.11.2, Qt 5.11.2 (x86_64-little_endian-llp64 shared (dynamic) release build; by MSVC 2017) PASS : orgQhull::QhullFacetList_test::initTestCase() PASS : orgQhull::QhullFacetList_test::t_construct_qh() PASS : orgQhull::QhullFacetList_test::t_construct_q() PASS : orgQhull::QhullFacetList_test::t_convert() PASS : orgQhull::QhullFacetList_test::t_readonly() PASS : orgQhull::QhullFacetList_test::t_foreach() PASS : orgQhull::QhullFacetList_test::t_java_iterator() Show all of FacetList Vertices for 3 facets - p1 (v6): 0.347133 -0.533546 0.587221 neighborFacets: f8 f4 f6 - p2 (v4): 0.207179 -0.272261 -0.795582 neighborFacets: f4 f3 f11 - p0 (v3): -0.307201 -0.800736 -0.12021 neighborFacets: f3 f4 f6 - p3 (v2): 0.861512 -0.00507083 -0.0881516 neighborFacets: f8 f4 f11 - p5 (v5): -0.207179 0.272261 0.795582 neighborFacets: f8 f6 f14 - p4 (v1): -0.861512 0.00507083 0.0881516 neighborFacets: f6 f3 f14 - p6 (v8): -0.347133 0.533546 -0.587221 neighborFacets: f3 f14 f11 - f4 - flags: top tested - merges: 1 - normal: 0.554312 -0.805806 -0.208361 - offset: -0.5 - center: 0.277156 -0.402903 -0.104181 - vertices: p1(v6) p2(v4) p0(v3) p3(v2) - neighboring facets: f3 f11 f6 f8 - ridges: - r4 tested simplicialtop simplicialbot vertices: p2(v4) p3(v2) between f11 and f4 - r8 tested simplicialtop simplicialbot vertices: p2(v4) p0(v3) between f4 and f3 - r7 tested vertices: p1(v6) p0(v3) between f6 and f4 - r6 tested simplicialbot vertices: p1(v6) p3(v2) between f4 and f8 - f6 - flags: top tested - merges: 1 - normal: -0.51438 -0.528475 0.675372 - offset: -0.5 - center: -0.25719 -0.264237 0.337686 - vertices: p1(v6) p5(v5) p0(v3) p4(v1) - neighboring facets: f3 f14 f4 f8 - ridges: - r1 tested simplicialtop simplicialbot vertices: p5(v5) p4(v1) between f14 and f6 - r10 tested simplicialtop vertices: p1(v6) p5(v5) between f8 and f6 - r7 tested vertices: p1(v6) p0(v3) between f6 and f4 - r11 tested simplicialtop simplicialbot vertices: p0(v3) p4(v1) between f6 and f3 - f3 - flags: bottom tested - merges: 1 - normal: -0.654333 -0.26719 -0.70743 - offset: -0.5 - center: -0.327167 -0.133595 -0.353715 - vertices: p6(v8) p2(v4) p0(v3) p4(v1) - neighboring facets: f6 f4 f11 f14 - ridges: - r11 tested simplicialtop simplicialbot vertices: p0(v3) p4(v1) between f6 and f3 - r8 tested simplicialtop simplicialbot vertices: p2(v4) p0(v3) between f4 and f3 - r17 tested vertices: p6(v8) p2(v4) between f11 and f3 - r16 tested vertices: p6(v8) p4(v1) between f3 and f14 Facets only - f4 - flags: top tested - merges: 1 - normal: 0.554312 -0.805806 -0.208361 - offset: -0.5 - center: 0.277156 -0.402903 -0.104181 - vertices: p1(v6) p2(v4) p0(v3) p3(v2) - neighboring facets: f3 f11 f6 f8 - ridges: - r4 tested simplicialtop simplicialbot vertices: p2(v4) p3(v2) between f11 and f4 - r8 tested simplicialtop simplicialbot vertices: p2(v4) p0(v3) between f4 and f3 - r7 tested vertices: p1(v6) p0(v3) between f6 and f4 - r6 tested simplicialbot vertices: p1(v6) p3(v2) between f4 and f8 - f6 - flags: top tested - merges: 1 - normal: -0.51438 -0.528475 0.675372 - offset: -0.5 - center: -0.25719 -0.264237 0.337686 - vertices: p1(v6) p5(v5) p0(v3) p4(v1) - neighboring facets: f3 f14 f4 f8 - ridges: - r1 tested simplicialtop simplicialbot vertices: p5(v5) p4(v1) between f14 and f6 - r10 tested simplicialtop vertices: p1(v6) p5(v5) between f8 and f6 - r7 tested vertices: p1(v6) p0(v3) between f6 and f4 - r11 tested simplicialtop simplicialbot vertices: p0(v3) p4(v1) between f6 and f3 - f3 - flags: bottom tested - merges: 1 - normal: -0.654333 -0.26719 -0.70743 - offset: -0.5 - center: -0.327167 -0.133595 -0.353715 - vertices: p6(v8) p2(v4) p0(v3) p4(v1) - neighboring facets: f6 f4 f11 f14 - ridges: - r11 tested simplicialtop simplicialbot vertices: p0(v3) p4(v1) between f6 and f3 - r8 tested simplicialtop simplicialbot vertices: p2(v4) p0(v3) between f4 and f3 - r17 tested vertices: p6(v8) p2(v4) between f11 and f3 - r16 tested vertices: p6(v8) p4(v1) between f3 and f14 Vertices only - p1 (v6): 0.347133 -0.533546 0.587221 neighborFacets: f8 f4 f6 - p2 (v4): 0.207179 -0.272261 -0.795582 neighborFacets: f4 f3 f11 - p0 (v3): -0.307201 -0.800736 -0.12021 neighborFacets: f3 f4 f6 - p3 (v2): 0.861512 -0.00507083 -0.0881516 neighborFacets: f8 f4 f11 - p5 (v5): -0.207179 0.272261 0.795582 neighborFacets: f8 f6 f14 - p4 (v1): -0.861512 0.00507083 0.0881516 neighborFacets: f6 f3 f14 - p6 (v8): -0.347133 0.533546 -0.587221 neighborFacets: f3 f14 f11 PASS : orgQhull::QhullFacetList_test::t_io() PASS : orgQhull::QhullFacetList_test::cleanupTestCase() Totals: 9 passed, 0 failed, 0 skipped, 0 blacklisted, 1ms ********* Finished testing of orgQhull::QhullFacetList_test ********* ********* Start testing of orgQhull::QhullFacetSet_test ********* Config: Using QtTest library 5.11.2, Qt 5.11.2 (x86_64-little_endian-llp64 shared (dynamic) release build; by MSVC 2017) PASS : orgQhull::QhullFacetSet_test::initTestCase() PASS : orgQhull::QhullFacetSet_test::t_construct() PASS : orgQhull::QhullFacetSet_test::t_convert() PASS : orgQhull::QhullFacetSet_test::t_readonly() PASS : orgQhull::QhullFacetSet_test::t_foreach() PASS : orgQhull::QhullFacetSet_test::t_java_iterator() Neighbors of first facet with point 0- f3 - flags: bottom tested - merges: 1 - normal: -0.654333 -0.26719 -0.70743 - offset: -0.5 - center: -0.327167 -0.133595 -0.353715 - vertices: p6(v8) p2(v4) p0(v3) p4(v1) - neighboring facets: f6 f4 f11 f14 - ridges: - r11 tested simplicialtop simplicialbot vertices: p0(v3) p4(v1) between f6 and f3 - r8 tested simplicialtop simplicialbot vertices: p2(v4) p0(v3) between f4 and f3 - r17 tested vertices: p6(v8) p2(v4) between f11 and f3 - r16 tested vertices: p6(v8) p4(v1) between f3 and f14 - f6 - flags: top tested - merges: 1 - normal: -0.51438 -0.528475 0.675372 - offset: -0.5 - center: -0.25719 -0.264237 0.337686 - vertices: p1(v6) p5(v5) p0(v3) p4(v1) - neighboring facets: f3 f14 f4 f8 - ridges: - r1 tested simplicialtop simplicialbot vertices: p5(v5) p4(v1) between f14 and f6 - r10 tested simplicialtop vertices: p1(v6) p5(v5) between f8 and f6 - r7 tested vertices: p1(v6) p0(v3) between f6 and f4 - r11 tested simplicialtop simplicialbot vertices: p0(v3) p4(v1) between f6 and f3 Facet identifiers: f3 f6 PASS : orgQhull::QhullFacetSet_test::t_io() PASS : orgQhull::QhullFacetSet_test::cleanupTestCase() Totals: 8 passed, 0 failed, 0 skipped, 0 blacklisted, 1ms ********* Finished testing of orgQhull::QhullFacetSet_test ********* ********* Start testing of orgQhull::QhullHyperplane_test ********* Config: Using QtTest library 5.11.2, Qt 5.11.2 (x86_64-little_endian-llp64 shared (dynamic) release build; by MSVC 2017) PASS : orgQhull::QhullHyperplane_test::initTestCase() PASS : orgQhull::QhullHyperplane_test::t_construct() PASS : orgQhull::QhullHyperplane_test::t_construct_qh() PASS : orgQhull::QhullHyperplane_test::t_convert() h18 h19 h22 h24 h26 h27 h30 h31 h34 h35 h38 h39 PASS : orgQhull::QhullHyperplane_test::t_readonly() PASS : orgQhull::QhullHyperplane_test::t_define() angle -5.55112e-17 PASS : orgQhull::QhullHyperplane_test::t_value() PASS : orgQhull::QhullHyperplane_test::t_operator() PASS : orgQhull::QhullHyperplane_test::t_iterator() PASS : orgQhull::QhullHyperplane_test::t_const_iterator() PASS : orgQhull::QhullHyperplane_test::t_foreach() PASS : orgQhull::QhullHyperplane_test::t_qhullHyperplane_iterator() PASS : orgQhull::QhullHyperplane_test::t_java_iterator() Hyperplane: -0 -0 -1 -0.5 message -0 -0 -1 -0.5 and a message -0 -0 -1 offset -0.5 PASS : orgQhull::QhullHyperplane_test::t_io() PASS : orgQhull::QhullHyperplane_test::cleanupTestCase() Totals: 15 passed, 0 failed, 0 skipped, 0 blacklisted, 1ms ********* Finished testing of orgQhull::QhullHyperplane_test ********* ********* Start testing of orgQhull::QhullLinkedList_test ********* Config: Using QtTest library 5.11.2, Qt 5.11.2 (x86_64-little_endian-llp64 shared (dynamic) release build; by MSVC 2017) PASS : orgQhull::QhullLinkedList_test::initTestCase() PASS : orgQhull::QhullLinkedList_test::t_construct() PASS : orgQhull::QhullLinkedList_test::t_convert() PASS : orgQhull::QhullLinkedList_test::t_element() PASS : orgQhull::QhullLinkedList_test::t_search() PASS : orgQhull::QhullLinkedList_test::t_iterator() PASS : orgQhull::QhullLinkedList_test::t_const_iterator() PASS : orgQhull::QhullLinkedList_test::t_foreach() PASS : orgQhull::QhullLinkedList_test::t_QhullLinkedList_iterator() PASS : orgQhull::QhullLinkedList_test::t_java_iterator() INFO: empty QhullVertextList INFO: - p1 (v6): 0.347133 -0.533546 0.587221 neighborFacets: f8 f4 f6 - p6 (v8): -0.347133 0.533546 -0.587221 neighborFacets: f3 f14 f11 - p2 (v4): 0.207179 -0.272261 -0.795582 neighborFacets: f4 f3 f11 - p4 (v1): -0.861512 0.00507083 0.0881516 neighborFacets: f6 f3 f14 - p7 (v7): 0.307201 0.800736 0.12021 neighborFacets: f11 f14 f8 - p0 (v3): -0.307201 -0.800736 -0.12021 neighborFacets: f3 f4 f6 - p5 (v5): -0.207179 0.272261 0.795582 neighborFacets: f8 f6 f14 - p3 (v2): 0.861512 -0.00507083 -0.0881516 neighborFacets: f8 f4 f11 PASS : orgQhull::QhullLinkedList_test::t_io() PASS : orgQhull::QhullLinkedList_test::cleanupTestCase() Totals: 12 passed, 0 failed, 0 skipped, 0 blacklisted, 3ms ********* Finished testing of orgQhull::QhullLinkedList_test ********* ********* Start testing of orgQhull::QhullPoint_test ********* Config: Using QtTest library 5.11.2, Qt 5.11.2 (x86_64-little_endian-llp64 shared (dynamic) release build; by MSVC 2017) PASS : orgQhull::QhullPoint_test::initTestCase() PASS : orgQhull::QhullPoint_test::t_construct() PASS : orgQhull::QhullPoint_test::t_convert() Point ids in 'rbox c' p1 p2 p3 p0 p5 p4 p7 p6 PASS : orgQhull::QhullPoint_test::t_readonly() PASS : orgQhull::QhullPoint_test::t_define() PASS : orgQhull::QhullPoint_test::t_operator() PASS : orgQhull::QhullPoint_test::t_iterator() PASS : orgQhull::QhullPoint_test::t_const_iterator() PASS : orgQhull::QhullPoint_test::t_foreach() PASS : orgQhull::QhullPoint_test::t_qhullpoint_iterator() PASS : orgQhull::QhullPoint_test::t_java_iterator() PASS : orgQhull::QhullPoint_test::t_method() Point: 0.5 -0.5 -0.5 Point w/ print: message 0.5 -0.5 -0.5 Point with id and a message p4: 0.5 -0.5 -0.5 PASS : orgQhull::QhullPoint_test::t_io() PASS : orgQhull::QhullPoint_test::cleanupTestCase() Totals: 14 passed, 0 failed, 0 skipped, 0 blacklisted, 1ms ********* Finished testing of orgQhull::QhullPoint_test ********* ********* Start testing of orgQhull::QhullPoints_test ********* Config: Using QtTest library 5.11.2, Qt 5.11.2 (x86_64-little_endian-llp64 shared (dynamic) release build; by MSVC 2017) PASS : orgQhull::QhullPoints_test::initTestCase() PASS : orgQhull::QhullPoints_test::t_construct_q() PASS : orgQhull::QhullPoints_test::t_construct_qh() PASS : orgQhull::QhullPoints_test::t_convert() PASS : orgQhull::QhullPoints_test::t_getset() PASS : orgQhull::QhullPoints_test::t_element() PASS : orgQhull::QhullPoints_test::t_iterator() PASS : orgQhull::QhullPoints_test::t_const_iterator() PASS : orgQhull::QhullPoints_test::t_foreach() PASS : orgQhull::QhullPoints_test::t_search() PASS : orgQhull::QhullPoints_test::t_points_iterator() PASS : orgQhull::QhullPoints_test::t_java_iterator() Empty QhullPoints QhullPoints from c[] 0 1 2 3 4 5 QhullPoints -0.307201 -0.800736 -0.12021 0.347133 -0.533546 0.587221 0.207179 -0.272261 -0.795582 0.861512 -0.00507083 -0.0881516 -0.861512 0.00507083 0.0881516 -0.207179 0.272261 0.795582 -0.347133 0.533546 -0.587221 0.307201 0.800736 0.12021 message -0.307201 -0.800736 -0.12021 0.347133 -0.533546 0.587221 0.207179 -0.272261 -0.795582 0.861512 -0.00507083 -0.0881516 -0.861512 0.00507083 0.0881516 -0.207179 0.272261 0.795582 -0.347133 0.533546 -0.587221 0.307201 0.800736 0.12021 w/ identifiers p0: -0.307201 -0.800736 -0.12021 p1: 0.347133 -0.533546 0.587221 p2: 0.207179 -0.272261 -0.795582 p3: 0.861512 -0.00507083 -0.0881516 p4: -0.861512 0.00507083 0.0881516 p5: -0.207179 0.272261 0.795582 p6: -0.347133 0.533546 -0.587221 p7: 0.307201 0.800736 0.12021 PASS : orgQhull::QhullPoints_test::t_io() PASS : orgQhull::QhullPoints_test::cleanupTestCase() Totals: 14 passed, 0 failed, 0 skipped, 0 blacklisted, 1ms ********* Finished testing of orgQhull::QhullPoints_test ********* ********* Start testing of orgQhull::QhullPointSet_test ********* Config: Using QtTest library 5.11.2, Qt 5.11.2 (x86_64-little_endian-llp64 shared (dynamic) release build; by MSVC 2017) PASS : orgQhull::QhullPointSet_test::initTestCase() PASS : orgQhull::QhullPointSet_test::t_construct() PASS : orgQhull::QhullPointSet_test::t_convert() PASS : orgQhull::QhullPointSet_test::t_element() PASS : orgQhull::QhullPointSet_test::t_iterator() PASS : orgQhull::QhullPointSet_test::t_const_iterator() PASS : orgQhull::QhullPointSet_test::t_search() PASS : orgQhull::QhullPointSet_test::t_foreach() PASS : orgQhull::QhullPointSet_test::t_pointset_iterator() PASS : orgQhull::QhullPointSet_test::t_java_iterator() QhullPointSet from coplanarPoints 0.368247 0.129543 0.5 0.35127 -0.210684 0.5 0.313266 0.0568358 0.5 0.0344498 -0.00151988 0.5 -0.000258967 -0.352467 0.5 0.44098 -0.449916 0.5 -0.300445 0.416634 0.5 -0.336919 0.403301 0.5 -0.442525 0.486883 0.5 0.100394 0.317561 0.5 0.188981 0.202207 0.5 0.196243 0.25294 0.5 -0.082514 0.186773 0.5 -0.22729 -0.0635886 0.5 -0.148985 0.0132737 0.5 -0.340232 -0.287248 0.5 -0.17844 -0.0395658 0.5 -0.114231 0.126861 0.5 -0.0840006 0.201191 0.5 -0.499992 -0.368462 0.5 0.076173 0.238959 0.5 0.0545838 0.390737 0.5 0.404653 0.00452289 0.5 With message 0.368247 0.129543 0.5 0.35127 -0.210684 0.5 0.313266 0.0568358 0.5 0.0344498 -0.00151988 0.5 -0.000258967 -0.352467 0.5 0.44098 -0.449916 0.5 -0.300445 0.416634 0.5 -0.336919 0.403301 0.5 -0.442525 0.486883 0.5 0.100394 0.317561 0.5 0.188981 0.202207 0.5 0.196243 0.25294 0.5 -0.082514 0.186773 0.5 -0.22729 -0.0635886 0.5 -0.148985 0.0132737 0.5 -0.340232 -0.287248 0.5 -0.17844 -0.0395658 0.5 -0.114231 0.126861 0.5 -0.0840006 0.201191 0.5 -0.499992 -0.368462 0.5 0.076173 0.238959 0.5 0.0545838 0.390737 0.5 0.404653 0.00452289 0.5 Coplanar points: p21 p51 p80 p27 p34 p19 p57 p97 p108 p48 p50 p75 p5 p12 p23 p29 p87 p100 p7 p0 p110 p28 p15 As a point set: 0.368247 0.129543 0.5 0.35127 -0.210684 0.5 0.313266 0.0568358 0.5 0.0344498 -0.00151988 0.5 -0.000258967 -0.352467 0.5 0.44098 -0.449916 0.5 -0.300445 0.416634 0.5 -0.336919 0.403301 0.5 -0.442525 0.486883 0.5 0.100394 0.317561 0.5 0.188981 0.202207 0.5 0.196243 0.25294 0.5 -0.082514 0.186773 0.5 -0.22729 -0.0635886 0.5 -0.148985 0.0132737 0.5 -0.340232 -0.287248 0.5 -0.17844 -0.0395658 0.5 -0.114231 0.126861 0.5 -0.0840006 0.201191 0.5 -0.499992 -0.368462 0.5 0.076173 0.238959 0.5 0.0545838 0.390737 0.5 0.404653 0.00452289 0.5 PASS : orgQhull::QhullPointSet_test::t_io() PASS : orgQhull::QhullPointSet_test::cleanupTestCase() Totals: 12 passed, 0 failed, 0 skipped, 0 blacklisted, 5ms ********* Finished testing of orgQhull::QhullPointSet_test ********* ********* Start testing of orgQhull::QhullRidge_test ********* Config: Using QtTest library 5.11.2, Qt 5.11.2 (x86_64-little_endian-llp64 shared (dynamic) release build; by MSVC 2017) PASS : orgQhull::QhullRidge_test::initTestCase() PASS : orgQhull::QhullRidge_test::t_construct() 4 8 7 6 PASS : orgQhull::QhullRidge_test::t_getSet() PASS : orgQhull::QhullRidge_test::t_foreach() PASS : orgQhull::QhullRidge_test::t_java_iterator() Ridges - r4 tested simplicialtop simplicialbot vertices: p2(v3) p0(v1) between f1 and f3 - r3 tested simplicialtop simplicialbot vertices: p4(v2) p0(v1) between f2 and f1 - r2 tested simplicialbot vertices: p6(v6) p2(v3) between f1 and f10 - r1 tested simplicialtop vertices: p6(v6) p4(v2) between f9 and f1 Ridge - r4 tested simplicialtop simplicialbot vertices: p2(v3) p0(v1) between f1 and f3 Ridge with message r4 tested simplicialtop simplicialbot vertices: p2(v3) p0(v1) between f1 and f3 PASS : orgQhull::QhullRidge_test::t_io() PASS : orgQhull::QhullRidge_test::cleanupTestCase() Totals: 7 passed, 0 failed, 0 skipped, 0 blacklisted, 1ms ********* Finished testing of orgQhull::QhullRidge_test ********* ********* Start testing of orgQhull::QhullSet_test ********* Config: Using QtTest library 5.11.2, Qt 5.11.2 (x86_64-little_endian-llp64 shared (dynamic) release build; by MSVC 2017) PASS : orgQhull::QhullSet_test::initTestCase() PASS : orgQhull::QhullSet_test::t_qhullsetbase() PASS : orgQhull::QhullSet_test::t_convert() PASS : orgQhull::QhullSet_test::t_element() PASS : orgQhull::QhullSet_test::t_search() PASS : orgQhull::QhullSet_test::t_iterator() PASS : orgQhull::QhullSet_test::t_const_iterator() PASS : orgQhull::QhullSet_test::t_qhullset_iterator() PASS : orgQhull::QhullSet_test::t_java_iterator() INFO: empty set INFO: Neighboring facets - f3 - flags: bottom tested - merges: 1 - normal: -0.654333 -0.26719 -0.70743 - offset: -0.5 - center: -0.327167 -0.133595 -0.353715 - vertices: p6(v8) p2(v4) p0(v3) p4(v1) - neighboring facets: f6 f4 f11 f14 - ridges: - r11 tested simplicialtop simplicialbot vertices: p0(v3) p4(v1) between f6 and f3 - r8 tested simplicialtop simplicialbot vertices: p2(v4) p0(v3) between f4 and f3 - r17 tested vertices: p6(v8) p2(v4) between f11 and f3 - r16 tested vertices: p6(v8) p4(v1) between f3 and f14 - f11 - flags: top tested - merges: 1 - normal: 0.51438 0.528475 -0.675372 - offset: -0.5 - center: 0.25719 0.264237 -0.337686 - vertices: p6(v8) p7(v7) p2(v4) p3(v2) - neighboring facets: f4 f8 f14 f3 - ridges: - r4 tested simplicialtop simplicialbot vertices: p2(v4) p3(v2) between f11 and f4 - r13 tested simplicialbot vertices: p7(v7) p3(v2) between f8 and f11 - r19 tested vertices: p6(v8) p7(v7) between f14 and f11 - r17 tested vertices: p6(v8) p2(v4) between f11 and f3 - f6 - flags: top tested - merges: 1 - normal: -0.51438 -0.528475 0.675372 - offset: -0.5 - center: -0.25719 -0.264237 0.337686 - vertices: p1(v6) p5(v5) p0(v3) p4(v1) - neighboring facets: f3 f14 f4 f8 - ridges: - r1 tested simplicialtop simplicialbot vertices: p5(v5) p4(v1) between f14 and f6 - r10 tested simplicialtop vertices: p1(v6) p5(v5) between f8 and f6 - r7 tested vertices: p1(v6) p0(v3) between f6 and f4 - r11 tested simplicialtop simplicialbot vertices: p0(v3) p4(v1) between f6 and f3 - f8 - flags: top tested - merges: 1 - normal: 0.654333 0.26719 0.70743 - offset: -0.5 - center: 0.327167 0.133595 0.353715 - vertices: p7(v7) p1(v6) p5(v5) p3(v2) - neighboring facets: f6 f4 f14 f11 - ridges: - r10 tested simplicialtop vertices: p1(v6) p5(v5) between f8 and f6 - r14 tested simplicialtop vertices: p7(v7) p5(v5) between f14 and f8 - r13 tested simplicialbot vertices: p7(v7) p3(v2) between f8 and f11 - r6 tested simplicialbot vertices: p1(v6) p3(v2) between f4 and f8 INFO: Ridges for a facet - r4 tested simplicialtop simplicialbot vertices: p2(v4) p3(v2) between f11 and f4 - r8 tested simplicialtop simplicialbot vertices: p2(v4) p0(v3) between f4 and f3 - r7 tested vertices: p1(v6) p0(v3) between f6 and f4 - r6 tested simplicialbot vertices: p1(v6) p3(v2) between f4 and f8 PASS : orgQhull::QhullSet_test::t_io() PASS : orgQhull::QhullSet_test::cleanupTestCase() Totals: 11 passed, 0 failed, 0 skipped, 0 blacklisted, 1ms ********* Finished testing of orgQhull::QhullSet_test ********* ********* Start testing of orgQhull::QhullVertex_test ********* Config: Using QtTest library 5.11.2, Qt 5.11.2 (x86_64-little_endian-llp64 shared (dynamic) release build; by MSVC 2017) PASS : orgQhull::QhullVertex_test::initTestCase() PASS : orgQhull::QhullVertex_test::t_constructConvert() 6 4 2 3 5 1 7 8 8 7 1 5 3 2 4 6 Point 1: 0.347133 -0.533546 0.587221 Point 2: 0.207179 -0.272261 -0.795582 Point 3: 0.861512 -0.00507083 -0.0881516 Point 0: -0.307201 -0.800736 -0.12021 Point 5: -0.207179 0.272261 0.795582 Point 4: -0.861512 0.00507083 0.0881516 Point 7: 0.307201 0.800736 0.12021 Point 6: -0.347133 0.533546 -0.587221 PASS : orgQhull::QhullVertex_test::t_getSet() PASS : orgQhull::QhullVertex_test::t_foreach() Vertex and vertices: - p4 (v2): 0.5 -0.5 -0.5 neighborFacets: f1 f2 f9 p6(v6) p2(v3) p4(v2) p0(v1) Vertex and vertices with message: Vertex p4 (v2): 0.5 -0.5 -0.5 neighborFacets: f1 f2 f9 Vertices: p6(v6) p2(v3) p4(v2) p0(v1) Try again with simplicial facets. No neighboring facets listed for vertices. Vertex and vertices: - p0 (v5): -0.0222149 -0.366435 0.327062 This time with neighborFacets() defined for all vertices: - p0 (v5): -0.0222149 -0.366435 0.327062 neighborFacets: f5 f6 f7 f8 Try again with Voronoi diagram of simplicial facets. Neighboring facets automatically defined for vertices. Vertex and vertices: - p7 (v2): 0.386746 0.0449288 0.118336 0.165595 neighborFacets: f1 f6 f9 f13 f14 f15 f16 f18 f19 f21 PASS : orgQhull::QhullVertex_test::t_io() PASS : orgQhull::QhullVertex_test::cleanupTestCase() Totals: 6 passed, 0 failed, 0 skipped, 0 blacklisted, 1ms ********* Finished testing of orgQhull::QhullVertex_test ********* ********* Start testing of orgQhull::QhullVertexSet_test ********* Config: Using QtTest library 5.11.2, Qt 5.11.2 (x86_64-little_endian-llp64 shared (dynamic) release build; by MSVC 2017) PASS : orgQhull::QhullVertexSet_test::initTestCase() INFO : Cube rotated by QR1595644756 PASS : orgQhull::QhullVertexSet_test::t_construct() INFO : Cube rotated by QR1595644756 PASS : orgQhull::QhullVertexSet_test::t_convert() PASS : orgQhull::QhullVertexSet_test::t_readonly() INFO : Cube rotated by QR1595644756 PASS : orgQhull::QhullVertexSet_test::t_foreach() PASS : orgQhull::QhullVertexSet_test::t_java_iterator() INFO : Cube rotated by QR1595644756 Vertices of first facet with point 0 p1(v6) p2(v4) p0(v3) p3(v2) Vertex identifiers: v6 v4 v3 v2 PASS : orgQhull::QhullVertexSet_test::t_io() PASS : orgQhull::QhullVertexSet_test::cleanupTestCase() Totals: 8 passed, 0 failed, 0 skipped, 0 blacklisted, 1ms ********* Finished testing of orgQhull::QhullVertexSet_test ********* ********* Start testing of orgQhull::RboxPoints_test ********* Config: Using QtTest library 5.11.2, Qt 5.11.2 (x86_64-little_endian-llp64 shared (dynamic) release build; by MSVC 2017) PASS : orgQhull::RboxPoints_test::initTestCase() PASS : orgQhull::RboxPoints_test::t_construct() INFO : Caught QH6189 rbox error: dimension, D0, out of bounds (>=200 or <=0) INFO : Caught QH10062 Qhull error: can not set PointCoordinates dimension to -1 PASS : orgQhull::RboxPoints_test::t_error() PASS : orgQhull::RboxPoints_test::t_test() INFO : Caught QH10063 Qhull error: can not change PointCoordinates dimension (from 2 to 102) PASS : orgQhull::RboxPoints_test::t_getSet() PASS : orgQhull::RboxPoints_test::t_foreach() INFO : Caught QH10012 Qhull error: expected 4 2-d PointCoordinates but read 3 PointCoordinates plus 1 extra coordinates PASS : orgQhull::RboxPoints_test::t_change() PASS : orgQhull::RboxPoints_test::t_ostream() PASS : orgQhull::RboxPoints_test::cleanupTestCase() Totals: 9 passed, 0 failed, 0 skipped, 0 blacklisted, 1ms ********* Finished testing of orgQhull::RboxPoints_test ********* ********* Start testing of orgQhull::Qhull_test ********* Config: Using QtTest library 5.11.2, Qt 5.11.2 (x86_64-little_endian-llp64 shared (dynamic) release build; by MSVC 2017) PASS : orgQhull::Qhull_test::initTestCase() INFO : Caught QH10023 Qhull error: checkIfQhullInitialized failed. Call runQhull() first. area delta 0. qFuzzyCompare delta 3.41421e-12 PASS : orgQhull::Qhull_test::t_construct() Expecting summary of halfspace intersection Halfspace intersection by the convex hull of 4 points in 2-d: Number of halfspaces: 4 Number of non-redundant halfspaces: 4 Number of intersection points: 4 Statistics for: normals of square | qhull H Number of points processed: 4 Number of hyperplanes created: 5 Number of distance tests for qhull: 3 CPU seconds to compute hull (after input): 0 Expecting no output from qh_fprintf() in Qhull.cpp Expecting output from ~Qhull Qhull messages at ~Qhull() Halfspace intersection by the convex hull of 4 points in 2-d: Number of halfspaces: 4 Number of non-redundant halfspaces: 4 Number of intersection points: 4 Statistics for: normals of square | qhull H Number of points processed: 4 Number of hyperplanes created: 5 Number of distance tests for qhull: 3 CPU seconds to compute hull (after input): 0 PASS : orgQhull::Qhull_test::t_attribute() INFO : Caught QH6029 qhull option error: option 'Fd' is not used with this program. It may be used with qhull. While executing: | Options selected for Qhull 2020.2.r 2020/07/24: run-id 225630356 _maxoutside 0 INFO : Error stream without output stream QH6029 qhull option error: option 'Fd' is not used with this program. It may be used with qhull. While executing: | Options selected for Qhull 2020.2.r 2020/07/24: run-id 225630356 _maxoutside 0 INFO : Caught QH6029INFO : Error output sent to output stream without error stream QH6023 qhull input error: feasible point is not clearly inside halfspace feasible point: 0 0 halfspace: -0.5 -0.5 at offset: 0.5 and distance: 0.5 The halfspace was at index 1 While executing: rbox "c" | qhull Tz H0 Options selected for Qhull 2020.2.r 2020/07/24: run-id 225630356 Tz-stdout Halfspace-about 0 _maxoutside 0 INFO : Caught QH6023INFO : No error stream or output stream INFO : Caught QH6029 qhull option error: option 'Fd' is not used with this program. It may be used with qhull. While executing: | Options selected for Qhull 2020.2.r 2020/07/24: run-id 225630356 _maxoutside 0 PASS : orgQhull::Qhull_test::t_message() Convex hull of 8 points in 3-d: Number of vertices: 8 Number of facets: 6 Number of non-simplicial facets: 6 Statistics for: rbox "c" | qhull s Number of points processed: 8 Number of hyperplanes created: 11 Number of distance tests for qhull: 34 Number of distance tests for merging: 90 Number of distance tests for checking: 48 Number of merged facets: 6 CPU seconds to compute hull (after input): 0 Convex hull of 8 points in 3-d: Number of vertices: 8 Number of facets: 6 Number of non-simplicial facets: 6 Statistics for: rbox "c" | qhull Number of points processed: 8 Number of hyperplanes created: 11 Number of distance tests for qhull: 34 Number of distance tests for merging: 90 Number of distance tests for checking: 48 Number of merged facets: 6 CPU seconds to compute hull (after input): 0 PASS : orgQhull::Qhull_test::t_getSet() PASS : orgQhull::Qhull_test::t_getQh() PASS : orgQhull::Qhull_test::t_getValue() PASS : orgQhull::Qhull_test::t_foreach() Expecting vertexList and facetList of a 3-d diamond. 3 6 8 12 0 0 -0.5 0 0 0.5 0 -0.5 0 0 0.5 0 -0.5 0 0 0.5 0 0 3 2 0 4 3 0 2 5 3 1 2 4 3 2 1 5 3 3 0 5 3 0 3 4 3 1 3 5 3 3 1 4 Expecting the same output using std::vector and Qhull classes 3 6 8 12 0 0 -0.5 0 0 0.5 0 -0.5 0 0 0.5 0 -0.5 0 0 0.5 0 0 3 2 0 4 3 0 2 5 3 1 2 4 3 2 1 5 3 3 0 5 3 0 3 4 3 1 3 5 3 3 1 4 Expecting normals of a 3-d diamond. 4 8 -0.5773502691896258 -0.5773502691896258 -0.5773502691896258 -0.2886751345948129 0.5773502691896258 -0.5773502691896258 -0.5773502691896258 -0.2886751345948129 -0.5773502691896258 -0.5773502691896258 0.5773502691896258 -0.2886751345948129 0.5773502691896258 -0.5773502691896258 0.5773502691896258 -0.2886751345948129 0.5773502691896258 0.5773502691896258 -0.5773502691896258 -0.2886751345948129 -0.5773502691896258 0.5773502691896258 -0.5773502691896258 -0.2886751345948129 0.5773502691896258 0.5773502691896258 0.5773502691896258 -0.2886751345948129 -0.5773502691896258 0.5773502691896258 0.5773502691896258 -0.2886751345948129 PASS : orgQhull::Qhull_test::t_diamond() PASS : orgQhull::Qhull_test::cleanupTestCase() Totals: 10 passed, 0 failed, 0 skipped, 0 blacklisted, 4ms ********* Finished testing of orgQhull::Qhull_test ********* Passed 155 tests. Finished test of libqhullcpp. Test libqhull_r with eg/q_test after building libqhull_r/Makefile qhull-2020.2/eg/qtest.sh0000755060175106010010000005154513504454011013267 0ustar bbarber#!/bin/bash # # eg/qtest.sh -- test qhull runs or log a qhull run # # tags: #help #test-rbox #test-qhull #grep #grep-merge #grep-step # #log-qhull #log-t #log-QR # # Test for internal errors using difficult cases for Qhull (see q_benchmark) # ../eg/qtest.sh 100 '500 s W1e-13 C1,1e-13 D4' 'd' | grep -vE 'topology|precision|CPU|Maximum # # $Id: //main/2019/qhull/eg/qtest.sh#4 $$DateTime: 2019/06/25 15:24:47 $ # $Change: 2701 $$Author: bbarber $ QHULL=${QHULL:-qhull} Tnz=${Tnz:-T4z} PROG=$0 NOW=$(date +"%s") TODAY=$(date +"%Y-%m-%d") BASE=$(( (NOW * 234533477) % 1000000 )) COUNT=0 QH_TMPDIR="$TMP/qtest-$TODAY" QH_TEST_DEST="$QH_TMPDIR/qhull-$BASE.log" QH_SHOW_DEST="$QH_TMPDIR/qhull-$BASE-show.log" QH_LOG_DEST="qhull.log" QH_STEP_DEST="qhull-step.log" QH_TEST_BASE=1 QH_TEST_GREP='QH[67]| Statis|[0-9][0-9][.][0-9]x|CPU|FIXUP|retries, input joggled|initial hull is narrow' QH_SHOW_GREPX="QH7[0-9][^8]|Stati" QH_STEP_GREP="QH[0-367]|FIXUP" QH_STEP_ARG="-A10" QH_STEP_EXTRA="QH6| of [0-9]+ points in|:precision problems" QH_MERGE_GREP="QH[67]|QH(1040|1050|3034)|qh_addpoint:|qh_checkflipped|qh_matchdupridge|qh_maxouter|qh_mergefacet|qh_test_centrum_merge|qh_test_nonsimplicial_merge|qtest.sh" QH_MERGE_GREPX='keep 239874664' # 'mergetype (11|13)|mindist= -2, maxdist= -2$' # QH_APPEND_DEST [env only] for copy of QH_TEST_DEST (e.g., eg/q_benchmark) # QH_APPEND_SHOW [env only] for copy of QH_SHOW_DEST (e.g., eg/q_benchmark) # QH_TEST [env only] grep expression appended to QH_TEST_GREP # QH_TESTX [env only] grep expression to exclude from QH_TEST_GREP # QH_SHOW [env only] grep expression to exclude from show log # QH_SHOWX [env only] grep expression appended to QH_SHOW_GREPX # QH_GREP [env only] grep expression appended to 'qtest.sh grep' # QH_GREPX [env only] grep expression to exclude from 'qtest.sh grep' if [[ $# -eq 0 || "$1" == "help" || "$1" == "--help" || "$1" == "-?" ]]; then echo #help echo "qtest.sh -- test qhull runs" echo " qtest.sh N 'rbox c | qhull' -- N random qhull runs" echo " qtest.sh N 'rbox-opts' 'qhull-opts' -- N random rbox|qhull runs" echo " qtest.sh -N 'rbox c | qhull' -- N qhull runs" echo " qtest.sh -N 'rbox opts' 'qhull opts' -- N rbox|qhull runs" echo "execute rbox and qhull" echo " qtest.sh run 'rbox c | qhull' -- execute 'qhull command'" echo " qtest.sh run QR... 'rbox | qhull' -- execute 'qhull command QR...'" echo " qtest.sh run t... 'rbox-opts' 'qhull-opts' -- execute 'rbox t... | qhull'" echo "log execution of rbox and qhull" echo " qtest.sh log 'rbox c | qhull' -- log qhull to qhull.log/qhull-step.log" echo " qtest.sh QR... 'rbox c | qhull' -- log a qhull run" echo " qtest.sh t... 'rbox-opts' 'qhull-opts' -- log a 'rbox|qhull' run" echo " qtest.sh grep 'include-regexp' -- grep qhull.log for events to grep.log" echo " qtest.sh grep 'include-regexp' 'exclude-regexp'" echo " qtest.sh grep-merge logfile -- grep logfile for qh_mergefacet,etc. to stdout" echo " qtest.sh grep-step logfile -- grep logfile for steps to stdout" echo " qtest.sh -v ... -- verbose output with environment vars" echo "variables defined in qtest.sh" echo " QH_TEST_BASE -- first tNN for negative counts" echo " QH_TEST_DEST -- qtest.sh log" echo " QH_TEST_GREP -- grep expression for qtest.sh log" echo " QH_SHOW_DEST -- qtest.sh show log" echo " QH_SHOW_GREPX -- exclude grep for show log" echo " QH_LOG_DEST -- qhull log" echo " QH_LOG_GREP -- grep expression for qhull log" echo " QH_STEP_DEST -- qhull step log" echo " QH_STEP_GREP -- grep expression for step log and grep-step" echo " QH_MERGE_GREP -- grep expression for grep-merge" echo " QH_MERGE_GREPX -- exclude grep for grep-merge" echo "environment variables" echo " QHULL -- qhull program, may be qconvex, etc" echo " QH_APPEND_DEST -- append qtest.sh log" echo " QH_APPEND_SHOW -- append show log" echo " QH_TEST -- additional grep expression for qtest.sh log" echo " QH_TESTX -- exclude grep for qtest.sh log" echo " QH_SHOW -- grep expression for show log" echo " QH_SHOWX -- additional exclude grep for show log" echo " QH_GREP -- additional grep expression for grep log" echo " QH_GREPX -- additional exclude grep for grep log" echo " Tnz -- Trace setting for 'qtest.sh log'" echo "examples" echo " qtest.sh help" echo " qtest.sh 25 '1000 W1e-13 D4' ''" echo " qtest.sh 25 '1000 W0 D4 C2,2e-13' 'Q14'" echo " qtest.sh 25 '300 D4 C1,2e-13' 'd Q14'" echo " qtest.sh -10 '10000 D4' ''" echo " qtest.sh -10 '1000 s D4' ''" echo " qtest.sh -10 'rbox 1000 s D4 | qhull'" echo " qtest.sh run QR4 'rbox 1000 s D4 | qhull'" echo " qtest.sh run t876333 '1000 s D4' ''" echo " qtest.sh log 'rbox 500 s D4 | qhull' # qhull.log qhull-step.log" echo " qtest.sh t876333 '500 s D4' ''" echo " qtest.sh QR4 'rbox 500 s D4 | qhull'" echo " qtest.sh grep 'qh_addpoint|qh_mark_dupridges' | head -20 # QH_GREP QH_GREPX" echo " qtest.sh grep 'qh_addpoint' 'added| qh_addpoint' | head -20" echo " qtest.sh grep-merge qhull.log | head -20" echo " qtest.sh grep-step qhull.log >qhull-step.log" echo " qtest.sh -v -10 '10000 D4' '' # verbose" echo echo "$(grep Id: $0 | head -1)" exit fi function isnum { expr "$1" + 0 >/dev/null 2>&1 } if ! which rbox >/dev/null 2>&1; then if [[ ! -d bin ]]; then echo 'eg/qtest.sh: Run eg/qtest.sh from the Qhull directory with bin/, or add $QHULL' "'$QHULL' and 'rbox' to" '$PATH' exit 1 fi if [[ ! -e bin/rbox && ! -e bin/rbox.exe ]]; then echo "eg/qtest.sh: Build '$QHULL' and 'rbox', or add" '$QHULL' "'$QHULL' and 'rbox' to" '$PATH' exit 1 fi if [[ ! -e "bin/$QHULL" && ! -e "bin/$QHULL.exe" ]]; then echo "eg/qtest.sh: Build '$QHULL' and 'rbox', or add" '$QHULL' "'$QHULL' and 'rbox' to" '$PATH' exit 1 fi PATH="$PWD/bin:$PATH" if ! which rbox >/dev/null 2>&1; then echo 'eg/qtest.sh: Failed to temporily add "$PWD/bin" to $PATH for access to $QHULL and rbox' "'$QHULL'." 'Please execute "export PATH=$PWD/bin:$PATH"' exit 1 fi fi if ! which $QHULL >/dev/null 2>&1; then echo 'eg/qtest.sh: $QHULL failed. Cannot run' "'rbox c | $QHULL'. Add '$QHULL' to" '$PATH' exit 1 fi if [[ ! -d $QH_TMPDIR ]]; then mkdir -p "$QH_TMPDIR" || (echo "qtest.sh: 'mkdir -p $QH_TMPDIR'" && exit 1) fi ISLOG=0 if [[ "$1" == "-v" ]]; then ISLOG=1 shift fi if [[ "$1" == "run" ]]; then if [[ $# -eq 2 ]]; then sh -c "$2" elif [[ $# -eq 3 && "${2:0:2}" == "QR" ]]; then sh -c "$3 $2" elif [[ $# -eq 3 ]]; then rbox $2 | $QHULL $3 elif [[ $# -eq 4 && "${2:0:1}" == "t" ]]; then rbox $3 $2 | $QHULL $4 elif [[ $# -eq 4 ]]; then echo "qtest.sh: Expecting 'run' followed by 'tNNN rbox-args qhull-args'. See 'qtest.sh help'" >&2 exit 1 else echo "qtest.sh: Expecting 'run' followed by 1 to 3 arguments. Got total of $# arguments. See 'qtest.sh help'" >&2 exit 1 fi exit fi if [[ $# -gt 3 ]]; then echo "qtest.sh: Expecting 1 to 3 arguments. Got $# arguments. See 'qtest.sh help'" >&2 exit 1 fi if [[ "$QH_TEST_DEST" == "" || "$QH_SHOW_DEST" == "" || "$QH_LOG_DEST" == "" ]]; then echo "qtest.sh: script does not define \$QH_TEST_DEST, \$QH_SHOW_DEST, or \$QH_LOG_DEST. Required setting for 'qtest.sh help'" >&2 echo -e " QH_TEST_DEST='$QH_TEST_DEST'\n QH_SHOW_DEST='$QH_SHOW_DEST'" >&2 echo -e " QH_LOG_DEST='$QH_TEST_DEST'" >&2 exit 1 elif [[ "$QH_TEST_GREP" == "" || "$QH_SHOW_GREPX" == "" || "$QH_STEP_EXTRA" == "" ]]; then echo "qtest.sh: script does not define \$QH_TEST_GREP, \$QH_STEP_EXTRA, or \$QH_SHOW_GREPX. Required setting for 'qtest.sh help'" >&2 echo -e " QH_TEST_GREP='$QH_TEST_GREP'\n QH_SHOW_GREPX='$QH_SHOW_GREPX'\n QH_STEP_EXTRA='$QH_STEP_EXTRA'" >&2 exit 1 fi if isnum "$1"; then COUNT=$1 fi if [[ $COUNT -lt 0 ]]; then BASE=$(( QH_TEST_BASE )) COUNT=$(( -COUNT )) fi if [[ $COUNT -gt 0 ]]; then DEST="$QH_TEST_DEST" GREP="$QH_TEST_GREP" GREPX="keep 239874664" DEST2="$QH_SHOW_DEST" GREP2="." GREPX2="$QH_SHOW_GREPX" if [[ "$QH_TEST" != "" ]]; then GREP="$GREP|$QH_TEST" fi if [[ "$QH_TESTX" != "" ]]; then GREPX="$QH_TESTX" fi if [[ "$QH_SHOW" != "" ]]; then GREP2="$QH_SHOW" fi if [[ "$QH_SHOWX" != "" ]]; then GREPX2="$GREPX2|$QH_SHOWX" fi if [[ $# -eq 3 ]]; then CMD="rbox $2 t$BASE | $QHULL $3" echo -e "\nTesting -- $CMD >$DEST" | tee "$DEST" | tee "$DEST2" echo "$PROG $COUNT '$2' '$3'" >> "$DEST" (date; pwd; ls -ld "$(which $QHULL)"; $QHULL -V) >> "$DEST" if ! rbox $2 1000 t$BASE | head -10 >/dev/null; then echo; echo "qtest.sh error: 'rbox $2 t$BASE' failed" exit 1 fi if ! (rbox 20 | $QHULL $3 TA1) >/dev/null; then echo; echo "qtest.sh error: 'rbox 20 | $QHULL $3 TA1' failed" exit 1 fi if [[ $ISLOG -gt 0 ]]; then echo "qtest.sh: rbox $2 t$i | $QHULL $3 Tsz | grep -E '$GREP' | grep -Ev '$GREPX' | tee -a '$DEST' | grep -E '$GREP2' | grep -Ev '$GREPX2' | tee -a '$DEST2' " echo -e " QH_TEST_DEST='$QH_TEST_DEST'\n QH_SHOW_DEST='$QH_SHOW_DEST'" echo -e " QH_TEST_GREP='$QH_TEST_GREP'\n QH_SHOW_GREPX='$QH_SHOW_GREPX'" echo -e " QH_TEST='$QH_TEST'\n QH_TESTX='$QH_TESTX'" echo -e " QH_SHOW='$QH_SHOW'\n QH_SHOWX='$QH_SHOWX'" fi #test-rbox START=$(date +"%s") for ((i=0; i<$COUNT; i++)); do RUN=$(( BASE + i )) echo "Test -- t$RUN" | tee -a "$DEST" | tee -a "$DEST2" sh -c "rbox $2 t$RUN | $QHULL $3 Tsz" | grep -E "$GREP" | grep -Ev "$GREPX" | tee -a "$DEST" \ | grep -E "$GREP2" | grep -Ev "$GREPX2" | tee -a "$DEST2" done DONE=$(date +"%s") if [[ $COUNT -gt 2 ]]; then echo "$DONE Test $COUNT runs in $((DONE - START)) seconds (ave. $(( (DONE - START)*1000/COUNT )) msec) -- $CMD" | tee -a "$DEST" | tee -a "$DEST2" fi elif [[ $# -eq 2 ]]; then CMD="$2" echo "Testing -- $CMD >$DEST" | tee "$DEST" | tee "$DEST2" echo "$PROG $COUNT '$CMD'" >> "$DEST" (date; pwd; ls -ld "$(which $QHULL)"; $QHULL -V) >> "$DEST" if ! sh -c "$CMD QR0 TA1" >/dev/null; then echo; echo "qtest.sh error: qhull failed" exit 1 fi if [[ $ISLOG -gt 0 ]]; then echo "qtest.sh: $CMD QR$BASE Tsz | grep -E '$GREP' | grep -Ev '$GREPX' | tee -a '$DEST' | grep -E '$GREP2' | grep -Ev '$GREPX2' | tee -a '$DEST2' " echo -e " QH_TEST_DEST='$QH_TEST_DEST'\n QH_SHOW_DEST='$QH_SHOW_DEST'" echo -e " QH_TEST_GREP='$QH_TEST_GREP'\n QH_SHOW_GREPX='$QH_SHOW_GREPX'" echo -e " QH_TEST='$QH_TEST'\n QH_TESTX='$QH_TESTX'" echo -e " QH_SHOW='$QH_SHOW'\n QH_SHOWX='$QH_SHOWX'" fi #test-qhull START=$(date +"%s") for ((i=0; i<$COUNT; i++)); do RUN=$(( BASE + i )) echo "Test -- QR$RUN" | tee -a "$DEST" | tee -a "$DEST2" sh -c "$CMD QR$RUN Tsz" | grep -E "$GREP" | grep -Ev "$GREPX" | tee -a "$DEST" \ | grep -E "$GREP2" | grep -Ev "$GREPX2" | tee -a "$DEST2" done DONE=$(date +"%s") if [[ $COUNT -gt 2 ]]; then echo "$DONE Test $COUNT runs in $((DONE - START)) seconds (average $(( (DONE - START)*1000/COUNT )) msec) -- $CMD" | tee -a "$DEST" | tee -a "$DEST2" fi else echo "qtest.sh: Expecting run count followed by rbox and qhull options. Only run count provided ($1)." exit 1 fi if [[ "$QH_APPEND_DEST" != "" ]]; then cat "$QH_TEST_DEST" >>"$QH_APPEND_DEST" fi if [[ "$QH_APPEND_SHOW" != "" ]]; then cat "$QH_SHOW_DEST" >>"$QH_APPEND_SHOW" fi elif [[ "$1" == "grep" ]]; then if [[ $# -ge 2 && "$QH_GREP" != "" ]]; then GREP="$2|$QH_GREP" elif [[ $# -ge 2 ]]; then GREP="$2" elif [[ "$QH_GREP" != "" ]]; then GREP="$QH_GREP" else GREP="." fi if [[ $# -eq 3 && "$QH_GREPX" != "" ]]; then GREPX="$3|$QH_GREPX" elif [[ $# -eq 3 ]]; then GREPX="$3" elif [[ "$QH_GREPX" != "" ]]; then GREPX="$QH_GREPX" else if [[ "$GREP" == "." ]]; then echo "qtest.sh: Expecting 'grep' followed by include and exclude regexps or \$QH_GREP or \$QH_GREPX. None defined." exit 1 fi GREPX="keep 239874664" fi echo "qtest.sh: grep from '$QH_LOG_DEST' to stdout" if [[ $ISLOG -gt 0 ]]; then echo "qtest.sh: grep -E '$GREP' '$QH_LOG_DEST' | grep -Ev '$GREPX'" >&2 echo -e " QH_LOG_DEST='$QH_TEST_DEST'" >&2 echo -e " QH_GREP='$QH_GREP'\n QH_GREPX='$QH_GREPX'" >&2 fi #grep grep -E "$GREP" "$QH_LOG_DEST" | grep -Ev "$GREPX" elif [[ "$1" == "grep-merge" ]]; then if [[ $# -ne 2 || ! -r "$2" ]]; then echo "qtest.sh: Expecting 'grep-merge' followed by log file. Got '$1 $2 $3 ...'" >&2 exit 1 fi SRC="$2" # includes qh_appendvertexmerge, qh_findhorizon GREP="$QH_MERGE_GREP" GREPX="$QH_MERGE_GREPX" SED='s/^xxx[0-9]*://' SED2='s/horizon for point.*/horizon for point/' echo "qtest.sh: grep merges from '$SRC' to stdout" >&2 if [[ $ISLOG -gt 0 ]]; then echo "qtest.sh: grep -E '$GREP' '$SRC' | grep -Ev '$GREPX' | sed -r -e '$SED' -e '$SED2'" >&2 fi #grep-merge grep -E "$GREP" "$SRC" | grep -Ev "$GREPX" | sed -r -e "$SED" -e "$SED2" elif [[ "$1" == "grep-step" ]]; then if [[ $# -ne 2 || ! -r "$2" ]]; then echo "qtest.sh: Expecting 'grep-step' followed by log file. Got '$1 $2 $3 ...'" >&2 exit 1 fi SRC="$2" GREP2="$QH_STEP_GREP" GREPX2="keep 239874664" ARG="$QH_STEP_ARG" EXTRA="$QH_STEP_EXTRA" if [[ "$QH_STEP" != "" ]]; then GREP2="$GREP2|$QH_STEP" fi if [[ "$QH_STEPX" != "" ]]; then GREPX2="$QH_STEPX" fi if [[ "$QH_ARG" != "" ]]; then ARG="$QH_ARG" fi if [[ "$QH_EXTRA" != "" ]]; then EXTRA="$EXTRA|$QH_EXTRA" fi echo "qtest.sh: grep step log from '$SRC' to stdout" >&2 if [[ $ISLOG -gt 0 ]]; then echo "qtest.sh: (grep -E '$GREP2' '$SRC' | grep -Ev '$GREPX2'; echo; echo ==== EXTRA $(date) ====; echo; grep '$ARG' -E '$EXTRA' '$SRC')" >&2 echo -e " QH_STEP_GREP='$QH_STEP_GREP'" >&2 echo -e " QH_STEP_ARG='$QH_STEP_ARG'\n QH_STEP_EXTRA='$QH_STEP_EXTRA'" >&2 echo -e " QH_ARG='$QH_ARG'\n QH_STEP='$QH_STEP'" >&2 fi #grep-step grep -E "$GREP2" "$SRC" | grep -Ev "$GREPX2"; echo; echo ==== EXTRA $(date) ====; echo; grep $ARG -E "$EXTRA" "$SRC" elif [[ "$1" == "log" && $# -ne 2 ]]; then echo "qtest.sh: Expecting 'log' followed by a qhull command line in quotes. Got $# arguments" >&2 exit 1 elif [[ "${1:0:1}" == "t" && $# -eq 1 ]]; then echo "qtest.sh: Expecting txxxxxx followed by rbox and qhull options. Got tag '$1' only" >&2 exit 1 elif [[ "${1:0:1}" == "t" && $# -eq 2 ]]; then echo "qtest.sh: Expecting txxxxxx followed by rbox and qhull options. Tag '$1' was followed by a qhull command -- $2" >&2 exit 1 elif [[ "${1:0:2}" == "QR" && $# -eq 1 ]]; then echo "qtest.sh: Expecting QRxxxxxx followed by a qhull command. Got tag '$1' only" >&2 exit 1 elif [[ "${1:0:2}" == "QR" && $# -eq 3 ]]; then echo "qtest.sh: Expecting QRxxxxxx followed by a qhull command. Got rbox options '$2' and qhull options '$3'" >&2 exit 1 elif [[ "${1:0:1}" != "t" && $# -eq 3 ]]; then echo "qtest.sh: Expecting 'txxxx' with rbox and qhull options. Got unknown tag '$1' with two additional arguments" >&2 exit 1 elif [[ "${1:0:2}" != "QR" && "$1" != "log" && $# -eq 2 ]]; then echo "qtest.sh: Expecting 'log' or 'QRxxxx' followed by a qhull command. Got unknown tag '$1' followed by one additional argument '$2'" >&2 exit 1 else DEST="$QH_LOG_DEST" DEST2="$QH_STEP_DEST" GREP="$QH_LOG_GREP" GREPX="keep 239874664" GREP2="$QH_STEP_GREP" GREPX2="keep 239874664" ARG="$QH_STEP_ARG" EXTRA="$QH_STEP_EXTRA" if [[ "$QH_LOG" != "" ]]; then GREP="$GREP|$QH_LOG" fi if [[ "$QH_LOGX" != "" ]]; then GREPX="$QH_LOGX" fi if [[ "$QH_STEP" != "" ]]; then GREP2="$GREP2|$QH_STEP" fi if [[ "$QH_STEPX" != "" ]]; then GREPX2="$QH_STEPX" fi if [[ "$QH_ARG" != "" ]]; then ARG="$QH_ARG" fi if [[ "$QH_EXTRA" != "" ]]; then EXTRA="$EXTRA|$QH_EXTRA" fi if [[ "$1" == "log" ]]; then echo "qtest.sh: log '$2 $Tnz' to '$DEST' and '$DEST2'" | tee "$DEST" | tee "$DEST2" >&2 (echo -n "$HOSTNAME "; date ; pwd; ls -ld "$(which $QHULL)"; $QHULL -V) >> "$DEST" if [[ $ISLOG -gt 0 ]]; then echo "qtest.sh: $2 $Tnz | grep -n . | grep -E '$GREP' | grep -Ev '$GREPX' | tee -a '$DEST' | grep -E '$GREP2' | grep -Ev '$GREPX2' | tee -a '$DEST2'; (echo; echo ==== EXTRA $(date) ====; echo; grep '$ARG' -E '$EXTRA' '$DEST') | tee -a '$DEST2' " >&2 echo -e " QH_LOG_DEST='$QH_LOG_DEST'\n QH_STEP_DEST='$QH_STEP_DEST'" >&2 echo -e " QH_LOG_GREP='$QH_LOG_GREP'\n QH_STEP_GREP='$QH_STEP_GREP'" >&2 echo -e " QH_STEP_ARG='$QH_STEP_ARG'\n QH_STEP_EXTRA='$QH_STEP_EXTRA'" >&2 echo -e " QH_LOG='$QH_LOG'\n QH_LOGX='$QH_LOGX'" >&2 echo -e " QH_ARG='$QH_ARG'\n QH_STEP='$QH_STEP'" >&2 fi #log-qhull sh -c "$2 $Tnz" | grep -n . | grep -E "$GREP" | grep -Ev "$GREPX" | tee -a "$DEST" \ | grep -E "$GREP2" | grep -Ev "$GREPX2" >> "$DEST2" (echo; echo ==== EXTRA $(date) ====; echo; grep $ARG -E "$EXTRA" "$DEST") | tee -a "$DEST2" elif [[ "${1:0:1}" == "t" ]]; then echo "qtest.sh: logging 'rbox $2 $1 | $QHULL T4sz $3' to '$DEST' and '$DEST2'" | tee "$DEST" | tee "$DEST2" >&2 (date; pwd; ls -ld "$(which $QHULL)"; $QHULL -V) >> "$DEST" if [[ $ISLOG -gt 0 ]]; then echo "qtest.sh: rbox $2 $i | $QHULL T4sz $3 | grep -E '$GREP' | grep -Ev '$GREPX' | tee -a '$DEST' | grep -E '$GREP2' | grep -Ev '$GREPX2' | tee -a '$DEST2'; (echo; echo ==== EXTRA $(date) ====; echo; grep '$ARG' -E '$EXTRA' '$DEST') | tee -a '$DEST2'" >&2 echo -e " QH_TEST_DEST='$QH_TEST_DEST'\n QH_SHOW_DEST='$QH_SHOW_DEST'" >&2 echo -e " QH_TEST_GREP='$QH_TEST_GREP'\n QH_SHOW_GREPX='$QH_SHOW_GREPX'" >&2 echo -e " QH_TEST_ARG='$QH_TEST_ARG'\n QH_TEST_EXTRA='$QH_TEST_EXTRA'" >&2 echo -e " QH_TEST='$QH_TEST'\n QH_TESTX='$QH_TESTX'" >&2 echo -e " QH_SHOW='$QH_SHOW'\n QH_SHOWX='$QH_SHOWX'" >&2 echo -e " QH_ARG='$QH_ARG'\n QH_EXTRA='$QH_EXTRA'" >&2 fi if ! rbox $2 $1 1000 >/dev/null; then echo; echo "qtest.sh error: 'rbox $2 $1' failed" >&2 exit 1 fi #log-t rbox $2 $1 | $QHULL $Tnz $3 | grep -n . | grep -E "$GREP" | grep -Ev "$GREPX" | tee -a "$DEST" \ | grep -E "$GREP2" | grep -Ev "$GREPX2" >> "$DEST2" (echo; echo ==== EXTRA $(date) ====; echo; grep $ARG -E "$EXTRA" "$DEST") | tee -a "$DEST2" elif [[ "${1:0:2}" == "QR" ]]; then echo "qtest.sh: log '$2 $Tnz $1' to '$DEST' and '$DEST2'" | tee "$DEST" | tee "$DEST2" >&2 (date; pwd; ls -ld "$(which $QHULL)"; $QHULL -V) >> "$DEST" if [[ $ISLOG -gt 0 ]]; then echo "qtest.sh: $2 $Tnz $1 | grep -n . | grep -E '$GREP' | grep -Ev '$GREPX' | tee -a '$DEST' | grep -E '$GREP2' | grep -Ev '$GREPX2' | tee -a '$DEST2'; (echo; echo ==== EXTRA $(date) ====; echo; grep '$ARG' -E '$EXTRA' '$DEST') | tee -a '$DEST2' " >&2 echo -e " QH_LOG_DEST='$QH_LOG_DEST'\n QH_STEP_DEST='$QH_STEP_DEST'" >&2 echo -e " QH_LOG_GREP='$QH_LOG_GREP'\n QH_STEP_GREP='$QH_STEP_GREP'" >&2 echo -e " QH_STEP_ARG='$QH_STEP_ARG'\n QH_STEP_EXTRA='$QH_STEP_EXTRA'" >&2 echo -e " QH_LOG='$QH_LOG'\n QH_LOGX='$QH_LOGX'" >&2 echo -e " QH_ARG='$QH_ARG'\n QH_STEP='$QH_STEP'" >&2 fi #log-QR sh -c "$2 $Tnz $1" | grep -n . | grep -E "$GREP" | grep -Ev "$GREPX" | tee -a "$DEST" \ | grep -E "$GREP2" | grep -Ev "$GREPX2" >> "$DEST2" (echo; echo ==== EXTRA $(date) ====; echo; grep $ARG -E "$EXTRA" "$DEST") | tee -a "$DEST2" else echo "qtest.sh: unexpected arguments, run 'qtest.sh' for help -- qtest.sh $1 $2 $3" exit 1 fi fi # end of qtest.sh qhull-2020.2/eg/q_benchmark0000755060175106010010000006460613666456540014014 0ustar bbarber#!/bin/sh # # eg/q_benchmark [test] [precision-count] [other-count] [pinched-count] [time-count]" # Time and precision benchmark for qhull using eg/qtest.sh # # With negative counts, compare output with Beyond Compare. Aligns on '^Test.?.?.? -- ' # Session > Session Settings.. > Alignment > Skew Tolerance > 5000 # # To compare various choices for facet merging (e.g., merge_r.c/qh_next_facetmerge) # T=A_LT_T_LT_6; ../eg/q_benchmark 0 -6 -6 | tee $T.log | grep -E '^== |Maximum|error' | tee $T.err; echo $T $(grep error $T.err | wc -l) # # Use 'gcc -O3' via libqhull/Makefile # # $Id: //main/2019/qhull/eg/q_benchmark#5 $$DateTime: 2020/06/05 16:33:18 $ # $Change: 2967 $$Author: bbarber $ function log { #message echo "$1" | tee -a $QH_APPEND_DEST | tee -a $QH_APPEND_SHOW } # set -v # echo commands to stdout if [[ "$1" == "test" ]]; then TEST_QTEST=1 shift fi N_PRECISION=${1:-0} FUZZY_CUBE=1 NARROW_LENSE=1 CONE=1 N_OTHER=${2:-0} DELAUNAY_CIRCLE=1 LENSE_SIZE=0 # not repeatable LENSE_GAP=0 # not repeatable N_PINCHED=${3:-0} # Q14 -- merge pinched vertices CUBE_PAIRS=1 DELAUNAY_PAIRS=1 CIRCLE_PAIRS=1 VORONOI_WIDE_MESH=1 # wide pairs, 1e-8 instead of 1e-13 DELAUNAY_DRUM_PAIRS=1 # nearly cospherical with Qbb TIME_DELAUNAY_PAIRS_CUBE=1 TIME_DELAUNAY_PAIRS=1 N_TIMING=${4:-0} TIME_INTERIOR=1 # Random points TIME_SPHERE=1 # Cospherical points TIME_POST_MERGE=1 # Post-merge of cospherical points TIME_CUBICAL=1 # Rotated cubical points TIME_JOGGLE=1 # Joggled cubical points TIME_MERGE=1 # Merging cubical points TIME_DELAUNAY=1 # Delaunay of random points TIME_REGULAR_MESH=1 QHULL=${QHULL:-qhull} if [[ -d eg ]]; then export QH_APPEND_DEST="eg/qhull-benchmark.log" export QH_APPEND_SHOW="eg/qhull-benchmark-show.log" else export QH_APPEND_DEST="qhull-benchmark.log" export QH_APPEND_SHOW="qhull-benchmark-show.log" fi rm -f $QH_APPEND_DEST rm -f $QH_APPEND_SHOW if qtest.sh >/dev/null 2>&1; then QTEST=qtest.sh elif [ -e qtest.sh ]; then QTEST=qtest.sh elif [ -e eg/qtest.sh ]; then QTEST=eg/qtest.sh elif [ -e ../eg/qtest.sh ]; then QTEST=../eg/qtest.sh elif [ -e ../../eg/qtest.sh ]; then QTEST=../../eg/qtest.sh else echo 'eg/q_benchmark: Not able to locate qtest.sh. Tried $PATH, ./, eg/, ../eg/, and ../../eg/' exit 1 fi if ! which rbox >/dev/null 2>&1; then if [ ! -d bin ]; then echo 'eg/q_benchmark: Run eg/q_benchmark from the Qhull directory with bin/rbox, or add rbox to $PATH' exit 1 fi if [ ! -e bin/rbox -a ! -e bin/rbox.exe ]; then echo 'eg/q_benchmark: Build qhull first. rbox is missing from bin/ directory and $PATH' exit 1 fi echo 'eg/q_benchmark: Temporarily add "$PWD/bin" to $PATH for access to rbox' PATH=$PWD/bin:$PATH if ! which rbox >/dev/null 2>&1; then echo 'eg/q_benchmark: PATH=... failed. Please execute "export PATH=$PWD/bin:$PATH" and repeat' exit 1 fi fi if ! which $QTEST >/dev/null 2>&1; then log "q_benchmark error: expecting Qhull test program '$QTEST', not able to execute" log "$(ls -ld $QTEST)" log "$($QTEST)" exit 1 fi if ! (rbox c | $QHULL >/dev/null 2>&1); then log "q_benchmark error: expecting a Qhull program \$QHULL '$QHULL', not able to execute" log "$(ls -ld $QHULL)" log "$($QHULL)" exit 1 fi export QH_TEST='' # additional regexp for qtest.sh, see N_TIMING log log "============================================" log "== eg/q_benchmark [test] [precision-count] [other-count] [pinched-count] [time-count]" log "== Time and precision benchmarks for qhull" log "============================================" log log "[jun'20] Many timing figures 5-10% faster than jun'19 results. No change to code" log if [[ "$TEST_QTEST" == 1 ]]; then log "'q_benchmark test $N_PRECISION $N_OTHER $N_PINCHED $N_TIMING' $(date)" else log "'q_benchmark $N_PRECISION $N_OTHER $N_PINCHED $N_TIMING' $(date)" fi log log "$(grep Id: $0 | head -1)" log "$($QTEST help | grep Id:)" log "qhull => $(QHULL -V)" log "$(ls -l $(which $QHULL))" log "rbox => $(rbox | grep Version | sed 's/^.*Version/Version/')" log "$(ls -l $(which rbox))" log "$(uname -a)" log log "Logging to $PWD/$QH_APPEND_DEST and $QH_APPEND_SHOW" if [[ "$TEST_QTEST" == 1 ]]; then log log ======================== log "=== test eg/qtest.sh ===" log ======================== log log "== qtest.sh help" $QTEST | tee -a "$QH_APPEND_DEST" log "== qtest.sh 1 '10' ''" $QTEST 1 '10' '' log "== qtest.sh 2 'rbox 10 | qhull'" $QTEST 2 'rbox 10 | qhull' log "== qtest.sh -3 '10' ''" $QTEST -3 '10' '' log "== qtest.sh -3 'rbox 10 | qhull'" $QTEST -3 'rbox 10 | qhull' log "== qtest.sh run t123456 '10' 'Tz'" $QTEST run t123456 '10' 'Tz' | tee -a "$QH_APPEND_DEST" log "== qtest.sh run QR123456 'rbox 10 | qhull Tz'" $QTEST run QR123456 'rbox 10 | qhull Tz' | tee -a "$QH_APPEND_DEST" log "== qtest.sh log 'rbox 10 | qhull'" ($QTEST log 'rbox 10 | qhull' && echo && echo qhull.log && head qhull.log) | tee -a "$QH_APPEND_DEST" log "== qtest.sh t123456 '10' ''" ($QTEST t123456 '10' '' && echo && echo qhull.log && head qhull.log) | tee -a "$QH_APPEND_DEST" log "== qtest.sh QR123456 'rbox 10 | qhull'" ($QTEST QR123456 'rbox 10 | qhull' && echo && echo qhull-step.log && head qhull-step.log) | tee -a "$QH_APPEND_DEST" log "== qtest.sh grep 'qh_addpoint|QH1' >qhull-grep.log" ($QTEST grep 'qh_addpoint|QH1' >qhull-grep.log && head qhull-grep.log && echo qhull-grep.log && tail qhull-grep.log) | tee -a "$QH_APPEND_DEST" log "== qtest.sh grep 'qh_addpoint' 'added| qh_addpoint' >qhull-grep.log" ($QTEST grep 'qh_addpoint' 'added| qh_addpoint' >qhull-grep.log && head qhull-grep.log && echo qhull-grep.log && tail qhull-grep.log) | tee -a "$QH_APPEND_DEST" log "== qtest.sh grep-merge 'qhull.log' >qhull-grep.log" ($QTEST grep-merge qhull.log >qhull-grep.log && head qhull-grep.log && echo qhull-grep.log && tail qhull-grep.log) | tee -a "$QH_APPEND_DEST" log "== qtest.sh grep-step 'qhull.log' >qhull-step.log" ($QTEST grep-step qhull.log >qhull-step.log && head qhull-step.log && echo qhull-step.log && tail qhull-step.log) | tee -a "$QH_APPEND_DEST" log "== qtest.sh -v -3 'rbox 10 | qhull'" $QTEST -v -3 'rbox 10 | qhull' log log ============================ log "=== test qtest.sh errors ===" log ============================ log "== qtest.sh run -3 'rbox 10 | qhull'" $QTEST run -3 'rbox 10 | qhull' | tee -a "$QH_APPEND_DEST" log "== qtest.sh run 3 '10' ''" $QTEST run 3 '10' '' | tee -a "$QH_APPEND_DEST" log "== qtest.sh run '10' ''" $QTEST run '10' '' | tee -a "$QH_APPEND_DEST" log "== qtest.sh run" $QTEST run | tee -a "$QH_APPEND_DEST" log "== qtest.sh 3 '10' d T4" $QTEST 3 '10' d T4 | tee -a "$QH_APPEND_DEST" log "== qtest.sh 3 '10' 'd H'" $QTEST 3 '10' 'd H' | tee -a "$QH_APPEND_DEST" log "== qtest.sh 3" $QTEST 3 | tee -a "$QH_APPEND_DEST" log "== qtest.sh grep" $QTEST grep | tee -a "$QH_APPEND_DEST" log "== qtest.sh grep-merge '10' 'v'" $QTEST grep-merge '10' 'v' | tee -a "$QH_APPEND_DEST" log "== qtest.sh grep-merge" $QTEST grep-merge | tee -a "$QH_APPEND_DEST" log "== qtest.sh grep-merge not-a-file" $QTEST grep-merge not-a-file | tee -a "$QH_APPEND_DEST" log "== qtest.sh grep-step '10' 'v'" $QTEST grep-step '10' 'v' | tee -a "$QH_APPEND_DEST" log "== qtest.sh grep-step" $QTEST grep-step | tee -a "$QH_APPEND_DEST" log "== qtest.sh grep-step not-a-file" $QTEST grep-step not-a-file | tee -a "$QH_APPEND_DEST" log "== qtest.sh log '10' 'd'" $QTEST log '10' 'd' | tee -a "$QH_APPEND_DEST" log "== qtest.sh t34" $QTEST t34 | tee -a "$QH_APPEND_DEST" log "== qtest.sh t34 'rbox 10 | qhull'" $QTEST t34 'rbox 10 | qhull' | tee -a "$QH_APPEND_DEST" log "== qtest.sh QR34" $QTEST QR34 | tee -a "$QH_APPEND_DEST" log "== qtest.sh QR34 '10' 'v'" $QTEST QR34 '10' 'v' | tee -a "$QH_APPEND_DEST" log "== qtest.sh t34 '10 ZERROR' 'v'" $QTEST t34 '10 ZERROR' 'v' | tee -a "$QH_APPEND_DEST" log "== Delete temporary log files ghull.log, qhull-grep.log, and qhull-step.log" rm -f qhull.log qhull-grep.log qhull-step.log fi log log "==============================" log "=== N_PRECISION test cases ===" log "==============================" if [[ $N_PRECISION -gt 0 || $N_PRECISION -lt 0 ]]; then log "== difficult cases for qhull ${d:-`date`}" if [[ $FUZZY_CUBE == 1 ]]; then log log ==================== log "== Convex hull of fuzzy cube (large flat facets)" log ==================== set -v # [2015-2019] 1 D5 error vs. 2 D5 + 1 D6 error, similar CPU # rbox is slow if compiled for Debug $QTEST $N_PRECISION '1000000 W1e-13 D2' 'Tv' $QTEST $N_PRECISION '500000 W1e-13 D3' 'Tv' $QTEST $N_PRECISION '10000 W1e-13 D4' 'Tv' $QTEST $N_PRECISION '2000 W1e-13 D5' 'Tv' $QTEST $N_PRECISION '1000 W1e-13 D6' 'Tv' set +v fi if [[ $NARROW_LENSE == 1 ]]; then log log ==================== log "== narrow lense" log ==================== set -v # [2015-2019] no errors, similar CPU, new sometimes slower $QTEST $N_PRECISION '1000000 L100000 s G1e-6 D2' 'Tv' $QTEST $N_PRECISION '10000 L100000 s G1e-6 D3' 'Q12 Tv' $QTEST $N_PRECISION '5000 L100000 s G1e-6 D4' 'Tv' $QTEST $N_PRECISION '1000 L100000 s G1e-6 D5' 'Tv' $QTEST $N_PRECISION '400 L100000 s G1e-6 D6' 'Tv' set +v fi if [[ $CONE == 1 ]]; then log log ==================== log "== cone" log ==================== set -v # [2015-2019] D2, no errors, similar CPU # [2015-2019] D3, 2+20x and outside points vs. 3+20x, new is faster except for one 3x slower # [2015-2019] D4, 3+20x vs. no errors, wide variation in CPU, new is slower # [2015-2019] D5, 0 vs. 2 errors, new is 2x slower # [2015-2019] D6, 0 vs. 1 error and 3 OK errors, new is 2x slower $QTEST $N_PRECISION '100000 s Z1 G1e-13 D2' 'Tv' $QTEST $N_PRECISION '10000 s Z1 G1e-13 D3' 'Q12 Tv' $QTEST $N_PRECISION '2000 s Z1 G1e-13 D4' 'Q12 Tv' $QTEST $N_PRECISION '1000 s Z1 G1e-13 D5' 'Q12 Tv' $QTEST $N_PRECISION '400 s Z1 G1e-13 D6' 'Q12 Tv' set +v fi export QH_TEST='' fi # end of N_PRECISION test cases log log "==========================" log "=== N_OTHER test cases ===" log "==========================" if [[ $N_OTHER -gt 0 || $N_OTHER -lt 0 ]]; then if [[ $DELAUNAY_CIRCLE == 1 ]]; then log log ==================== log "== Delaunay triangulation of fuzzy circle (large, narrow disk)" log "== No Qbb, highly degenerate due to narrow disk of two cospherical sets of points" log ==================== set -v # [2015-2019] D2, ten 20+x vs. 3 errors and seven 20+x # [2015-2019] D3, 1 error 2 outside nine 20+x vs. 8 errors and two 20+x # [2015-2019] D4, 5 errors and three 20+x vs. 3 errors and three 20+x # [2015-2019] D5, 7 errors vs. 1 error and one 20+x # [2015-2019] D6, 8 errors vs. 9 errors # Only 8 facets remain due to many dupridges with flipped facets $QTEST $N_OTHER '10000 s W1e-13 D2' 'd Tv' # no Qbb $QTEST $N_OTHER '2000 s W1e-13 D3' 'd Tv' $QTEST $N_OTHER '1000 s W1e-13 D4' 'd Tv' $QTEST $N_OTHER '200 s W1e-13 D5' 'd Tv' $QTEST $N_OTHER '100 s W1e-13 D6' 'd Tv' set +v fi export QH_TEST='merge|rename|created:|facets:| hull:' if [[ $LENSE_SIZE == 1 ]]; then # For testing, normally skipped log log ==================== log "== test narrow lense by size " log ==================== set -v # [2015.2-2018.0] D3 similar behavior, 10x increase in merges/facet per run # [2015.2-2018.0] D3 L1000000 QH6154, initial simplex is flat $QTEST 1 '1000 L1000 s G1e-6 D3' '' $QTEST 1 '1000 L10000 s G1e-6 D3' '' $QTEST 1 '1000 L100000 s G1e-6 D3' '' $QTEST 1 '1000 L1000000 s G1e-6 D3' '' set +v fi if [[ $LENSE_GAP == 1 ]]; then # For testing, normally skipped log log ==================== log "== test narrow lense by gap " log ==================== set -v # [2015.2-2018.0] D3 similar behavior, L100000 max'd 511 merges for a facet $QTEST 1 '1000 L100000 s G1e-3 D3' '' $QTEST 1 '1000 L100000 s G1e-4 D3' '' $QTEST 1 '1000 L100000 s G1e-5 D3' '' $QTEST 1 '1000 L100000 s G1e-6 D3' '' $QTEST 1 '1000 L100000 s G1e-7 D3' '' $QTEST 1 '1000 L100000 s G1e-8 D3' '' set +v fi export QH_TEST='' fi # end of N_OTHER test cases log log "===========================================================" log "=== N_PINCHED test cases for Q14-merge-pinched-vertices ===" log "===========================================================" if [[ $N_PINCHED -gt 0 || $N_PINCHED -lt 0 ]]; then if [[ $CUBE_PAIRS == 1 ]]; then log log ==================== log "== Convex hull of fuzzy cube with point pairs (large flat facets)" log ==================== set -v # [2015-2019] D2, no errors, similar CPU # [2015-2019] D3, no errors, new is faster # [2015-2019] D4, 3 vs. 1 error, similar speed # [2015-2019] D5, 10 vs. 1 errors # [2015-2019] D6, 10 vs. 2 errors $QTEST $N_PINCHED '1000000 W1e-13 C1,2e-13 D2' 'Q14 Tv' $QTEST $N_PINCHED '500000 W1e-13 C1,2e-13 D3' 'Q14 Tv' # Tv doubles the time $QTEST $N_PINCHED '20000 W1e-13 C1,2e-13 D4' 'Q14 Tv' $QTEST $N_PINCHED '2000 W1e-13 C1,2e-13 D5' 'Q14 Tv' $QTEST $N_PINCHED '500 W1e-13 C1,2e-13 D6' 'Q14 Tv' set +v log log ==================== log "== Convex hull of cube with point pairs (large flat facets)" log ==================== set -v # [2015-2019] D2, no errors, new is somewhat slower # [2015-2019] D3, no errors, similar CPU # [2015-2019] D4, 5 vs. no errors, similar speed # [2015-2019] D5, 9 vs. 1 error # [2015-2019] D6, 10 vs. 6 errors $QTEST $N_PINCHED '1000000 W0 C1,2e-13 D2' 'Q14 Tv' $QTEST $N_PINCHED '100000 W0 C1,2e-13 D3' 'Q14 Tv' $QTEST $N_PINCHED '5000 W0 C1,2e-13 D4' 'Q14 Tv' $QTEST $N_PINCHED '1000 W0 C1,2e-13 D5' 'Q14 Tv' $QTEST $N_PINCHED '500 W0 C1,2e-13 D6' 'Q14 Tv' set +v fi if [[ $DELAUNAY_PAIRS == 1 ]]; then log log ==================== log "== Delaunay triangulation of point pairs (large upper facet)" log "== Difficult case due to large upper facet with nearly adjacent vertices" log "== A bounding box helps avoid this case, see TIME_DELAUNAY_PAIRS" log ==================== set -v # [2015-2019] D2 no errors, similar CPU # [2015-2019] D3 10 vs. 0 errors # [2015-2019] D4 10 vs. 4 errors # [2015-2019] D5 10 vs. 7 errors # [2015-2019] D6 10 vs. 0 errors $QTEST $N_PINCHED '100000 C1,2e-13 D2' 'Q14 d Qbb' # Tv is too expensive $QTEST $N_PINCHED '10000 C1,2e-13 D3' 'Q14 d Qbb Tv' $QTEST $N_PINCHED '500 C1,2e-13 D4' 'Q14 d Qbb Tv' $QTEST $N_PINCHED '200 C1,2e-13 D5' 'Q14 d Qbb Tv' $QTEST $N_PINCHED '100 C1,2e-13 D6' 'Q14 d Qbb Tv' set +v log log ==================== log "== Delaunay triangulation of point quads (2e-13, large upper facet)" log "== Difficult case due to large upper facet with many nearly adjacent vertices" log ==================== set -v # [2015-2019] D2 no errors, new somewhat faster # [2015-2019] D3 10 vs. 7 errors # [2015-2019] D4 10 vs. 9 errors # [2015-2019] D5 10 vs. 9 errors # [2015-2019] D6 10 vs. 2 errors $QTEST $N_PINCHED '50000 C3,2e-13 D2' 'Q14 d Qbb' # 'Tv' is too expensive $QTEST $N_PINCHED '10000 C3,2e-13 D3' 'Q14 d Qbb' # 'Tv' is too expensive $QTEST $N_PINCHED '200 C3,2e-13 D4' 'Q14 d Qbb Tv' # lots of errors for 300 $QTEST $N_PINCHED '100 C3,2e-13 D5' 'Q14 d Qbb Tv' # lots of error for 100 and 200 $QTEST $N_PINCHED '100 C3,2e-13 D6' 'Q14 d Qbb Tv' # OK set +v fi if [[ $CIRCLE_PAIRS == 1 ]]; then log log ==================== log "== Delaunay triangulation of fuzzy circle with pairs (large, narrow disk)" log "== Highly degenerate due to narrow disk of two cospherical sets of point pairs" log "== Worse with Qbb since it stretches out the paraboloid, doubling _one-merge" log ==================== set -v # [2015-2019] D2 0 vs. 2 errors, new 10x faster # [2015-2019] D3 10 vs. 9 errors # [2015-2019] D4 10 vs. 7 errors # [2015-2019] D5 10 vs. 10 errors # [2015-2019] D6 10 vs. 10 errors $QTEST $N_PINCHED '10000 s W1e-13 C1,1e-13 D2' 'Q14 d Tv' $QTEST $N_PINCHED '5000 s W1e-13 C1,1e-13 D3' 'Q14 d Tv' $QTEST $N_PINCHED '500 s W1e-13 C1,1e-13 D4' 'Q14 d Tv' $QTEST $N_PINCHED '200 s W1e-13 C1,1e-13 D5' 'Q14 d Tv' $QTEST $N_PINCHED '100 s W1e-13 C1,1e-13 D6' 'Q14 d Tv' set +v fi if [[ $VORONOI_WIDE_MESH == 1 ]]; then log log ==================== log "== Voronoi diagram of rotated mesh with wide, 1e-8 pairs" log "== All fail at C1,1e-12" log ==================== set -v # [2015-2019] D2 1 vs. 0 errors, similar speed # [2015-2019] D3 6 vs. 4 errors, similar speed # [2015-2019] D4 0 vs. 0 errors, new is 5% slower # [2015-2019] D5 0 vs. 2 errors, new is 10% slower # [2015-2019] D6 skipped, too slow $QTEST $N_PINCHED "10000 M3,4 C1,1e-8 D2" "QR3 Q14 v Qbb Tv" # co-circular if 40000 $QTEST $N_PINCHED "2000 M3,4,5 C1,1e-8 D3" "QR3 Q14 v Qbb Tv" $QTEST $N_PINCHED "600 M3,4,5 C1,1e-8 D4" "QR3 Q14 v Qbb Tv" $QTEST $N_PINCHED "300 M3,4,5 C1,1e-8 D5" "QR3 Q14 v Qbb Tv" # 250 is narrow log "skip D6, millions of vertices" # $QTEST $N_PINCHED "250 M3,4,5 D6 C1,1e-8" "QR3 Q14 v Qbb Tv" set +v fi if [[ $DELAUNAY_DRUM_PAIRS == 1 ]]; then log log ============================ log "== Delaunay triangulation of nearly cospherical point pairs with Qbb drum" log "== Qbb makes this the most difficult distribution for Qhull, only 100 points" log ============================ # [2015-2019] D3 0 vs. 0 errors, new is 2x faster # [2015-2019] D4 9 vs. 8 errors # [2015-2019] D5 10 vs. 10 errors # [2015-2019] D6 10 vs. 10 errors $QTEST $N_PINCHED '1000 s C1,1e-13 D3' 'Q14 d Qbb Tv' $QTEST $N_PINCHED '100 s C1,1e-13 D4' 'Q14 d Qbb Tv' $QTEST $N_PINCHED '50 s C1,1e-13 D5' 'Q14 d Qbb Tv' $QTEST $N_PINCHED '50 s C1,1e-13 D6' 'Q14 d Qbb Tv' fi if [[ $TIME_DELAUNAY_PAIRS_CUBE == 1 ]]; then log log ============================ log "== Time for pinched Delaunay triangulation of random point pairs (Q14) with bounding box" log ============================ # [2015-2019] D2 no errors, similar speed # [2015-2019] D3 3 vs. no errors, similar speed # [2015-2019] D4 10 vs. 1 error # [2015-2019] D5 10 vs. 1 error # [2015-2019] D6 10 vs. 1 error $QTEST $N_PINCHED '50000 C1,2e-13 c G2.0 D2' 'Q14 d Qbb' $QTEST $N_PINCHED '10000 C1,2e-13 c G2.0 D3' 'Q14 d Qbb' $QTEST $N_PINCHED '3000 C1,2e-13 c G2.0 D4' 'Q14 d Qbb' $QTEST $N_PINCHED '500 C1,2e-13 c G2.0 D5' 'Q14 d Qbb' $QTEST $N_PINCHED '100 C1,2e-13 c G2.0 D6' 'Q14 d Qbb' fi if [[ $TIME_DELAUNAY_PAIRS == 1 ]]; then log log ============================ log "== Time for pinched Delaunay triangulation of random point pairs (Q14, Q12)" log "== qh_next_facetmerge, qh_findbesthorizon (qh_distplane)" log ============================ # [2015-2019] D2 no errors, 20% slower CPU # [2015-2019] D3 10 vs. no errors # [2015-2019] D4 10 vs. no errors # [2015-2019] D5 10 vs. 2 errors # [2015-2019] D6 10 vs. no errors $QTEST $N_PINCHED '50000 C1,2e-13 D2' 'Q14 d Qbb' $QTEST $N_PINCHED '5000 C1,2e-13 D3' 'Q14 d Qbb' $QTEST $N_PINCHED '500 C1,2e-13 D4' 'Q12 Q14 d Qbb' $QTEST $N_PINCHED '300 C1,2e-13 D5' 'Q12 Q14 d Qbb' $QTEST $N_PINCHED '100 C1,2e-13 D6' 'Q14 d Qbb' fi export QH_TEST='' fi # end of N_PINCHED test cases log log =========================== log "=== N_TIMING test cases ===" log =========================== if [[ $N_TIMING -gt 0 || $N_TIMING -lt 0 ]]; then # export QH_TEST='vertices:|facets:|sites:|regions:|merged facets:|hyperplanes created:' log log ============================ log "== Time for random points in a cube" log ============================ if [[ $TIME_INTERIOR == 1 ]]; then # [2015-2019] D2 no errors, 10% slower CPU # [2015-2019] D3 no errors, 5% slower CPU # [2015-2019] D4 no errors, similar CPU # [2015-2019] D5 no errors, similar CPU # [2015-2019] D6 no errors, similar CPU $QTEST $N_TIMING '1000000 D2' '' $QTEST $N_TIMING '500000 D3' '' $QTEST $N_TIMING '200000 D4' '' $QTEST $N_TIMING '100000 D5' 'Q12' $QTEST $N_TIMING '3000 D6' '' fi log log ============================ log "== Time for random cospherical points" log ============================ if [[ $TIME_SPHERE == 1 ]]; then # [2015-2019] D2 no errors, similar CPU # [2015-2019] D3 no errors, 10% slower CPU # [2015-2019] D4 no errors, 5% slower CPU # [2019, gcc] D4 qconvex, no errors, 4% faster than qhull # [2015-2019] D5 no errors, similar CPU # [2015-2019] D6 no errors, similar CPU $QTEST $N_TIMING '100000 s D2' '' $QTEST $N_TIMING '100000 s D3' '' $QTEST $N_TIMING '50000 s D4' '' if [[ -e ../bin/qconvex || -e bin/qconvex ]]; then echo echo == Repeat with 'qconvex', bin/qconvex is built with libqhull instead of libqhull_r QHULL=qconvex $QTEST $N_TIMING '50000 s D4' '' fi $QTEST $N_TIMING '10000 s D5' '' $QTEST $N_TIMING '1000 s D6' '' fi log log ============================ log "== Time for extreme post-merge of random cospherical points" log ============================ if [[ $TIME_POST_MERGE == 1 ]]; then # [2015-2019] D2 no errors, 10% slower CPU # [2015-2019] D3 no errors, 20% slower CPU # [2015-2019] D4 no errors, 15% slower CPU # [2019, gcc] D4 qconvex, no errors, slightly faster than qhull # [2015-2019] D5 no errors, 10% slower CPU # [2015-2019] D6 no errors, 10% slower CPU $QTEST $N_TIMING '100000 s D2' 'C0.01' $QTEST $N_TIMING '10000 s D3' 'C0.01' $QTEST $N_TIMING '5000 s D4' 'C0.01' if [[ -e ../bin/qconvex || -e bin/qconvex ]]; then echo echo == Repeat with 'qconvex', bin/qconvex is built with libqhull instead of libqhull_r QHULL=qconvex $QTEST $N_TIMING '5000 s D4' 'C0.01' fi $QTEST $N_TIMING '2000 s D5' 'C0.01' $QTEST $N_TIMING '500 s D6' 'C0.01' fi log log ============================ log "== Time for rotated cubical points with large merged facets" log ============================ if [[ $TIME_CUBICAL == 1 ]]; then # [2015-2019] D2 no errors, 5% slower CPU # [2015-2019] D3 no errors, somewhat slower CPU # [2015-2019] D4 no errors, similar CPU # [2015-2019] D5 no errors, 10% slower CPU # [2015-2019] D6 no errors, 10% slower CPU $QTEST $N_TIMING '5000000 W0 D2' 'QR3' $QTEST $N_TIMING '1000000 W0 D3' 'QR3' $QTEST $N_TIMING '100000 W0 D4' 'QR3' $QTEST $N_TIMING '10000 W0 D5' 'QR3' $QTEST $N_TIMING '1000 W0 D6' 'QR3' fi log log ============================ log "== Time for joggled, rotated cubical points with multiple retries" log ============================ if [[ $TIME_JOGGLE == 1 ]]; then # [2015-2019] D2 no errors, somewhat slower CPU, 0.67-0.78 was 0.8 # [2015-2019] D3 no errors, similar CPU, 0.4-1.7 was 0.5-0.6 # [2015-2019] D4 no errors, somewhat slower CPU, 0.24-0.37 was 0.35 # [2015-2019] D5 no errors, similar CPU, 0.4-0.9 was 0.6 # [2015-2019] D6 no errors, similar CPU, 0.5-1.0 was 0.9 $QTEST $N_TIMING '5000000 W0 D2' 'QR3 QJ' $QTEST $N_TIMING '1000000 W0 D3' 'QR3 QJ' $QTEST $N_TIMING '100000 W0 D4' 'QR3 QJ' $QTEST $N_TIMING '10000 W0 D5' 'QR3 QJ' $QTEST $N_TIMING '1000 W0 D6' 'QR3 QJ' log log ============================ log "== Time for joggled, nearly cubical points" log ============================ $QTEST $N_TIMING '1000000 W1e-13 D2' 'QJ' $QTEST $N_TIMING '500000 W1e-13 D3' 'QJ' $QTEST $N_TIMING '100000 W1e-13 D4' 'QJ' $QTEST $N_TIMING '10000 W1e-13 D5' 'QJ' $QTEST $N_TIMING '1000 W1e-13 D6' 'QJ' fi log log ============================ log "== Time for merging nearly cubical points" log ============================ if [[ $TIME_MERGE == 1 ]]; then # [2015-2019] D2 no errors, somewhat slower CPU # [2015-2019] D3 no errors, similar CPU # [2015-2019] D4 no vs. 1+20x, varied CPU # [2015-2019] D5 1 vs. 1 errors, similar CPU # [2015-2019] D6 no errors, similar CPU $QTEST $N_TIMING '1000000 W1e-13 D2' '' $QTEST $N_TIMING '1000000 W1e-13 D3' '' $QTEST $N_TIMING '100000 W1e-13 D4' 'Q12' $QTEST $N_TIMING '2000 W1e-13 D5' 'Q12' $QTEST $N_TIMING '500 W1e-13 D6' '' fi log log ============================ log "== Time for Delaunay triangulation of random points" log "== qh_findbesthorizon, qh_distplane, qh_update_vertexneighbors_cone, qh_makenew_simplicial" log ============================ if [[ $TIME_DELAUNAY == 1 ]]; then # [2015-2019] D2 no errors, similar CPU # [2015-2019] D3 no errors, similar CPU # [2015-2019] D4 no errors, 5% slower CPU # [2015-2019] D5 no errors, 5% slower CPU # [2015-2019] D6 no errors, 10% slower CPU $QTEST $N_TIMING '100000 D2' 'd Qbb Qz' $QTEST $N_TIMING '50000 D3' 'd Qbb Qz' $QTEST $N_TIMING '10000 D4' 'd Qbb Qz' $QTEST $N_TIMING '1000 D5' 'd Qbb Qz' $QTEST $N_TIMING '200 D6' 'd Qbb Qz' fi if [[ $TIME_REGULAR_MESH == 1 ]]; then log log ==================== log "== Time for Delaunay triangulation of regular mesh, integer coordinates" log ==================== set -v # [2015-2019] D2 no errors, similar CPU # [2015-2019] D3 no errors, 5% slower CPU # [2015-2019] D4 no errors, 5% slower CPU # [2015-2019] D5 no errors, 5% slower CPU # [2015-2019] D6 no errors, somewhat slower CPU $QTEST $N_TIMING "100000 M3,4 z D2" "QR3 d Qt Qbb" $QTEST $N_TIMING "20000 M3,4,5 z D3" "QR3 d Qt Qbb" $QTEST $N_TIMING "5000 M3,4,5 z D4" "QR3 d Qt Qbb" $QTEST $N_TIMING "1500 M3,4,5 z D5" "QR3 d Qt Qbb" $QTEST $N_TIMING "500 M3,4,5 z D6" "QR3 d Qt Qbb" log log ==================== log "== Time for Voronoi diagram of regular mesh" log ==================== # [2015-2019] D2 no errors, somewhat faster CPU # [2015-2019] D3 no errors, 5% slower CPU # [2015-2019] D4 no errors, 5% slower CPU # [2015-2019] D5 no errors, 5% slower CPU # [2015-2019] D6 no errors, 10% slower CPU $QTEST $N_TIMING "rbox 100000 M3,4 z D2 | $QHULL v Qbb" $QTEST $N_TIMING "rbox 20000 M3,4,5 z | $QHULL v Qbb" $QTEST $N_TIMING "rbox 5000 M3,4,5 z D4 | $QHULL v Qbb" $QTEST $N_TIMING "rbox 1500 M3,4,5 z D5 | $QHULL v Qbb" $QTEST $N_TIMING "rbox 500 M3,4,5 z D6 | $QHULL v Qbb" set +v fi export QH_TEST='' fi # end of N_TIMING test cases # end of q_benchmark qhull-2020.2/eg/q_benchmark-ok.txt0000644060175106010010000063535613706705221015230 0ustar bbarber============================================ == make benchmark ========================== == eg/qtest.sh ========================== ============================================ == Thu, Jun 4, 2020 7:26:49 PM eg/q_benchmark -10 -10 -10 -10 eg/q_benchmark: Temporarily add "$PWD/bin" to $PATH for access to rbox ============================================ == eg/q_benchmark [test] [precision-count] [other-count] [pinched-count] [time-count] == Time and precision benchmarks for qhull ============================================ [jun'20] Many timing figures 5-10% faster than jun'19 results. No change to code 'q_benchmark -10 -10 -10 -10' Thu, Jun 4, 2020 7:26:50 PM # $Id: //main/2019/qhull/eg/q_benchmark-ok.txt#5 $$DateTime: 2020/06/05 16:33:18 $ # $Id: //main/2019/qhull/eg/q_benchmark-ok.txt#5 $$DateTime: 2020/06/05 16:33:18 $ qhull => qhull_r 8.0.0 (2020.1.r 2020/05/29) -rwxr-xr-x 1 bbarber 197121 339968 Jun 4 16:16 /var/tmp/qhull-zip-2020-06-04-16-17/zip/qhull-2020.1/bin/qhull rbox => Version: 2019/11/10 -rwxr-xr-x 1 bbarber 197121 32768 Jun 4 16:16 /var/tmp/qhull-zip-2020-06-04-16-17/zip/qhull-2020.1/bin/rbox MINGW64_NT-10.0-18362 kelwyn 3.0.7-338.x86_64 2019-04-30 21:52 UTC x86_64 Msys Logging to /var/tmp/qhull-zip-2020-06-04-16-17/zip/qhull-2020.1/eg/qhull-benchmark.log and eg/qhull-benchmark-show.log ============================== === N_PRECISION test cases === ============================== == difficult cases for qhull Thu, Jun 4, 2020 7:26:51 PM ==================== == Convex hull of fuzzy cube (large flat facets) ==================== Testing -- rbox 1000000 W1e-13 D2 t1 | qhull Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-864647.log Test -- t1 CPU seconds to compute hull (after input): 0.249 Test -- t2 CPU seconds to compute hull (after input): 0.196 Test -- t3 CPU seconds to compute hull (after input): 0.21 Test -- t4 CPU seconds to compute hull (after input): 0.215 Test -- t5 CPU seconds to compute hull (after input): 0.197 Test -- t6 CPU seconds to compute hull (after input): 0.221 Test -- t7 CPU seconds to compute hull (after input): 0.192 Test -- t8 CPU seconds to compute hull (after input): 0.213 Test -- t9 CPU seconds to compute hull (after input): 0.197 Test -- t10 CPU seconds to compute hull (after input): 0.212 1591313239 Test 10 runs in 28 seconds (ave. 2800 msec) -- rbox 1000000 W1e-13 D2 t1 | qhull Tv Testing -- rbox 500000 W1e-13 D3 t1 | qhull Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-802003.log Test -- t1 CPU seconds to compute hull (after input): 0.565 Test -- t2 CPU seconds to compute hull (after input): 0.572 Test -- t3 CPU seconds to compute hull (after input): 0.508 Test -- t4 CPU seconds to compute hull (after input): 0.485 Test -- t5 CPU seconds to compute hull (after input): 0.504 Test -- t6 CPU seconds to compute hull (after input): 0.574 Test -- t7 CPU seconds to compute hull (after input): 0.486 Test -- t8 CPU seconds to compute hull (after input): 0.517 Test -- t9 CPU seconds to compute hull (after input): 0.505 Test -- t10 CPU seconds to compute hull (after input): 0.541 1591313286 Test 10 runs in 46 seconds (ave. 4600 msec) -- rbox 500000 W1e-13 D3 t1 | qhull Tv Testing -- rbox 10000 W1e-13 D4 t1 | qhull Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-875422.log Test -- t1 QH6347 qhull precision error (qh_mergefacet): wide merge for facet f15532 into f15531 for mergetype 7 (dupridge). maxdist 0 (0.0x) mindist -1.1e-12 (112.6x) vertexdist 0.074 Allow with 'Q12' (allow-wide) Test -- t2 CPU seconds to compute hull (after input): 0.134 Test -- t3 CPU seconds to compute hull (after input): 0.086 Test -- t4 CPU seconds to compute hull (after input): 0.123 Test -- t5 CPU seconds to compute hull (after input): 0.09 Test -- t6 CPU seconds to compute hull (after input): 0.115 Test -- t7 CPU seconds to compute hull (after input): 0.084 Test -- t8 CPU seconds to compute hull (after input): 0.103 Test -- t9 CPU seconds to compute hull (after input): 0.099 Test -- t10 CPU seconds to compute hull (after input): 0.094 1591313292 Test 10 runs in 5 seconds (ave. 500 msec) -- rbox 10000 W1e-13 D4 t1 | qhull Tv Testing -- rbox 2000 W1e-13 D5 t1 | qhull Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-76284.log Test -- t1 CPU seconds to compute hull (after input): 0.532 Test -- t2 CPU seconds to compute hull (after input): 0.479 Test -- t3 QH6347 qhull precision error (qh_mergefacet): wide merge for facet f75175 into f75221 for mergetype 7 (dupridge). maxdist 0 (0.0x) mindist -1.6e-12 (96.1x) vertexdist 0.048 Allow with 'Q12' (allow-wide) Maximum distance of point above facet: 2.1e-13 (12.8x) Test -- t4 CPU seconds to compute hull (after input): 0.495 Test -- t5 CPU seconds to compute hull (after input): 0.47 Test -- t6 CPU seconds to compute hull (after input): 0.612 Test -- t7 CPU seconds to compute hull (after input): 0.529 Test -- t8 QH6271 qhull topology error (qh_check_dupridge): wide merge (100.6x wider) due to dupridge between f23261 and f23245 (vertex dist 0.16), merge dist 2e-12, while processing p54 Test -- t9 CPU seconds to compute hull (after input): 0.558 Test -- t10 CPU seconds to compute hull (after input): 0.488 1591313301 Test 10 runs in 8 seconds (ave. 800 msec) -- rbox 2000 W1e-13 D5 t1 | qhull Tv Testing -- rbox 1000 W1e-13 D6 t1 | qhull Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-411054.log Test -- t1 CPU seconds to compute hull (after input): 2.168 Test -- t2 QH6271 qhull topology error (qh_check_dupridge): wide merge (78677624350.8x wider) due to dupridge between f372429 and f372158 (vertex dist 0.48), merge dist 0.011, while processing p166 Test -- t3 CPU seconds to compute hull (after input): 1.993 Test -- t4 CPU seconds to compute hull (after input): 2.038 Test -- t5 CPU seconds to compute hull (after input): 1.961 Test -- t6 CPU seconds to compute hull (after input): 2.044 Test -- t7 CPU seconds to compute hull (after input): 2.055 Test -- t8 CPU seconds to compute hull (after input): 2.153 Test -- t9 CPU seconds to compute hull (after input): 1.98 Test -- t10 CPU seconds to compute hull (after input): 2.067 1591313330 Test 10 runs in 28 seconds (ave. 2800 msec) -- rbox 1000 W1e-13 D6 t1 | qhull Tv ==================== == narrow lense ==================== Testing -- rbox 1000000 L100000 s G1e-6 D2 t1 | qhull Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-881887.log Test -- t1 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.175 Test -- t2 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.17 Test -- t3 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.184 Test -- t4 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.207 Test -- t5 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.174 Test -- t6 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.185 Test -- t7 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.227 Test -- t8 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.195 Test -- t9 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.181 Test -- t10 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.233 1591313354 Test 10 runs in 23 seconds (ave. 2300 msec) -- rbox 1000000 L100000 s G1e-6 D2 t1 | qhull Tv Testing -- rbox 10000 L100000 s G1e-6 D3 t1 | qhull Q12 Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-685335.log Test -- t1 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.574 Test -- t2 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.555 Test -- t3 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.572 Test -- t4 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.578 Maximum distance of point above facet: 8.3e-14 (14.9x) Test -- t5 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.56 Test -- t6 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.594 Test -- t7 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.601 Test -- t8 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.623 Test -- t9 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.633 Maximum distance of point above facet: 1.1e-13 (19.4x) Test -- t10 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.599 1591313373 Test 10 runs in 18 seconds (ave. 1800 msec) -- rbox 10000 L100000 s G1e-6 D3 t1 | qhull Q12 Tv Testing -- rbox 5000 L100000 s G1e-6 D4 t1 | qhull Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-287921.log Test -- t1 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.493 Test -- t2 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.508 Test -- t3 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.506 Test -- t4 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 1.305 Test -- t5 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.458 Test -- t6 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 1.343 Maximum distance of point above facet: 2.1e-13 (21.0x) Test -- t7 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.556 Test -- t8 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.459 Test -- t9 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.462 Test -- t10 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.488 1591313394 Test 10 runs in 20 seconds (ave. 2000 msec) -- rbox 5000 L100000 s G1e-6 D4 t1 | qhull Tv Testing -- rbox 1000 L100000 s G1e-6 D5 t1 | qhull Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-490938.log Test -- t1 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.161 Test -- t2 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.165 Test -- t3 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.173 Test -- t4 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.17 Test -- t5 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.164 Test -- t6 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.162 Test -- t7 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.165 Test -- t8 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.172 Test -- t9 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.17 Test -- t10 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.173 1591313401 Test 10 runs in 6 seconds (ave. 600 msec) -- rbox 1000 L100000 s G1e-6 D5 t1 | qhull Tv Testing -- rbox 400 L100000 s G1e-6 D6 t1 | qhull Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-225277.log Test -- t1 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.354 Test -- t2 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.364 Test -- t3 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.4 Test -- t4 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.346 Test -- t5 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.354 Test -- t6 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.327 Test -- t7 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.355 Test -- t8 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.353 Test -- t9 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.318 Test -- t10 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.352 1591313409 Test 10 runs in 7 seconds (ave. 700 msec) -- rbox 400 L100000 s G1e-6 D6 t1 | qhull Tv ==================== == cone ==================== Testing -- rbox 100000 s Z1 G1e-13 D2 t1 | qhull Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-26570.log Test -- t1 CPU seconds to compute hull (after input): 0.026 Test -- t2 CPU seconds to compute hull (after input): 0.024 Test -- t3 CPU seconds to compute hull (after input): 0.042 Test -- t4 CPU seconds to compute hull (after input): 0.027 Test -- t5 CPU seconds to compute hull (after input): 0.032 Test -- t6 CPU seconds to compute hull (after input): 0.02 Test -- t7 CPU seconds to compute hull (after input): 0.02 Test -- t8 CPU seconds to compute hull (after input): 0.019 Test -- t9 CPU seconds to compute hull (after input): 0.02 Test -- t10 CPU seconds to compute hull (after input): 0.029 1591313414 Test 10 runs in 4 seconds (ave. 400 msec) -- rbox 100000 s Z1 G1e-13 D2 t1 | qhull Tv Testing -- rbox 10000 s Z1 G1e-13 D3 t1 | qhull Q12 Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-160478.log Test -- t1 QH7088 Qhull precision warning: in post-processing (qh_check_maxout) p8 for f18922 is 1.7e-12 above hidden facet f41175 nearest vertices 0.0001 QH7088 Qhull precision warning: in post-processing (qh_check_maxout) p11 for f11008 is 1.7e-12 above hidden facet f41175 nearest vertices 0.0001 QH7088 Qhull precision warning: in post-processing (qh_check_maxout) p27 for f29977 is 1.7e-12 above hidden facet f41175 nearest vertices 0.0001 QH7088 Qhull precision warning: in post-processing (qh_check_maxout) p73 for f29524 is 1.7e-12 above hidden facet f41175 nearest vertices 0.0001 QH7088 Qhull precision warning: in post-processing (qh_check_maxout) p148 for f29629 is 1.7e-12 above hidden facet f41175 nearest vertices 0.0001 QH7088 Qhull precision warning: in post-processing (qh_check_maxout) p273 for f19304 is 1.7e-12 above hidden facet f41175 nearest vertices 0.0001 QH7088 Qhull precision warning: in post-processing (qh_check_maxout) p1065 for f11292 is 1.7e-12 above hidden facet f41175 nearest vertices 0.0001 QH7088 Qhull precision warning: in post-processing (qh_check_maxout) p1189 for f11280 is 1.7e-12 above hidden facet f41175 nearest vertices 0.0001 QH7088 Qhull precision warning: in post-processing (qh_check_maxout) p2536 for f29640 is 1.7e-12 above hidden facet f41175 nearest vertices 0.0001 CPU seconds to compute hull (after input): 0.505 Maximum distance of point above facet: 1.7e-12 (308.8x) Test -- t2 CPU seconds to compute hull (after input): 0.467 Test -- t3 CPU seconds to compute hull (after input): 1.49 Maximum distance of point above facet: 8.5e-14 (15.2x) Test -- t4 CPU seconds to compute hull (after input): 0.533 Test -- t5 CPU seconds to compute hull (after input): 0.647 Test -- t6 CPU seconds to compute hull (after input): 0.47 Test -- t7 QH7088 Qhull precision warning: in post-processing (qh_check_maxout) p21 for f56395 is 1.2e-11 above hidden facet f84424 nearest vertices 6.2e-05 QH7088 Qhull precision warning: in post-processing (qh_check_maxout) p36 for f109744 is 1.2e-11 above hidden facet f84424 nearest vertices 6.2e-05 QH7088 Qhull precision warning: in post-processing (qh_check_maxout) p217 for f104110 is 1.2e-11 above hidden facet f84424 nearest vertices 6.2e-05 QH7088 Qhull precision warning: in post-processing (qh_check_maxout) p564 for f89945 is 1.2e-11 above hidden facet f84424 nearest vertices 6.2e-05 QH7088 Qhull precision warning: in post-processing (qh_check_maxout) p2226 for f56971 is 1.2e-11 above hidden facet f84424 nearest vertices 6.2e-05 QH7088 Qhull precision warning: in post-processing (qh_check_maxout) p8038 for f89945 is 1.2e-11 above hidden facet f84424 nearest vertices 6.2e-05 QH7088 Qhull precision warning: in post-processing (qh_check_maxout) p9660 for f104202 is 1.2e-11 above hidden facet f84424 nearest vertices 6.2e-05 CPU seconds to compute hull (after input): 2.016 Maximum distance of point above facet: 1.2e-11 (2123.2x) Test -- t8 CPU seconds to compute hull (after input): 1.515 Maximum distance of point above facet: 5.9e-13 (106.8x) Test -- t9 CPU seconds to compute hull (after input): 0.513 Maximum distance of point above facet: 1.9e-13 (33.5x) Test -- t10 CPU seconds to compute hull (after input): 0.435 1591313440 Test 10 runs in 26 seconds (ave. 2600 msec) -- rbox 10000 s Z1 G1e-13 D3 t1 | qhull Q12 Tv Testing -- rbox 2000 s Z1 G1e-13 D4 t1 | qhull Q12 Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-564357.log Test -- t1 CPU seconds to compute hull (after input): 3.213 Test -- t2 CPU seconds to compute hull (after input): 3.322 Maximum distance of point above facet: 2.5e-13 (24.5x) Test -- t3 CPU seconds to compute hull (after input): 2.259 Test -- t4 CPU seconds to compute hull (after input): 0.816 Test -- t5 CPU seconds to compute hull (after input): 1.606 Test -- t6 CPU seconds to compute hull (after input): 0.631 Test -- t7 CPU seconds to compute hull (after input): 1.152 Test -- t8 CPU seconds to compute hull (after input): 1.7 Test -- t9 CPU seconds to compute hull (after input): 1.554 Test -- t10 CPU seconds to compute hull (after input): 0.85 1591313461 Test 10 runs in 20 seconds (ave. 2000 msec) -- rbox 2000 s Z1 G1e-13 D4 t1 | qhull Q12 Tv Testing -- rbox 1000 s Z1 G1e-13 D5 t1 | qhull Q12 Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-767374.log Test -- t1 CPU seconds to compute hull (after input): 0.509 Test -- t2 CPU seconds to compute hull (after input): 1.121 Test -- t3 QH6271 qhull topology error (qh_check_dupridge): wide merge (230539152422.1x wider) due to dupridge between f44488 and f44473 (vertex dist 0.061), merge dist 0.032, while processing p101 CPU seconds to compute hull (after input): 0.539 Maximum distance of vertex below facet: -0.032 (1972076014119.1x) Test -- t4 CPU seconds to compute hull (after input): 0.602 Test -- t5 CPU seconds to compute hull (after input): 0.405 Test -- t6 QH6271 qhull topology error (qh_check_dupridge): wide merge (35319340797.5x wider) due to dupridge between f39960 and f39992 (vertex dist 0.072), merge dist 0.0062, while processing p696 CPU seconds to compute hull (after input): 0.667 Maximum distance of point above facet: 0.00026 (16181662784.3x) Maximum distance of vertex below facet: -0.0018 (109549989077.6x) Test -- t7 CPU seconds to compute hull (after input): 0.544 Test -- t8 CPU seconds to compute hull (after input): 0.51 Test -- t9 CPU seconds to compute hull (after input): 0.4 Test -- t10 CPU seconds to compute hull (after input): 0.536 1591313472 Test 10 runs in 10 seconds (ave. 1000 msec) -- rbox 1000 s Z1 G1e-13 D5 t1 | qhull Q12 Tv Testing -- rbox 400 s Z1 G1e-13 D6 t1 | qhull Q12 Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-635621.log Test -- t1 CPU seconds to compute hull (after input): 1.015 Test -- t2 CPU seconds to compute hull (after input): 2.154 Test -- t3 QH6271 qhull topology error (qh_check_dupridge): wide merge (210507823427.9x wider) due to dupridge between f5405 and f5520 (vertex dist 0.19), merge dist 0.037, while processing p318 CPU seconds to compute hull (after input): 5.686 Test -- t4 CPU seconds to compute hull (after input): 0.884 Test -- t5 CPU seconds to compute hull (after input): 2.565 Test -- t6 QH6271 qhull topology error (qh_check_dupridge): wide merge (271634975.9x wider) due to dupridge between f96869 and f97564 (vertex dist 0.091), merge dist 0.00015, while processing p223 CPU seconds to compute hull (after input): 3.793 Test -- t7 QH6271 qhull topology error (qh_check_dupridge): wide merge (3447376779583.9x wider) due to dupridge between f2795 and f2801 (vertex dist 0.17), merge dist 0.16, while processing p85 QH6271 qhull topology error (qh_check_dupridge): wide merge (13981974127.2x wider) due to dupridge between f89269 and f89268 (vertex dist 0.16), merge dist 0.011, while processing p296 CPU seconds to compute hull (after input): 2.05 Maximum distance of point above facet: 0.0033 (134133559778.9x) Maximum distance of vertex below facet: -0.0067 (273160548745.7x) Test -- t8 QH6271 qhull topology error (qh_check_dupridge): wide merge (114810705647.7x wider) due to dupridge between f2488 and f2437 (vertex dist 0.23), merge dist 0.0039, while processing p150 QH6271 qhull topology error (qh_check_dupridge): wide merge (962458297491.5x wider) due to dupridge between f8964 and f9014 (vertex dist 0.21), merge dist 0.074, while processing p351 CPU seconds to compute hull (after input): 4.798 Test -- t9 QH6271 qhull topology error (qh_check_dupridge): wide merge (24322794639.0x wider) due to dupridge between f10036 and f10102 (vertex dist 0.13), merge dist 0.0053, while processing p237 QH6271 qhull topology error (qh_check_dupridge): wide merge (13665015104.4x wider) due to dupridge between f25745 and f25744 (vertex dist 0.12), merge dist 0.013, while processing p259 QH6271 qhull topology error (qh_check_dupridge): wide merge (5189398520.6x wider) due to dupridge between f27688 and f27087 (vertex dist 0.12), merge dist 0.005, while processing p60 CPU seconds to compute hull (after input): 2.728 Test -- t10 CPU seconds to compute hull (after input): 1.507 1591313509 Test 10 runs in 36 seconds (ave. 3600 msec) -- rbox 400 s Z1 G1e-13 D6 t1 | qhull Q12 Tv ========================== === N_OTHER test cases === ========================== ==================== == Delaunay triangulation of fuzzy circle (large, narrow disk) == No Qbb, highly degenerate due to narrow disk of two cospherical sets of points ==================== Testing -- rbox 10000 s W1e-13 D2 t1 | qhull d Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-374270.log Test -- t1 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6347 qhull precision error (qh_mergefacet): wide merge for facet f13593 into f5532 for mergetype 6 (flip). maxdist 0 (0.0x) mindist -4.3e-11 (7726.8x) vertexdist 0.00042 Allow with 'Q12' (allow-wide) Test -- t2 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.451 Maximum distance of point above facet: 8e-12 (1437.2x) Test -- t3 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6347 qhull precision error (qh_mergefacet): wide merge for facet f5431 into f3337 for mergetype 6 (flip). maxdist 0 (0.0x) mindist -3.4e-12 (614.3x) vertexdist 0.011 Allow with 'Q12' (allow-wide) Maximum distance of vertex below facet: -2.5e-13 (45.3x) Test -- t4 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.453 Maximum distance of point above facet: 2.5e-12 (455.3x) Test -- t5 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.298 Maximum distance of point above facet: 1.8e-12 (318.7x) Test -- t6 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6347 qhull precision error (qh_mergefacet): wide merge for facet f2694 into f1989 for mergetype 6 (flip). maxdist 0 (0.0x) mindist -5.5e-12 (986.3x) vertexdist 0.025 Allow with 'Q12' (allow-wide) Maximum distance of point above facet: 7.8e-14 (14.0x) Maximum distance of vertex below facet: -1.3e-13 (23.1x) Test -- t7 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.504 Maximum distance of point above facet: 2.6e-12 (460.3x) Test -- t8 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 1.073 Maximum distance of point above facet: 3.4e-13 (61.2x) Test -- t9 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.422 Maximum distance of point above facet: 2.2e-12 (400.0x) Test -- t10 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7086 Qhull precision warning: repartition coplanar point p3137 from f19949 as an outside point above hidden facet f19948 dist 2.9e-12 nearest vertices 3.4e-06 QH7086 Qhull precision warning: repartition coplanar point p8476 from f28083 as an outside point above hidden facet f28083 dist 5.7e-12 nearest vertices 1.3e-06 QH7088 Qhull precision warning: in post-processing (qh_check_maxout) p2710 for f2993 is 4.4e-12 above hidden facet f36150 nearest vertices 5.1e-07 QH6297 Qhull precision error (qh_check_maxout): large increase in qh.max_outside during post-processing dist 4.4e-12 (102.2x). See warning QH0032/QH0033. Allow with 'Q12' (allow-wide) and 'Pp' Maximum distance of point above facet: 4.4e-12 (797.8x) 1591313524 Test 10 runs in 14 seconds (ave. 1400 msec) -- rbox 10000 s W1e-13 D2 t1 | qhull d Tv Testing -- rbox 2000 s W1e-13 D3 t1 | qhull d Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-842948.log Test -- t1 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6347 qhull precision error (qh_mergefacet): wide merge for facet f5159 into f4940 for mergetype 6 (flip). maxdist 0 (0.0x) mindist -3.2e-11 (3209.7x) vertexdist 0.092 Allow with 'Q12' (allow-wide) Maximum distance of point above facet: 2.2e-13 (22.1x) Maximum distance of vertex below facet: -2.2e-13 (21.4x) Test -- t2 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.848 Maximum distance of point above facet: 4.2e-12 (417.7x) Test -- t3 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6347 qhull precision error (qh_mergefacet): wide merge for facet f24055 into f21217 for mergetype 6 (flip). maxdist 0 (0.0x) mindist -1.6e-11 (1628.3x) vertexdist 0.013 Allow with 'Q12' (allow-wide) Maximum distance of point above facet: 1.7e-12 (171.9x) Test -- t4 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6347 qhull precision error (qh_mergefacet): wide merge for facet f5422 into f3326 for mergetype 6 (flip). maxdist 0 (0.0x) mindist -5.5e-12 (545.2x) vertexdist 0.056 Allow with 'Q12' (allow-wide) Maximum distance of point above facet: 4.8e-13 (47.8x) Maximum distance of vertex below facet: -3e-13 (29.6x) Test -- t5 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6347 qhull precision error (qh_mergefacet): wide merge for facet f6567 into f5543 for mergetype 6 (flip). maxdist 0 (0.0x) mindist -1.9e-12 (186.6x) vertexdist 0.14 Allow with 'Q12' (allow-wide) Maximum distance of point above facet: 3.2e-12 (317.3x) Maximum distance of vertex below facet: -8.1e-13 (80.2x) Test -- t6 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7086 Qhull precision warning: repartition coplanar point p947 from f5509 as an outside point above hidden facet f5521 dist 1.9e-12 nearest vertices 0.0032 QH6347 qhull precision error (qh_mergefacet): wide merge for facet f6036 into f6042 for mergetype 6 (flip). maxdist 1.7e-12 (166.5x) mindist 0 (-0.0x) vertexdist 0.12 Allow with 'Q12' (allow-wide) Maximum distance of vertex below facet: -2e-13 (19.6x) Test -- t7 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6347 qhull precision error (qh_mergefacet): wide merge for facet f16711 into f13078 for mergetype 6 (flip). maxdist 0 (0.0x) mindist -6.2e-12 (615.7x) vertexdist 0.033 Allow with 'Q12' (allow-wide) Maximum distance of vertex below facet: -8.5e-13 (84.1x) Test -- t8 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6347 qhull precision error (qh_mergefacet): wide merge for facet f20687 into f19136 for mergetype 6 (flip). maxdist 0 (0.0x) mindist -9.5e-12 (947.4x) vertexdist 0.024 Allow with 'Q12' (allow-wide) Maximum distance of point above facet: 8.2e-12 (809.7x) Maximum distance of vertex below facet: -2.4e-13 (24.2x) Test -- t9 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6347 qhull precision error (qh_mergefacet): wide merge for facet f991 into f4726 for mergetype 3 (concave). maxdist 1.5e-13 (15.4x) mindist -1.2e-12 (123.4x) vertexdist 0.023 Allow with 'Q12' (allow-wide) Test -- t10 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6347 qhull precision error (qh_mergefacet): wide merge for facet f2500 into f1666 for mergetype 6 (flip). maxdist 0 (0.0x) mindist -5.5e-12 (541.1x) vertexdist 0.03 Allow with 'Q12' (allow-wide) Maximum distance of point above facet: 7.8e-13 (77.8x) Maximum distance of vertex below facet: -3e-13 (29.6x) 1591313528 Test 10 runs in 4 seconds (ave. 400 msec) -- rbox 2000 s W1e-13 D3 t1 | qhull d Tv Testing -- rbox 1000 s W1e-13 D4 t1 | qhull d Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-510333.log Test -- t1 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.75 Maximum distance of point above facet: 3.5e-13 (21.2x) Test -- t2 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 1.405 Maximum distance of point above facet: 2e-12 (125.0x) Test -- t3 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6347 qhull precision error (qh_mergefacet): wide merge for facet f71887 into f69472 for mergetype 6 (flip). maxdist 0 (0.0x) mindist -2.7e-12 (165.0x) vertexdist 0.097 Allow with 'Q12' (allow-wide) Maximum distance of point above facet: 1.6e-12 (97.5x) Maximum distance of vertex below facet: -1e-12 (63.5x) Test -- t4 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.599 Maximum distance of point above facet: 2e-13 (12.4x) Test -- t5 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6347 qhull precision error (qh_mergefacet): wide merge for facet f52894 into f47417 for mergetype 6 (flip). maxdist 0 (0.0x) mindist -1.7e-12 (103.0x) vertexdist 0.075 Allow with 'Q12' (allow-wide) Maximum distance of point above facet: 5.7e-13 (35.6x) Maximum distance of vertex below facet: -3.9e-13 (24.6x) Test -- t6 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.754 Maximum distance of point above facet: 2.1e-13 (12.7x) Test -- t7 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.781 Maximum distance of point above facet: 2.6e-13 (16.0x) Test -- t8 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6347 qhull precision error (qh_mergefacet): wide merge for facet f71726 into f40542 for mergetype 6 (flip). maxdist 0 (0.0x) mindist -2.1e-12 (128.7x) vertexdist 0.075 Allow with 'Q12' (allow-wide) Maximum distance of point above facet: 2.4e-12 (149.9x) Maximum distance of vertex below facet: -5.8e-13 (35.9x) Test -- t9 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.881 Maximum distance of point above facet: 2.7e-13 (16.8x) Test -- t10 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.72 Maximum distance of point above facet: 6.6e-13 (40.9x) 1591313540 Test 10 runs in 11 seconds (ave. 1100 msec) -- rbox 1000 s W1e-13 D4 t1 | qhull d Tv Testing -- rbox 200 s W1e-13 D5 t1 | qhull d Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-378580.log Test -- t1 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.362 Test -- t2 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.258 Test -- t3 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6227 qhull topology error: Only 7 facets remain. The input is too degenerate or the convexity constraints are too strong. Maximum distance of point above facet: 3.7e-13 (15.2x) Maximum distance of vertex below facet: -9.9e-13 (40.8x) Test -- t4 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7086 Qhull precision warning: repartition coplanar point p152 from f29818 as an outside point above hidden facet f24789 dist 1.6e-11 nearest vertices 0.33 CPU seconds to compute hull (after input): 0.527 Maximum distance of point above facet: 9.2e-13 (37.7x) Test -- t5 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.539 Test -- t6 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.313 Test -- t7 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.406 Test -- t8 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.228 Test -- t9 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.399 Test -- t10 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.26 1591313546 Test 10 runs in 6 seconds (ave. 600 msec) -- rbox 200 s W1e-13 D5 t1 | qhull d Tv Testing -- rbox 100 s W1e-13 D6 t1 | qhull d Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-579442.log Test -- t1 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6227 qhull topology error: Only 8 facets remain. The input is too degenerate or the convexity constraints are too strong. Maximum distance of point above facet: 8.5e-13 (26.9x) Maximum distance of vertex below facet: -7.6e-13 (24.1x) Test -- t2 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6227 qhull topology error: Only 8 facets remain. The input is too degenerate or the convexity constraints are too strong. Maximum distance of point above facet: 6e-13 (19.1x) Maximum distance of vertex below facet: -9.5e-13 (30.0x) Test -- t3 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6227 qhull topology error: Only 8 facets remain. The input is too degenerate or the convexity constraints are too strong. Maximum distance of point above facet: 5.2e-13 (15.6x) Maximum distance of vertex below facet: -1.2e-12 (36.9x) Test -- t4 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6227 qhull topology error: Only 8 facets remain. The input is too degenerate or the convexity constraints are too strong. Maximum distance of point above facet: 3.9e-12 (129.6x) Maximum distance of vertex below facet: -1e-12 (33.3x) Test -- t5 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6227 qhull topology error: Only 8 facets remain. The input is too degenerate or the convexity constraints are too strong. Maximum distance of point above facet: 6.9e-13 (21.4x) Maximum distance of vertex below facet: -7.9e-13 (24.8x) Test -- t6 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6227 qhull topology error: Only 8 facets remain. The input is too degenerate or the convexity constraints are too strong. Maximum distance of point above facet: 6.1e-13 (18.2x) Maximum distance of vertex below facet: -9.5e-13 (28.3x) Test -- t7 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.487 Test -- t8 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6227 qhull topology error: Only 8 facets remain. The input is too degenerate or the convexity constraints are too strong. Maximum distance of vertex below facet: -1.3e-12 (41.0x) Test -- t9 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6227 qhull topology error: Only 8 facets remain. The input is too degenerate or the convexity constraints are too strong. Maximum distance of vertex below facet: -6.7e-13 (21.0x) Test -- t10 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6227 qhull topology error: Only 8 facets remain. The input is too degenerate or the convexity constraints are too strong. Maximum distance of point above facet: 5e-13 (16.1x) Maximum distance of vertex below facet: -1.4e-12 (45.7x) 1591313551 Test 10 runs in 5 seconds (ave. 500 msec) -- rbox 100 s W1e-13 D6 t1 | qhull d Tv =========================================================== === N_PINCHED test cases for Q14-merge-pinched-vertices === =========================================================== ==================== == Convex hull of fuzzy cube with point pairs (large flat facets) ==================== Testing -- rbox 1000000 W1e-13 C1,2e-13 D2 t1 | qhull Q14 Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-246827.log Test -- t1 CPU seconds to compute hull (after input): 0.332 Test -- t2 CPU seconds to compute hull (after input): 0.309 Test -- t3 CPU seconds to compute hull (after input): 0.343 Test -- t4 CPU seconds to compute hull (after input): 0.314 Test -- t5 CPU seconds to compute hull (after input): 0.307 Test -- t6 CPU seconds to compute hull (after input): 0.301 Test -- t7 CPU seconds to compute hull (after input): 0.295 Test -- t8 CPU seconds to compute hull (after input): 0.347 Test -- t9 CPU seconds to compute hull (after input): 0.293 Test -- t10 CPU seconds to compute hull (after input): 0.279 1591313609 Test 10 runs in 57 seconds (ave. 5700 msec) -- rbox 1000000 W1e-13 C1,2e-13 D2 t1 | qhull Q14 Tv Testing -- rbox 500000 W1e-13 C1,2e-13 D3 t1 | qhull Q14 Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-188493.log Test -- t1 CPU seconds to compute hull (after input): 0.641 Test -- t2 CPU seconds to compute hull (after input): 0.576 Test -- t3 CPU seconds to compute hull (after input): 0.487 Test -- t4 CPU seconds to compute hull (after input): 0.492 Test -- t5 CPU seconds to compute hull (after input): 0.508 Test -- t6 CPU seconds to compute hull (after input): 0.603 Test -- t7 CPU seconds to compute hull (after input): 0.556 Test -- t8 CPU seconds to compute hull (after input): 0.558 Test -- t9 CPU seconds to compute hull (after input): 0.605 Test -- t10 CPU seconds to compute hull (after input): 0.53 1591313735 Test 10 runs in 126 seconds (ave. 12600 msec) -- rbox 500000 W1e-13 C1,2e-13 D3 t1 | qhull Q14 Tv Testing -- rbox 20000 W1e-13 C1,2e-13 D4 t1 | qhull Q14 Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-940072.log Test -- t1 CPU seconds to compute hull (after input): 0.148 Test -- t2 CPU seconds to compute hull (after input): 0.126 Test -- t3 CPU seconds to compute hull (after input): 0.147 Test -- t4 CPU seconds to compute hull (after input): 0.178 Test -- t5 CPU seconds to compute hull (after input): 0.178 Test -- t6 CPU seconds to compute hull (after input): 0.14 Test -- t7 CPU seconds to compute hull (after input): 0.169 Test -- t8 CPU seconds to compute hull (after input): 0.144 Test -- t9 CPU seconds to compute hull (after input): 0.141 Test -- t10 CPU seconds to compute hull (after input): 0.145 1591313766 Test 10 runs in 30 seconds (ave. 3000 msec) -- rbox 20000 W1e-13 C1,2e-13 D4 t1 | qhull Q14 Tv Testing -- rbox 2000 W1e-13 C1,2e-13 D5 t1 | qhull Q14 Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-944382.log Test -- t1 QH6347 qhull precision error (qh_mergefacet): wide merge for facet f113177 into f113175 for mergetype 7 (dupridge). maxdist 0 (0.0x) mindist -1.5e-12 (92.2x) vertexdist 0.16 Allow with 'Q12' (allow-wide) Maximum distance of point above facet: 1.8e-13 (11.2x) Test -- t2 CPU seconds to compute hull (after input): 0.438 Test -- t3 QH7085 Qhull precision warning: repartition coplanar point p2235 from f117398 as an outside point above twisted facet f115796 dist 0.00029 nearest vertices 2.1e-13 CPU seconds to compute hull (after input): 0.389 Test -- t4 QH7085 Qhull precision warning: repartition coplanar point p2331 from f138633 as an outside point above twisted facet f138769 dist 0.0037 nearest vertices 2.2e-13 QH7085 Qhull precision warning: repartition coplanar point p2331 from f142401 as an outside point above twisted facet f142401 dist 0.0037 nearest vertices 2.2e-13 CPU seconds to compute hull (after input): 0.504 Test -- t5 CPU seconds to compute hull (after input): 0.438 Test -- t6 CPU seconds to compute hull (after input): 0.407 Maximum distance of point above facet: 1.7e-13 (10.5x) Test -- t7 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r15110 and r15115. Nearest v591 and v666 dist 0.38 (25519640968939.1x) Test -- t8 CPU seconds to compute hull (after input): 0.459 Maximum distance of point above facet: 2e-13 (12.4x) Test -- t9 CPU seconds to compute hull (after input): 0.482 Maximum distance of point above facet: 1.9e-13 (11.5x) Maximum distance of vertex below facet: -1.9e-13 (11.7x) Test -- t10 CPU seconds to compute hull (after input): 0.425 1591313780 Test 10 runs in 13 seconds (ave. 1300 msec) -- rbox 2000 W1e-13 C1,2e-13 D5 t1 | qhull Q14 Tv Testing -- rbox 500 W1e-13 C1,2e-13 D6 t1 | qhull Q14 Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-413060.log Test -- t1 CPU seconds to compute hull (after input): 1.246 Maximum distance of point above facet: 3e-13 (12.3x) Maximum distance of vertex below facet: -2.9e-13 (11.9x) Test -- t2 CPU seconds to compute hull (after input): 1.228 Maximum distance of point above facet: 3.1e-13 (12.7x) Maximum distance of vertex below facet: -2.6e-13 (10.4x) Test -- t3 QH7085 Qhull precision warning: repartition coplanar point p512 from f323305 as an outside point above twisted facet f322364 dist 0.00083 nearest vertices 2.9e-13 CPU seconds to compute hull (after input): 1.232 Maximum distance of point above facet: 2.8e-13 (11.5x) Maximum distance of vertex below facet: -2.6e-13 (10.7x) Test -- t4 QH6271 qhull topology error (qh_check_dupridge): wide merge (476654024777.9x wider) due to dupridge between f307863 and f307761 (vertex dist 2.6e-13), merge dist 0.092, while processing p516 Test -- t5 CPU seconds to compute hull (after input): 1.118 Maximum distance of point above facet: 2.8e-13 (11.3x) Maximum distance of vertex below facet: -2.7e-13 (11.1x) Test -- t6 CPU seconds to compute hull (after input): 1.231 Maximum distance of point above facet: 2.9e-13 (12.0x) Maximum distance of vertex below facet: -2.9e-13 (11.8x) Test -- t7 QH7085 Qhull precision warning: repartition coplanar point p73 from f185396 as an outside point above twisted facet f161746 dist 0.00022 nearest vertices 2.3e-13 CPU seconds to compute hull (after input): 1.162 Test -- t8 QH6271 qhull topology error (qh_check_dupridge): wide merge (33125155946.5x wider) due to dupridge between f313208 and f313293 (vertex dist 1.4e-13), merge dist 0.016, while processing p504 Maximum distance of point above facet: 4.9e-13 (19.7x) Maximum distance of vertex below facet: -3.8e-13 (15.3x) Test -- t9 CPU seconds to compute hull (after input): 1.196 Maximum distance of point above facet: 2.9e-13 (11.7x) Maximum distance of vertex below facet: -6e-13 (24.2x) Test -- t10 CPU seconds to compute hull (after input): 1.176 Maximum distance of point above facet: 3e-13 (12.1x) Maximum distance of vertex below facet: -3.1e-13 (12.7x) 1591313798 Test 10 runs in 17 seconds (ave. 1700 msec) -- rbox 500 W1e-13 C1,2e-13 D6 t1 | qhull Q14 Tv ==================== == Convex hull of cube with point pairs (large flat facets) ==================== Testing -- rbox 1000000 W0 C1,2e-13 D2 t1 | qhull Q14 Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-15646.log Test -- t1 CPU seconds to compute hull (after input): 0.292 Test -- t2 CPU seconds to compute hull (after input): 0.286 Test -- t3 CPU seconds to compute hull (after input): 0.299 Test -- t4 CPU seconds to compute hull (after input): 0.353 Test -- t5 CPU seconds to compute hull (after input): 0.319 Test -- t6 CPU seconds to compute hull (after input): 0.362 Test -- t7 CPU seconds to compute hull (after input): 0.312 Test -- t8 CPU seconds to compute hull (after input): 0.312 Test -- t9 CPU seconds to compute hull (after input): 0.306 Test -- t10 CPU seconds to compute hull (after input): 0.364 1591313851 Test 10 runs in 52 seconds (ave. 5200 msec) -- rbox 1000000 W0 C1,2e-13 D2 t1 | qhull Q14 Tv Testing -- rbox 100000 W0 C1,2e-13 D3 t1 | qhull Q14 Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-289927.log Test -- t1 CPU seconds to compute hull (after input): 0.08 Test -- t2 CPU seconds to compute hull (after input): 0.112 Test -- t3 CPU seconds to compute hull (after input): 0.082 Test -- t4 CPU seconds to compute hull (after input): 0.093 Test -- t5 CPU seconds to compute hull (after input): 0.099 Test -- t6 CPU seconds to compute hull (after input): 0.099 Test -- t7 CPU seconds to compute hull (after input): 0.082 Test -- t8 CPU seconds to compute hull (after input): 0.091 Test -- t9 CPU seconds to compute hull (after input): 0.087 Test -- t10 CPU seconds to compute hull (after input): 0.094 1591313873 Test 10 runs in 21 seconds (ave. 2100 msec) -- rbox 100000 W0 C1,2e-13 D3 t1 | qhull Q14 Tv Testing -- rbox 5000 W0 C1,2e-13 D4 t1 | qhull Q14 Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-26421.log Test -- t1 QH6347 qhull precision error (qh_mergefacet): wide merge for facet f25732 into f25739 for mergetype 7 (dupridge). maxdist 1.7e-12 (170.7x) mindist 0 (-0.0x) vertexdist 0.077 Allow with 'Q12' (allow-wide) Maximum distance of point above facet: 1.7e-13 (17.0x) Test -- t2 CPU seconds to compute hull (after input): 0.054 Test -- t3 CPU seconds to compute hull (after input): 0.048 Test -- t4 CPU seconds to compute hull (after input): 0.058 Test -- t5 CPU seconds to compute hull (after input): 0.05 Test -- t6 CPU seconds to compute hull (after input): 0.058 Test -- t7 CPU seconds to compute hull (after input): 0.047 Test -- t8 CPU seconds to compute hull (after input): 0.054 Test -- t9 CPU seconds to compute hull (after input): 0.046 Test -- t10 CPU seconds to compute hull (after input): 0.047 1591313879 Test 10 runs in 6 seconds (ave. 600 msec) -- rbox 5000 W0 C1,2e-13 D4 t1 | qhull Q14 Tv Testing -- rbox 1000 W0 C1,2e-13 D5 t1 | qhull Q14 Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-760760.log Test -- t1 QH7085 Qhull precision warning: repartition coplanar point p267 from f75220 as an outside point above twisted facet f75416 dist 0.0034 nearest vertices 2.3e-13 QH7085 Qhull precision warning: repartition coplanar point p267 from f75294 as an outside point above twisted facet f82791 dist 0.0035 nearest vertices 2.3e-13 CPU seconds to compute hull (after input): 0.226 Maximum distance of point above facet: 1.8e-13 (11.1x) Maximum distance of vertex below facet: -1.8e-13 (10.9x) Test -- t2 CPU seconds to compute hull (after input): 0.198 Test -- t3 QH7085 Qhull precision warning: repartition coplanar point p401 from f90444 as an outside point above twisted facet f90433 dist 0.00047 nearest vertices 3.2e-13 CPU seconds to compute hull (after input): 0.177 Maximum distance of point above facet: 2.3e-13 (13.8x) Maximum distance of vertex below facet: -1.8e-13 (11.1x) Test -- t4 CPU seconds to compute hull (after input): 0.208 Test -- t5 CPU seconds to compute hull (after input): 0.243 Test -- t6 CPU seconds to compute hull (after input): 0.211 Maximum distance of point above facet: 2e-13 (12.0x) Test -- t7 CPU seconds to compute hull (after input): 0.205 Test -- t8 CPU seconds to compute hull (after input): 0.194 Test -- t9 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r12609 and r12598. Nearest v498 and v570 dist 0.51 (33702563635476.9x) Test -- t10 CPU seconds to compute hull (after input): 0.19 1591313886 Test 10 runs in 6 seconds (ave. 600 msec) -- rbox 1000 W0 C1,2e-13 D5 t1 | qhull Q14 Tv Testing -- rbox 500 W0 C1,2e-13 D6 t1 | qhull Q14 Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-495099.log Test -- t1 QH7085 Qhull precision warning: repartition coplanar point p75 from f228039 as an outside point above twisted facet f249986 dist 0.00033 nearest vertices 3.2e-13 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r79874 and r79879. Nearest v324 and v535 dist 0.46 (19985215447239.0x) Test -- t2 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r66254 and r66259. Nearest v20 and v213 dist 0.49 (21557823068697.4x) Maximum distance of point above facet: 5.7e-13 (23.1x) Test -- t3 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r22309 and r22303. Nearest v26 and v290 dist 0.43 (18762058006914.9x) Test -- t4 CPU seconds to compute hull (after input): 1.283 Maximum distance of point above facet: 2.5e-13 (10.1x) Maximum distance of vertex below facet: -3e-13 (12.2x) Test -- t5 CPU seconds to compute hull (after input): 1.132 Maximum distance of vertex below facet: -2.5e-13 (10.0x) Test -- t6 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r142084 and r143506. Nearest v236 and v580 dist 0.28 (12167221004784.7x) Maximum distance of point above facet: 5.3e-13 (21.6x) Maximum distance of vertex below facet: -6.3e-13 (25.7x) Test -- t7 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r93165 and r93538. Nearest v296 and v410 dist 0.48 (21206162079995.6x) Maximum distance of vertex below facet: -2.9e-13 (11.7x) Test -- t8 CPU seconds to compute hull (after input): 1.33 Maximum distance of point above facet: 2.7e-13 (11.1x) Maximum distance of vertex below facet: -3e-13 (12.1x) Test -- t9 CPU seconds to compute hull (after input): 1.201 Maximum distance of point above facet: 2.9e-13 (11.7x) Maximum distance of vertex below facet: -2.8e-13 (11.4x) Test -- t10 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r54174 and r72009. Nearest v295 and v518 dist 0.37 (15990634214780.1x) 1591313899 Test 10 runs in 12 seconds (ave. 1200 msec) -- rbox 500 W0 C1,2e-13 D6 t1 | qhull Q14 Tv ==================== == Delaunay triangulation of point pairs (large upper facet) == Difficult case due to large upper facet with nearly adjacent vertices == A bounding box helps avoid this case, see TIME_DELAUNAY_PAIRS ==================== Testing -- rbox 100000 C1,2e-13 D2 t1 | qhull Q14 d Qbb >/d/bash/var/tmp/qtest-2020-06-04/qhull-430300.log Test -- t1 CPU seconds to compute hull (after input): 1.03 Test -- t2 CPU seconds to compute hull (after input): 1.141 Test -- t3 CPU seconds to compute hull (after input): 1.077 Test -- t4 CPU seconds to compute hull (after input): 1.058 Test -- t5 CPU seconds to compute hull (after input): 1.068 Test -- t6 CPU seconds to compute hull (after input): 1.105 Test -- t7 CPU seconds to compute hull (after input): 1.063 Test -- t8 CPU seconds to compute hull (after input): 1.053 Test -- t9 CPU seconds to compute hull (after input): 1.155 Test -- t10 CPU seconds to compute hull (after input): 1.039 1591313919 Test 10 runs in 19 seconds (ave. 1900 msec) -- rbox 100000 C1,2e-13 D2 t1 | qhull Q14 d Qbb Testing -- rbox 10000 C1,2e-13 D3 t1 | qhull Q14 d Qbb Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-99840.log Test -- t1 CPU seconds to compute hull (after input): 0.567 Maximum distance of point above facet: 1.3e-13 (12.4x) Maximum distance of vertex below facet: -1.4e-13 (13.6x) Test -- t2 CPU seconds to compute hull (after input): 0.578 Maximum distance of point above facet: 1.2e-13 (12.1x) Maximum distance of vertex below facet: -1.3e-13 (12.6x) Test -- t3 CPU seconds to compute hull (after input): 0.6 Test -- t4 CPU seconds to compute hull (after input): 0.586 Maximum distance of point above facet: 1.7e-13 (17.0x) Maximum distance of vertex below facet: -1.7e-13 (17.0x) Test -- t5 CPU seconds to compute hull (after input): 0.666 Test -- t6 CPU seconds to compute hull (after input): 0.57 Test -- t7 CPU seconds to compute hull (after input): 0.554 Maximum distance of point above facet: 1.2e-13 (11.9x) Maximum distance of vertex below facet: -1e-13 (10.0x) Test -- t8 CPU seconds to compute hull (after input): 0.595 Maximum distance of point above facet: 1.6e-13 (15.6x) Maximum distance of vertex below facet: -1.6e-13 (15.4x) Test -- t9 CPU seconds to compute hull (after input): 0.591 Test -- t10 CPU seconds to compute hull (after input): 0.569 Maximum distance of point above facet: 1.7e-13 (17.2x) 1591314060 Test 10 runs in 140 seconds (ave. 14000 msec) -- rbox 10000 C1,2e-13 D3 t1 | qhull Q14 d Qbb Tv Testing -- rbox 500 C1,2e-13 D4 t1 | qhull Q14 d Qbb Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-786620.log Test -- t1 CPU seconds to compute hull (after input): 0.251 Maximum distance of point above facet: 1.7e-13 (10.4x) Test -- t2 CPU seconds to compute hull (after input): 0.297 Test -- t3 QH6347 qhull precision error (qh_mergefacet): wide merge for facet f61980 into f61983 for mergetype 3 (concave). maxdist 0 (0.0x) mindist -0.00029 (17708951316.3x) vertexdist 0.24 Allow with 'Q12' (allow-wide) Test -- t4 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r37323 and r37309. Nearest v145 and v655 dist 0.067 (4459578188183.3x) Test -- t5 QH6348 qhull precision error (qh_mergefacet): wide merge for pinched facet f90244 into f90226 for mergetype 3 (concave). maxdist 8.9e-16 (0x) mindist -0.00072 (43999621074.9x) vertexdist 2.3e-13 Allow with 'Q12' (allow-wide) Maximum distance of point above facet: 2.5e-13 (15.4x) Test -- t6 CPU seconds to compute hull (after input): 0.245 Test -- t7 QH7085 Qhull precision warning: repartition coplanar point p939 from f58978 as an outside point above twisted facet f53492 dist 0.00041 nearest vertices 2.1e-13 CPU seconds to compute hull (after input): 0.248 Test -- t8 QH6391 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve opposite oriented ridges r49440 and r49431 in f83434 and f83454. Nearest v702 and v749 dist 0.13 (8887619111449.9x) Test -- t9 CPU seconds to compute hull (after input): 0.269 Test -- t10 CPU seconds to compute hull (after input): 0.287 Maximum distance of point above facet: 2.2e-13 (13.3x) Maximum distance of vertex below facet: -2.2e-13 (13.3x) 1591314066 Test 10 runs in 5 seconds (ave. 500 msec) -- rbox 500 C1,2e-13 D4 t1 | qhull Q14 d Qbb Tv Testing -- rbox 200 C1,2e-13 D5 t1 | qhull Q14 d Qbb Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-987482.log Test -- t1 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f185034 and f185037 have the same vertices (skip 1, skip 1) and same horizon ridges to f141174 and f144760 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f185034 and f185037 have the same vertices (skip 2, skip 2) and same horizon ridges to f141174 and f144760 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f185034 and f185037 have the same vertices (skip 3, skip 3) and same horizon ridges to f141174 and f144760 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f185034 and f185037 have the same vertices (skip 4, skip 4) and same horizon ridges to f141174 and f144760 CPU seconds to compute hull (after input): 0.593 Maximum distance of point above facet: 2.9e-13 (11.9x) Maximum distance of vertex below facet: -3e-13 (12.1x) Test -- t2 QH6348 qhull precision error (qh_mergefacet): wide merge for pinched facet f174047 into f174042 for mergetype 10 (degen). maxdist 0 (0x) mindist -0.0016 (66839804109.7x) vertexdist 2.3e-13 Allow with 'Q12' (allow-wide) Maximum distance of point above facet: 3e-13 (12.4x) Test -- t3 QH7085 Qhull precision warning: repartition coplanar point p347 from f112661 as an outside point above twisted facet f84991 dist 0.012 nearest vertices 2.4e-13 QH7085 Qhull precision warning: repartition coplanar point p262 from f146466 as an outside point above twisted facet f146340 dist 0.0036 nearest vertices 2.7e-13 CPU seconds to compute hull (after input): 0.677 Maximum distance of point above facet: 2.9e-13 (11.6x) Maximum distance of vertex below facet: -2.8e-13 (11.3x) Test -- t4 CPU seconds to compute hull (after input): 0.617 Maximum distance of point above facet: 3.2e-13 (12.8x) Maximum distance of vertex below facet: -3.1e-13 (12.8x) Test -- t5 CPU seconds to compute hull (after input): 0.612 Maximum distance of vertex below facet: -3.1e-13 (12.5x) Test -- t6 QH7085 Qhull precision warning: repartition coplanar point p360 from f151288 as an outside point above twisted facet f150803 dist 0.0006 nearest vertices 2.3e-13 CPU seconds to compute hull (after input): 0.648 Maximum distance of point above facet: 2.7e-13 (11.1x) Maximum distance of vertex below facet: -2.7e-13 (11.0x) Test -- t7 QH6271 qhull topology error (qh_check_dupridge): wide merge (137048246420.0x wider) due to dupridge between f120616 and f120712 (vertex dist 2.9e-13), merge dist 0.032, while processing p87 Test -- t8 QH7085 Qhull precision warning: repartition coplanar point p398 from f162825 as an outside point above twisted facet f161866 dist 0.0035 nearest vertices 2.4e-13 CPU seconds to compute hull (after input): 0.655 Maximum distance of point above facet: 3.3e-13 (13.2x) Maximum distance of vertex below facet: -3.1e-13 (12.7x) Test -- t9 QH7085 Qhull precision warning: repartition coplanar point p20 from f184186 as an outside point above twisted facet f151412 dist 0.0025 nearest vertices 2.3e-13 QH7085 Qhull precision warning: repartition coplanar point p170 from f185019 as an outside point above twisted facet f185295 dist 0.0019 nearest vertices 2.6e-13 QH6348 qhull precision error (qh_mergefacet): wide merge for pinched facet f201965 into f164338 for mergetype 10 (degen). maxdist 0 (0x) mindist -0.00068 (27672717659.2x) vertexdist 2.6e-13 Allow with 'Q12' (allow-wide) Test -- t10 QH7085 Qhull precision warning: repartition coplanar point p299 from f93758 as an outside point above twisted facet f108187 dist 0.00051 nearest vertices 2.5e-13 QH7085 Qhull precision warning: repartition coplanar point p80 from f146206 as an outside point above twisted facet f146404 dist 0.0016 nearest vertices 2.1e-13 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f173687 and f173690 have the same vertices (skip 2, skip 2) and same horizon ridges to f148123 and f114638 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f173687 and f173690 have the same vertices (skip 4, skip 4) and same horizon ridges to f148123 and f114638 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f173687 and f173690 have the same vertices (skip 5, skip 5) and same horizon ridges to f148123 and f114638 QH6155 qhull topology error (qh_matchdupridge): missing qh_DUPLICATEridge at f173690 skip 4 for new f173687 skip 4 hash 2975 ismatch 1. Set by qh_matchneighbor 1591314074 Test 10 runs in 8 seconds (ave. 800 msec) -- rbox 200 C1,2e-13 D5 t1 | qhull Q14 d Qbb Tv Testing -- rbox 100 C1,2e-13 D6 t1 | qhull Q14 d Qbb Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-788775.log Test -- t1 CPU seconds to compute hull (after input): 1.063 Maximum distance of vertex below facet: -3.7e-13 (10.6x) Test -- t2 CPU seconds to compute hull (after input): 0.989 Test -- t3 CPU seconds to compute hull (after input): 1.078 Test -- t4 CPU seconds to compute hull (after input): 1.032 Maximum distance of point above facet: 3.6e-13 (10.3x) Maximum distance of vertex below facet: -3.6e-13 (10.4x) Test -- t5 CPU seconds to compute hull (after input): 1.035 Maximum distance of point above facet: 3.9e-13 (11.2x) Maximum distance of vertex below facet: -3.5e-13 (10.0x) Test -- t6 CPU seconds to compute hull (after input): 1.183 Maximum distance of point above facet: 3.6e-13 (10.2x) Maximum distance of vertex below facet: -3.6e-13 (10.2x) Test -- t7 CPU seconds to compute hull (after input): 1.035 Maximum distance of point above facet: 3.6e-13 (10.3x) Maximum distance of vertex below facet: -3.9e-13 (11.2x) Test -- t8 CPU seconds to compute hull (after input): 1.092 Maximum distance of point above facet: 3.9e-13 (11.2x) Test -- t9 CPU seconds to compute hull (after input): 1.053 Maximum distance of vertex below facet: -3.5e-13 (10.1x) Test -- t10 CPU seconds to compute hull (after input): 1.133 1591314089 Test 10 runs in 14 seconds (ave. 1400 msec) -- rbox 100 C1,2e-13 D6 t1 | qhull Q14 d Qbb Tv ==================== == Delaunay triangulation of point quads (2e-13, large upper facet) == Difficult case due to large upper facet with many nearly adjacent vertices ==================== Testing -- rbox 50000 C3,2e-13 D2 t1 | qhull Q14 d Qbb >/d/bash/var/tmp/qtest-2020-06-04/qhull-257453.log Test -- t1 CPU seconds to compute hull (after input): 0.79 Test -- t2 CPU seconds to compute hull (after input): 0.816 Test -- t3 CPU seconds to compute hull (after input): 0.751 Test -- t4 CPU seconds to compute hull (after input): 0.794 Test -- t5 CPU seconds to compute hull (after input): 0.827 Test -- t6 CPU seconds to compute hull (after input): 0.816 Test -- t7 CPU seconds to compute hull (after input): 0.756 Test -- t8 CPU seconds to compute hull (after input): 0.788 Test -- t9 CPU seconds to compute hull (after input): 0.807 Test -- t10 CPU seconds to compute hull (after input): 0.798 1591314105 Test 10 runs in 15 seconds (ave. 1500 msec) -- rbox 50000 C3,2e-13 D2 t1 | qhull Q14 d Qbb Testing -- rbox 10000 C3,2e-13 D3 t1 | qhull Q14 d Qbb >/d/bash/var/tmp/qtest-2020-06-04/qhull-793085.log Test -- t1 QH7085 Qhull precision warning: repartition coplanar point p12320 from f382177 as an outside point above twisted facet f291472 dist 1.2e-05 nearest vertices 2.4e-13 CPU seconds to compute hull (after input): 1.319 Maximum distance of point above facet: 1.7e-13 (16.5x) Maximum distance of vertex below facet: -2.8e-13 (27.9x) Test -- t2 CPU seconds to compute hull (after input): 1.19 Maximum distance of point above facet: 2e-13 (19.9x) Maximum distance of vertex below facet: -3e-13 (29.5x) Test -- t3 QH6271 qhull topology error (qh_check_dupridge): wide merge (23901933399.7x wider) due to dupridge between f137488 and f137468 (vertex dist 1.5e-13), merge dist 0.0039, while processing p17270 Maximum distance of point above facet: 1.6e-13 (16.3x) Test -- t4 QH7085 Qhull precision warning: repartition coplanar point p29925 from f280725 as an outside point above twisted facet f256639 dist 0.00035 nearest vertices 3.3e-13 CPU seconds to compute hull (after input): 1.327 Test -- t5 CPU seconds to compute hull (after input): 1.315 Maximum distance of vertex below facet: -2e-13 (20.2x) Test -- t6 QH6271 qhull topology error (qh_check_dupridge): wide merge (11702792832.0x wider) due to dupridge between f387461 and f387449 (vertex dist 2.6e-13), merge dist 0.00061, while processing p22990 Maximum distance of vertex below facet: -2.2e-13 (21.3x) Test -- t7 QH7085 Qhull precision warning: repartition coplanar point p5375 from f42124 as an outside point above twisted facet f35929 dist 0.00017 nearest vertices 2.3e-13 QH7085 Qhull precision warning: repartition coplanar point p12414 from f118528 as an outside point above twisted facet f118402 dist 8.2e-05 nearest vertices 2.9e-13 QH7085 Qhull precision warning: repartition coplanar point p12412 from f131934 as an outside point above twisted facet f118402 dist 8.2e-05 nearest vertices 2.9e-13 QH6271 qhull topology error (qh_check_dupridge): wide merge (34223214094.6x wider) due to dupridge between f220362 and f220384 (vertex dist 2.1e-13), merge dist 0.0034, while processing p30020 Test -- t8 QH6271 qhull topology error (qh_check_dupridge): wide merge (7996982012.6x wider) due to dupridge between f145209 and f145190 (vertex dist 2.5e-13), merge dist 0.00036, while processing p33922 Test -- t9 QH6348 qhull precision error (qh_mergefacet): wide merge for pinched facet f281312 into f281315 for mergetype 10 (degen). maxdist 0.00023 (22681376866x) mindist 0 (-0.0x) vertexdist 2.8e-13 Allow with 'Q12' (allow-wide) Maximum distance of point above facet: 1.5e-13 (14.5x) Maximum distance of vertex below facet: -1.9e-13 (18.6x) Test -- t10 QH7085 Qhull precision warning: repartition coplanar point p13174 from f115708 as an outside point above twisted facet f75801 dist 6.2e-05 nearest vertices 1.8e-13 CPU seconds to compute hull (after input): 1.255 Maximum distance of point above facet: 1.2e-13 (11.9x) Maximum distance of vertex below facet: -1.5e-13 (15.0x) 1591314118 Test 10 runs in 13 seconds (ave. 1300 msec) -- rbox 10000 C3,2e-13 D3 t1 | qhull Q14 d Qbb Testing -- rbox 200 C3,2e-13 D4 t1 | qhull Q14 d Qbb Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-728286.log Test -- t1 QH7085 Qhull precision warning: repartition coplanar point p472 from f30497 as an outside point above twisted facet f28296 dist 0.0013 nearest vertices 2.9e-13 QH7085 Qhull precision warning: repartition coplanar point p474 from f15245 as an outside point above twisted facet f28296 dist 0.0013 nearest vertices 2.9e-13 QH7085 Qhull precision warning: repartition coplanar point p475 from f25323 as an outside point above twisted facet f28296 dist 0.0013 nearest vertices 2.9e-13 QH7085 Qhull precision warning: repartition coplanar point p360 from f32075 as an outside point above twisted facet f38829 dist 0.0016 nearest vertices 3.3e-13 QH7085 Qhull precision warning: repartition coplanar point p568 from f45312 as an outside point above twisted facet f61895 dist 0.00052 nearest vertices 3.2e-13 CPU seconds to compute hull (after input): 0.233 Maximum distance of vertex below facet: -2.2e-13 (13.2x) Test -- t2 QH6271 qhull topology error (qh_check_dupridge): wide merge (428757713021.6x wider) due to dupridge between f60125 and f60186 (vertex dist 1.8e-13), merge dist 0.046, while processing p212 Test -- t3 QH7085 Qhull precision warning: repartition coplanar point p712 from f33823 as an outside point above twisted facet f33910 dist 0.0062 nearest vertices 3e-13 QH7085 Qhull precision warning: repartition coplanar point p489 from f63992 as an outside point above twisted facet f58682 dist 0.00083 nearest vertices 2.6e-13 QH7085 Qhull precision warning: repartition coplanar point p712 from f65054 as an outside point above twisted facet f65054 dist 0.0062 nearest vertices 3e-13 CPU seconds to compute hull (after input): 0.224 Maximum distance of point above facet: 2.7e-13 (16.3x) Maximum distance of vertex below facet: -2.6e-13 (16.0x) Test -- t4 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f85331 and f85334 have the same vertices (skip 1, skip 1) and same horizon ridges to f56870 and f56807 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f85331 and f85334 have the same vertices (skip 3, skip 3) and same horizon ridges to f56870 and f56807 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f85331 and f85334 have the same vertices (skip 4, skip 4) and same horizon ridges to f56870 and f56807 CPU seconds to compute hull (after input): 0.244 Maximum distance of point above facet: 1.7e-13 (10.2x) Maximum distance of vertex below facet: -2.1e-13 (13.0x) Test -- t5 CPU seconds to compute hull (after input): 0.25 Maximum distance of point above facet: 2.7e-13 (16.2x) Test -- t6 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f69535 and f69536 have the same vertices (skip 2, skip 2) and same horizon ridges to f67282 and f55324 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f69535 and f69536 have the same vertices (skip 4, skip 4) and same horizon ridges to f67282 and f55324 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r33127 and r33205. Nearest v112 and v298 dist 0.44 (29005168264526.7x) Test -- t7 QH6271 qhull topology error (qh_check_dupridge): wide merge (127462857834.9x wider) due to dupridge between f68944 and f69003 (vertex dist 1.8e-13), merge dist 0.026, while processing p131 Maximum distance of point above facet: 2e-13 (12.4x) Test -- t8 QH7085 Qhull precision warning: repartition coplanar point p676 from f45805 as an outside point above twisted facet f45702 dist 0.0013 nearest vertices 2.1e-13 QH7085 Qhull precision warning: repartition coplanar point p676 from f57639 as an outside point above twisted facet f57674 dist 0.0013 nearest vertices 2.1e-13 CPU seconds to compute hull (after input): 0.223 Maximum distance of point above facet: 2.2e-13 (13.6x) Test -- t9 QH6271 qhull topology error (qh_check_dupridge): wide merge (32039228101.5x wider) due to dupridge between f54848 and f54847 (vertex dist 4.5e-13), merge dist 0.003, while processing p245 Test -- t10 QH7085 Qhull precision warning: repartition coplanar point p195 from f41114 as an outside point above twisted facet f45686 dist 0.00052 nearest vertices 2.3e-13 QH7085 Qhull precision warning: repartition coplanar point p649 from f55532 as an outside point above twisted facet f51266 dist 0.00025 nearest vertices 3.1e-13 QH6271 qhull topology error (qh_check_dupridge): wide merge (126156001671.2x wider) due to dupridge between f84631 and f84632 (vertex dist 1.6e-13), merge dist 0.014, while processing p249 1591314123 Test 10 runs in 4 seconds (ave. 400 msec) -- rbox 200 C3,2e-13 D4 t1 | qhull Q14 d Qbb Tv Testing -- rbox 100 C3,2e-13 D5 t1 | qhull Q14 d Qbb Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-395671.log Test -- t1 QH7085 Qhull precision warning: repartition coplanar point p398 from f32500 as an outside point above twisted facet f31968 dist 0.00053 nearest vertices 3.1e-13 QH6271 qhull topology error (qh_check_dupridge): wide merge (85243973871.6x wider) due to dupridge between f37655 and f37777 (vertex dist 1.2e-13), merge dist 0.014, while processing p277 Test -- t2 QH6271 qhull topology error (qh_check_dupridge): wide merge (53863715239.4x wider) due to dupridge between f53646 and f53579 (vertex dist 1.8e-13), merge dist 0.011, while processing p271 Test -- t3 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f69313 and f69314 have the same vertices (skip 1, skip 1) and same horizon ridges to f48822 and f47087 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f69313 and f69314 have the same vertices (skip 2, skip 2) and same horizon ridges to f48822 and f47087 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f69313 and f69314 have the same vertices (skip 3, skip 3) and same horizon ridges to f48822 and f47087 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f69313 and f69314 have the same vertices (skip 4, skip 4) and same horizon ridges to f48822 and f47087 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f69313 and f69314 have the same vertices (skip 5, skip 5) and same horizon ridges to f48822 and f47087 QH6155 qhull topology error (qh_matchdupridge): missing qh_DUPLICATEridge at f69314 skip 4 for new f69313 skip 4 hash 299 ismatch 1. Set by qh_matchneighbor Maximum distance of point above facet: 5.2e-13 (21.0x) Test -- t4 QH6425 Qhull topology error (qh_partitioncoplanar): can not repartition coplanar point p81 from f24330 as outside point above f38196. It previously failed to form a cone of facets, dist 0.021, nearest vertices 1.9e-13 Maximum distance of point above facet: 4.5e-13 (18.2x) Test -- t5 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f55397 and f55399 have the same vertices (skip 1, skip 1) and same horizon ridges to f45325 and f30999 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f55397 and f55399 have the same vertices (skip 2, skip 2) and same horizon ridges to f45325 and f30999 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f55397 and f55399 have the same vertices (skip 3, skip 3) and same horizon ridges to f45325 and f30999 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f55397 and f55399 have the same vertices (skip 5, skip 5) and same horizon ridges to f45325 and f30999 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f55691 and f55692 have the same vertices (skip 1, skip 1) and same horizon ridges to f31188 and f31188 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f55691 and f55692 have the same vertices (skip 2, skip 2) and same horizon ridges to f31188 and f31188 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f55691 and f55692 have the same vertices (skip 3, skip 3) and same horizon ridges to f31188 and f31188 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f55691 and f55692 have the same vertices (skip 4, skip 4) and same horizon ridges to f31188 and f31188 QH6155 qhull topology error (qh_matchdupridge): missing qh_DUPLICATEridge at f55692 skip 2 for new f55691 skip 2 hash 110 ismatch 1. Set by qh_matchneighbor Maximum distance of point above facet: 3.7e-13 (14.9x) Test -- t6 QH6425 Qhull topology error (qh_partitioncoplanar): can not repartition coplanar point p118 from f42823 as outside point above f59123. It previously failed to form a cone of facets, dist 0.0012, nearest vertices 3e-13 Maximum distance of point above facet: 4.3e-13 (17.6x) Test -- t7 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f32570 and f32577 have the same vertices (skip 1, skip 1) and same horizon ridges to f30838 and f17693 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f32570 and f32577 have the same vertices (skip 2, skip 2) and same horizon ridges to f30838 and f17693 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f32570 and f32577 have the same vertices (skip 3, skip 3) and same horizon ridges to f30838 and f17693 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f32570 and f32577 have the same vertices (skip 5, skip 5) and same horizon ridges to f30838 and f17693 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f33395 and f33396 have the same vertices (skip 1, skip 1) and same horizon ridges to f30837 and f30837 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f33395 and f33396 have the same vertices (skip 2, skip 2) and same horizon ridges to f30837 and f30837 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f33395 and f33396 have the same vertices (skip 4, skip 4) and same horizon ridges to f30837 and f30837 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f33395 and f33396 have the same vertices (skip 5, skip 5) and same horizon ridges to f30837 and f30837 QH6155 qhull topology error (qh_matchdupridge): missing qh_DUPLICATEridge at f33396 skip 4 for new f33395 skip 4 hash 1814 ismatch 1. Set by qh_matchneighbor Test -- t8 QH7085 Qhull precision warning: repartition coplanar point p2 from f55464 as an outside point above twisted facet f55542 dist 0.012 nearest vertices 3.4e-13 QH7085 Qhull precision warning: repartition coplanar point p3 from f71850 as an outside point above twisted facet f55542 dist 0.012 nearest vertices 3.4e-13 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r62183 and r43372. Nearest v132 and v169 dist 0.36 (15824738144899.3x) Test -- t9 QH7085 Qhull precision warning: repartition coplanar point p104 from f37252 as an outside point above twisted facet f34161 dist 0.0053 nearest vertices 1.4e-13 QH7085 Qhull precision warning: repartition coplanar point p195 from f55708 as an outside point above twisted facet f55858 dist 0.0025 nearest vertices 2.8e-13 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f60441 and f60442 have the same vertices (skip 1, skip 1) and same horizon ridges to f52475 and f43643 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f60441 and f60442 have the same vertices (skip 4, skip 4) and same horizon ridges to f52475 and f43643 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f60441 and f60442 have the same vertices (skip 5, skip 5) and same horizon ridges to f52475 and f43643 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f75399 and f75401 have the same vertices (skip 2, skip 2) and same horizon ridges to f50203 and f53335 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f75399 and f75401 have the same vertices (skip 3, skip 3) and same horizon ridges to f50203 and f53335 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f75399 and f75401 have the same vertices (skip 4, skip 4) and same horizon ridges to f50203 and f53335 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f75399 and f75401 have the same vertices (skip 5, skip 5) and same horizon ridges to f50203 and f53335 QH6155 qhull topology error (qh_matchdupridge): missing qh_DUPLICATEridge at f75401 skip 5 for new f75399 skip 5 hash 2313 ismatch 1. Set by qh_matchneighbor Maximum distance of point above facet: 3.9e-13 (15.7x) Test -- t10 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f46690 and f46691 have the same vertices (skip 1, skip 1) and same horizon ridges to f41615 and f41615 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f46690 and f46691 have the same vertices (skip 2, skip 2) and same horizon ridges to f41615 and f41615 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f46690 and f46691 have the same vertices (skip 4, skip 4) and same horizon ridges to f41615 and f41615 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f53810 and f53813 have the same vertices (skip 1, skip 1) and same horizon ridges to f44991 and f49453 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f53810 and f53813 have the same vertices (skip 2, skip 2) and same horizon ridges to f44991 and f49453 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f53810 and f53813 have the same vertices (skip 3, skip 3) and same horizon ridges to f44991 and f49453 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f53810 and f53813 have the same vertices (skip 4, skip 4) and same horizon ridges to f44991 and f49453 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f53810 and f53813 have the same vertices (skip 5, skip 5) and same horizon ridges to f44991 and f49453 QH6155 qhull topology error (qh_matchdupridge): missing qh_DUPLICATEridge at f53813 skip 3 for new f53810 skip 3 hash 649 ismatch 1. Set by qh_matchneighbor Maximum distance of point above facet: 3.2e-13 (12.8x) 1591314127 Test 10 runs in 3 seconds (ave. 300 msec) -- rbox 100 C3,2e-13 D5 t1 | qhull Q14 d Qbb Tv Testing -- rbox 100 C3,2e-13 D6 t1 | qhull Q14 d Qbb Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-529579.log Test -- t1 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f60622 and f60625 have the same vertices (skip 2, skip 2) and same horizon ridges to f45381 and f45383 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f60622 and f60625 have the same vertices (skip 3, skip 3) and same horizon ridges to f45381 and f45383 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f60622 and f60625 have the same vertices (skip 4, skip 4) and same horizon ridges to f45381 and f45383 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f60622 and f60625 have the same vertices (skip 5, skip 5) and same horizon ridges to f45381 and f45383 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r62945 and r62952. Nearest v1 and v91 dist 0.58 (17756633105771.5x) Test -- t2 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f30378 and f30379 have the same vertices (skip 3, skip 3) and same horizon ridges to f28250 and f28199 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f30378 and f30379 have the same vertices (skip 4, skip 4) and same horizon ridges to f28250 and f28199 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f30378 and f30379 have the same vertices (skip 5, skip 5) and same horizon ridges to f28250 and f28199 QH7085 Qhull precision warning: repartition coplanar point p77 from f459553 as an outside point above twisted facet f459471 dist 0.0045 nearest vertices 3.6e-13 QH6425 Qhull topology error (qh_partitioncoplanar): can not repartition coplanar point p269 from f428888 as outside point above f443167. It previously failed to form a cone of facets, dist 0.0044, nearest vertices 3.4e-13 Maximum distance of point above facet: 5.4e-13 (15.5x) Test -- t3 QH7085 Qhull precision warning: repartition coplanar point p138 from f486368 as an outside point above twisted facet f456801 dist 0.018 nearest vertices 2.9e-13 QH6425 Qhull topology error (qh_partitioncoplanar): can not repartition coplanar point p138 from f456801 as outside point above f456801. It previously failed to form a cone of facets, dist 0.018, nearest vertices 2.9e-13 Maximum distance of point above facet: 6.7e-13 (19.1x) Test -- t4 QH7085 Qhull precision warning: repartition coplanar point p160 from f486132 as an outside point above twisted facet f478047 dist 0.0078 nearest vertices 2.1e-13 QH7085 Qhull precision warning: repartition coplanar point p161 from f486262 as an outside point above twisted facet f478047 dist 0.0078 nearest vertices 2.1e-13 CPU seconds to compute hull (after input): 2.417 Maximum distance of point above facet: 5.4e-13 (15.3x) Maximum distance of vertex below facet: -6.4e-13 (18.4x) Test -- t5 QH7085 Qhull precision warning: repartition coplanar point p71 from f128831 as an outside point above twisted facet f125804 dist 0.0028 nearest vertices 5e-13 QH7087 Qhull precision warning: in post-processing (qh_check_maxout) p196 for f444324 is 0.014 above twisted facet f474646 nearest vertices 2.9e-13 QH7087 Qhull precision warning: in post-processing (qh_check_maxout) p197 for f244291 is 0.014 above twisted facet f474646 nearest vertices 2.9e-13 QH7087 Qhull precision warning: in post-processing (qh_check_maxout) p198 for f173972 is 0.014 above twisted facet f474646 nearest vertices 2.9e-13 QH7087 Qhull precision warning: in post-processing (qh_check_maxout) p199 for f338726 is 0.014 above twisted facet f474646 nearest vertices 2.9e-13 QH6297 Qhull precision error (qh_check_maxout): large increase in qh.max_outside during post-processing dist 0.014 (27511359088.2x). See warning QH0032/QH0033. Allow with 'Q12' (allow-wide) and 'Pp' Maximum distance of point above facet: 0.014 (393049147618.8x) Maximum distance of vertex below facet: -4.2e-13 (12.1x) Test -- t6 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f188213 and f188267 have the same vertices (skip 2, skip 2) and same horizon ridges to f147427 and f92655 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f188213 and f188267 have the same vertices (skip 4, skip 4) and same horizon ridges to f147427 and f92655 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f188213 and f188267 have the same vertices (skip 5, skip 5) and same horizon ridges to f147427 and f92655 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f188213 and f188267 have the same vertices (skip 6, skip 6) and same horizon ridges to f147427 and f92655 QH6271 qhull topology error (qh_check_dupridge): wide merge (4575757634.2x wider) due to dupridge between f379449 and f379436 (vertex dist 3.3e-13), merge dist 0.0028, while processing p275 Maximum distance of point above facet: 6e-13 (17.3x) Test -- t7 QH7085 Qhull precision warning: repartition coplanar point p392 from f47849 as an outside point above twisted facet f48668 dist 0.0048 nearest vertices 2.6e-13 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f131731 and f131732 have the same vertices (skip 1, skip 1) and same horizon ridges to f103529 and f90653 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f131731 and f131732 have the same vertices (skip 2, skip 2) and same horizon ridges to f103529 and f90653 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f131731 and f131732 have the same vertices (skip 4, skip 4) and same horizon ridges to f103529 and f90653 QH7085 Qhull precision warning: repartition coplanar point p56 from f145507 as an outside point above twisted facet f154853 dist 0.0022 nearest vertices 4.1e-13 QH6425 Qhull topology error (qh_partitioncoplanar): can not repartition coplanar point p112 from f208350 as outside point above f444562. It previously failed to form a cone of facets, dist 0.022, nearest vertices 3.9e-13 Maximum distance of point above facet: 5.5e-13 (15.6x) Test -- t8 QH7085 Qhull precision warning: repartition coplanar point p289 from f154666 as an outside point above twisted facet f154831 dist 0.0001 nearest vertices 3.5e-13 QH7085 Qhull precision warning: repartition coplanar point p10 from f202799 as an outside point above twisted facet f198044 dist 8.8e-05 nearest vertices 3.6e-13 CPU seconds to compute hull (after input): 2.755 Maximum distance of point above facet: 5.9e-13 (16.7x) Maximum distance of vertex below facet: -5.9e-13 (16.9x) Test -- t9 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f62222 and f62223 have the same vertices (skip 3, skip 3) and same horizon ridges to f46423 and f46695 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f62222 and f62223 have the same vertices (skip 4, skip 4) and same horizon ridges to f46423 and f46695 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f62222 and f62223 have the same vertices (skip 5, skip 5) and same horizon ridges to f46423 and f46695 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f62220 and f62224 have the same vertices (skip 2, skip 2) and same horizon ridges to f44626 and f58290 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f62220 and f62224 have the same vertices (skip 3, skip 3) and same horizon ridges to f44626 and f58290 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f62220 and f62224 have the same vertices (skip 5, skip 5) and same horizon ridges to f44626 and f58290 QH6155 qhull topology error (qh_matchdupridge): missing qh_DUPLICATEridge at f62223 skip 5 for new f62222 skip 5 hash 9681 ismatch 1. Set by qh_matchneighbor Test -- t10 QH7085 Qhull precision warning: repartition coplanar point p84 from f300897 as an outside point above twisted facet f298172 dist 0.0014 nearest vertices 2.3e-13 QH7085 Qhull precision warning: repartition coplanar point p87 from f271195 as an outside point above twisted facet f298172 dist 0.0014 nearest vertices 2.3e-13 QH7085 Qhull precision warning: repartition coplanar point p287 from f392815 as an outside point above twisted facet f373850 dist 0.0018 nearest vertices 2.2e-13 CPU seconds to compute hull (after input): 2.57 Maximum distance of point above facet: 5.1e-13 (14.7x) Maximum distance of vertex below facet: -4.7e-13 (13.4x) 1591314149 Test 10 runs in 21 seconds (ave. 2100 msec) -- rbox 100 C3,2e-13 D6 t1 | qhull Q14 d Qbb Tv ==================== == Delaunay triangulation of fuzzy circle with pairs (large, narrow disk) == Highly degenerate due to narrow disk of two cospherical sets of point pairs == Worse with Qbb since it stretches out the paraboloid, doubling _one-merge ==================== Testing -- rbox 10000 s W1e-13 C1,1e-13 D2 t1 | qhull Q14 d Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-799550.log Test -- t1 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.15 Maximum distance of point above facet: 8.9e-14 (16.0x) Test -- t2 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7085 Qhull precision warning: repartition coplanar point p8919 from f70212 as an outside point above twisted facet f70212 dist 3e-09 nearest vertices 3.9e-14 QH7085 Qhull precision warning: repartition coplanar point p455 from f59188 as an outside point above twisted facet f81155 dist 4.4e-12 nearest vertices 1.3e-13 CPU seconds to compute hull (after input): 0.181 Maximum distance of point above facet: 1.1e-13 (19.3x) Test -- t3 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7085 Qhull precision warning: repartition coplanar point p17910 from f11508 as an outside point above twisted facet f11509 dist 1.5e-09 nearest vertices 1.2e-13 QH7085 Qhull precision warning: repartition coplanar point p1289 from f50034 as an outside point above twisted facet f50033 dist 1.1e-10 nearest vertices 1.3e-13 QH7085 Qhull precision warning: repartition coplanar point p1146 from f51301 as an outside point above twisted facet f51297 dist 5.3e-09 nearest vertices 9.6e-14 CPU seconds to compute hull (after input): 0.132 Maximum distance of point above facet: 9e-14 (16.3x) Test -- t4 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7085 Qhull precision warning: repartition coplanar point p9630 from f2685 as an outside point above twisted facet f2685 dist 8.6e-08 nearest vertices 1.2e-13 QH7085 Qhull precision warning: repartition coplanar point p16714 from f32738 as an outside point above twisted facet f32736 dist 1.6e-08 nearest vertices 1.1e-13 QH7085 Qhull precision warning: repartition coplanar point p13115 from f87933 as an outside point above twisted facet f87933 dist 7.7e-11 nearest vertices 5.9e-14 CPU seconds to compute hull (after input): 0.158 Maximum distance of point above facet: 1.4e-13 (25.2x) Test -- t5 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7085 Qhull precision warning: repartition coplanar point p17035 from f27535 as an outside point above twisted facet f18091 dist 3.2e-08 nearest vertices 1.4e-13 CPU seconds to compute hull (after input): 0.128 Maximum distance of point above facet: 7.3e-14 (13.1x) Test -- t6 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7085 Qhull precision warning: repartition coplanar point p9250 from f30601 as an outside point above twisted facet f30601 dist 4.5e-10 nearest vertices 8.7e-14 CPU seconds to compute hull (after input): 0.263 Maximum distance of point above facet: 1e-13 (18.3x) Test -- t7 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7085 Qhull precision warning: repartition coplanar point p10212 from f52627 as an outside point above twisted facet f39538 dist 8e-08 nearest vertices 1.2e-13 QH7085 Qhull precision warning: repartition coplanar point p18974 from f62060 as an outside point above twisted facet f62059 dist 1.8e-10 nearest vertices 1.5e-13 CPU seconds to compute hull (after input): 0.155 Maximum distance of point above facet: 7.9e-14 (14.2x) Test -- t8 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.135 Test -- t9 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7085 Qhull precision warning: repartition coplanar point p9241 from f12854 as an outside point above twisted facet f19747 dist 2.1e-10 nearest vertices 5.3e-14 CPU seconds to compute hull (after input): 0.285 Maximum distance of point above facet: 1.1e-13 (20.2x) Test -- t10 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7085 Qhull precision warning: repartition coplanar point p1126 from f6831 as an outside point above twisted facet f6829 dist 6.6e-08 nearest vertices 6.8e-14 QH7085 Qhull precision warning: repartition coplanar point p5672 from f50284 as an outside point above twisted facet f50284 dist 2e-08 nearest vertices 1.3e-13 QH7085 Qhull precision warning: repartition coplanar point p16435 from f83558 as an outside point above twisted facet f83559 dist 4.2e-09 nearest vertices 1.2e-13 CPU seconds to compute hull (after input): 0.134 1591314207 Test 10 runs in 56 seconds (ave. 5600 msec) -- rbox 10000 s W1e-13 C1,1e-13 D2 t1 | qhull Q14 d Tv Testing -- rbox 5000 s W1e-13 C1,1e-13 D3 t1 | qhull Q14 d Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-207739.log Test -- t1 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6417 qhull precision error (qh_merge_twisted): twisted facet f21567 does not contain pinched vertices. Too wide to merge into neighbor. mindist -2.7e-12 maxdist 1.2e-13 vertexdist 0.0099 maxpinched 1.8e-13 neighbor f50395 mindist -1.7e-13 maxdist 0 Maximum distance of point above facet: 1.1e-13 (10.9x) Maximum distance of vertex below facet: -1.1e-13 (11.3x) Test -- t2 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.869 Test -- t3 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7085 Qhull precision warning: repartition coplanar point p8930 from f104123 as an outside point above twisted facet f103999 dist 0.00018 nearest vertices 1.2e-13 QH7085 Qhull precision warning: repartition coplanar point p892 from f113105 as an outside point above twisted facet f111527 dist 4.1e-05 nearest vertices 1.2e-13 QH7085 Qhull precision warning: repartition coplanar point p6690 from f123791 as an outside point above twisted facet f123795 dist 0.0006 nearest vertices 1.4e-13 QH7085 Qhull precision warning: repartition coplanar point p5468 from f142839 as an outside point above twisted facet f142837 dist 0.00098 nearest vertices 1.6e-13 QH7085 Qhull precision warning: repartition coplanar point p3405 from f142848 as an outside point above twisted facet f139682 dist 7.8e-05 nearest vertices 1e-13 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r165439 and r38425. Nearest v830 and v1354 dist 0.074 (8134458896400.2x) Maximum distance of point above facet: 3.7e-13 (37.2x) Maximum distance of vertex below facet: -4.4e-13 (43.6x) Test -- t4 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7085 Qhull precision warning: repartition coplanar point p7666 from f61505 as an outside point above twisted facet f61504 dist 0.00016 nearest vertices 1.2e-13 QH7087 Qhull precision warning: in post-processing (qh_check_maxout) p606 for f82547 is 1.3e-05 above twisted facet f153062 nearest vertices 1.1e-13 QH7087 Qhull precision warning: in post-processing (qh_check_maxout) p956 for f158681 is 2.2e-05 above twisted facet f158676 nearest vertices 5.8e-14 QH7087 Qhull precision warning: in post-processing (qh_check_maxout) p957 for f138507 is 2.2e-05 above twisted facet f158676 nearest vertices 5.8e-14 QH7087 Qhull precision warning: in post-processing (qh_check_maxout) p1790 for f158676 is 4.3e-05 above twisted facet f158681 nearest vertices 9.4e-14 QH7087 Qhull precision warning: in post-processing (qh_check_maxout) p5202 for f105552 is 0.0004 above twisted facet f153062 nearest vertices 1.1e-13 QH7087 Qhull precision warning: in post-processing (qh_check_maxout) p5282 for f81536 is 0.00041 above twisted facet f153062 nearest vertices 1.1e-13 QH6297 Qhull precision error (qh_check_maxout): large increase in qh.max_outside during post-processing dist 0.00041 (6382723453.9x). See warning QH0032/QH0033. Allow with 'Q12' (allow-wide) and 'Pp' Maximum distance of point above facet: 0.00041 (40469546794.9x) Maximum distance of vertex below facet: -2.3e-13 (22.9x) Test -- t5 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7087 Qhull precision warning: in post-processing (qh_check_maxout) p8850 for f55068 is 8.7e-07 above twisted facet f95335 nearest vertices 1.1e-13 QH6297 Qhull precision error (qh_check_maxout): large increase in qh.max_outside during post-processing dist 8.7e-07 (1930350.1x). See warning QH0032/QH0033. Allow with 'Q12' (allow-wide) and 'Pp' Maximum distance of point above facet: 8.7e-07 (85973653.6x) Maximum distance of vertex below facet: -1e-13 (10.2x) Test -- t6 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7085 Qhull precision warning: repartition coplanar point p2321 from f163230 as an outside point above twisted facet f163220 dist 8.3e-05 nearest vertices 7.5e-14 QH7087 Qhull precision warning: in post-processing (qh_check_maxout) p826 for f88991 is 0.00033 above twisted facet f110829 nearest vertices 1.7e-13 QH6297 Qhull precision error (qh_check_maxout): large increase in qh.max_outside during post-processing dist 0.00033 (4218337700.8x). See warning QH0032/QH0033. Allow with 'Q12' (allow-wide) and 'Pp' Maximum distance of point above facet: 0.00033 (33146888209.5x) Maximum distance of vertex below facet: -2.3e-13 (22.6x) Test -- t7 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7087 Qhull precision warning: in post-processing (qh_check_maxout) p652 for f85664 is 3e-06 above twisted facet f144652 nearest vertices 7.8e-14 QH7087 Qhull precision warning: in post-processing (qh_check_maxout) p653 for f85664 is 3e-06 above twisted facet f144652 nearest vertices 7.8e-14 QH7087 Qhull precision warning: in post-processing (qh_check_maxout) p5236 for f144004 is 0.00013 above twisted facet f159710 nearest vertices 1.2e-13 QH6297 Qhull precision error (qh_check_maxout): large increase in qh.max_outside during post-processing dist 0.00013 (919993296.3x). See warning QH0032/QH0033. Allow with 'Q12' (allow-wide) and 'Pp' Maximum distance of point above facet: 0.00013 (13191992399.9x) Maximum distance of vertex below facet: -1.2e-13 (12.2x) Test -- t8 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6347 qhull precision error (qh_mergefacet): wide merge for facet f33822 into f23677 for mergetype 6 (flip). maxdist 0 (0.0x) mindist -2.4e-12 (236.3x) vertexdist 0.024 Allow with 'Q12' (allow-wide) Maximum distance of point above facet: 1.9e-13 (19.3x) Maximum distance of vertex below facet: -2.7e-13 (26.9x) Test -- t9 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7085 Qhull precision warning: repartition coplanar point p6766 from f44641 as an outside point above twisted facet f59686 dist 0.00017 nearest vertices 1.5e-13 QH7085 Qhull precision warning: repartition coplanar point p6333 from f79975 as an outside point above twisted facet f76440 dist 0.0019 nearest vertices 1.1e-13 QH6347 qhull precision error (qh_mergefacet): wide merge for facet f80579 into f75812 for mergetype 6 (flip). maxdist 0 (0.0x) mindist -9.1e-12 (907.4x) vertexdist 0.029 Allow with 'Q12' (allow-wide) Maximum distance of point above facet: 3.9e-12 (383.9x) Maximum distance of vertex below facet: -1.8e-13 (17.6x) Test -- t10 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7087 Qhull precision warning: in post-processing (qh_check_maxout) p7294 for f134434 is 7.2e-05 above twisted facet f147686 nearest vertices 1.1e-13 QH6297 Qhull precision error (qh_check_maxout): large increase in qh.max_outside during post-processing dist 7.2e-05 (691353684.1x). See warning QH0032/QH0033. Allow with 'Q12' (allow-wide) and 'Pp' Maximum distance of point above facet: 7.2e-05 (7140208545.0x) Maximum distance of vertex below facet: -1.2e-13 (11.7x) 1591314219 Test 10 runs in 12 seconds (ave. 1200 msec) -- rbox 5000 s W1e-13 C1,1e-13 D3 t1 | qhull Q14 d Tv Testing -- rbox 500 s W1e-13 C1,1e-13 D4 t1 | qhull Q14 d Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-609463.log Test -- t1 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7085 Qhull precision warning: repartition coplanar point p948 from f83190 as an outside point above twisted facet f86648 dist 0.00028 nearest vertices 1.1e-13 CPU seconds to compute hull (after input): 0.274 Test -- t2 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.267 Test -- t3 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r38713 and r38597. Nearest v77 and v303 dist 0.05 (3330384581182.4x) Maximum distance of point above facet: 6.2e-13 (38.1x) Maximum distance of vertex below facet: -5.5e-13 (33.5x) Test -- t4 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r13989 and r13927. Nearest v122 and v202 dist 0.14 (9422510226747.0x) Test -- t5 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.418 Test -- t6 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6271 qhull topology error (qh_check_dupridge): wide merge (231006179866.2x wider) due to dupridge between f34685 and f34686 (vertex dist 1.2e-13), merge dist 0.011, while processing p470 Test -- t7 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7085 Qhull precision warning: repartition coplanar point p617 from f25266 as an outside point above twisted facet f65328 dist 0.00047 nearest vertices 1.3e-13 QH7085 Qhull precision warning: repartition coplanar point p605 from f71137 as an outside point above twisted facet f81400 dist 0.021 nearest vertices 1.2e-13 QH6425 Qhull topology error (qh_partitioncoplanar): can not repartition coplanar point p617 from f65328 as outside point above f65328. It previously failed to form a cone of facets, dist 0.00047, nearest vertices 1.3e-13 Maximum distance of vertex below facet: -6.1e-13 (37.6x) Test -- t8 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6271 qhull topology error (qh_check_dupridge): wide merge (1712425744.3x wider) due to dupridge between f42222 and f42213 (vertex dist 1.3e-13), merge dist 0.00016, while processing p901 Test -- t9 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r97497 and r97495. Nearest v951 and v958 dist 0.21 (14211983327451.1x) Test -- t10 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6391 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve opposite oriented ridges r23942 and r23905 in f26657 and f26648. Nearest v57 and v94 dist 0.12 (8422534220006.4x) Maximum distance of point above facet: 2e-13 (12.6x) 1591314224 Test 10 runs in 4 seconds (ave. 400 msec) -- rbox 500 s W1e-13 C1,1e-13 D4 t1 | qhull Q14 d Tv Testing -- rbox 200 s W1e-13 C1,1e-13 D5 t1 | qhull Q14 d Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-276848.log Test -- t1 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f65877 and f65878 have the same vertices (skip 3, skip 3) and same horizon ridges to f36436 and f26957 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f65877 and f65878 have the same vertices (skip 4, skip 4) and same horizon ridges to f36436 and f26957 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r91033 and r90813. Nearest v102 and v243 dist 0.25 (11585979429831.3x) Maximum distance of point above facet: 2.5e-13 (10.7x) Maximum distance of vertex below facet: -8e-13 (34.2x) Test -- t2 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r27312 and r21744. Nearest v8 and v11 dist 0.12 (5599980284995.9x) Maximum distance of vertex below facet: -3.8e-13 (16.3x) Test -- t3 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f76669 and f76670 have the same vertices (skip 1, skip 1) and same horizon ridges to f72263 and f72252 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f76669 and f76670 have the same vertices (skip 2, skip 2) and same horizon ridges to f72263 and f72252 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f76668 and f76672 have the same vertices (skip 1, skip 1) and same horizon ridges to f70929 and f70929 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f76668 and f76672 have the same vertices (skip 2, skip 2) and same horizon ridges to f70929 and f70929 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f76668 and f76672 have the same vertices (skip 5, skip 5) and same horizon ridges to f70929 and f70929 QH7081 qhull precision warning (qh_getpinchedmerges): pinched vertices v231 and v85 (dist 0.15, 1328212115756x) would produce a wide merge for f76671 and f76596. Will merge dupridge instead QH6361 qhull topological error (qh_mark_dupridges): multiple dupridges for f76668 and f76672, including reverse Test -- t4 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r5823 and r3583. Nearest v13 and v33 dist 0.26 (11735381901050.8x) Maximum distance of point above facet: 2.4e-13 (10.0x) Test -- t5 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6347 qhull precision error (qh_mergefacet): wide merge for facet f86767 into f86766 for mergetype 7 (dupridge). maxdist 0 (0.0x) mindist -2.9e-12 (128.8x) vertexdist 0.2 Allow with 'Q12' (allow-wide) Test -- t6 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6391 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve opposite oriented ridges r21534 and r21559 in f18063 and f18083. Nearest v58 and v85 dist 0.29 (13646960554035.8x) Test -- t7 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f18317 and f18319 have the same vertices (skip 1, skip 1) and same horizon ridges to f14054 and f14054 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f18317 and f18319 have the same vertices (skip 2, skip 2) and same horizon ridges to f14054 and f14054 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f18317 and f18319 have the same vertices (skip 3, skip 3) and same horizon ridges to f14054 and f14054 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f18317 and f18319 have the same vertices (skip 5, skip 5) and same horizon ridges to f14054 and f14054 QH6155 qhull topology error (qh_matchdupridge): missing qh_DUPLICATEridge at f18319 skip 3 for new f18317 skip 3 hash 802 ismatch 1. Set by qh_matchneighbor Maximum distance of point above facet: 9.8e-13 (40.9x) Test -- t8 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f86520 and f86528 have the same vertices (skip 1, skip 1) and same horizon ridges to f84820 and f84820 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f86520 and f86528 have the same vertices (skip 2, skip 2) and same horizon ridges to f84820 and f84820 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f86520 and f86528 have the same vertices (skip 3, skip 3) and same horizon ridges to f84820 and f84820 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f86520 and f86528 have the same vertices (skip 4, skip 4) and same horizon ridges to f84820 and f84820 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f86520 and f86528 have the same vertices (skip 5, skip 5) and same horizon ridges to f84820 and f84820 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f86545 and f86546 have the same vertices (skip 1, skip 1) and same horizon ridges to f84922 and f84922 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f86545 and f86546 have the same vertices (skip 2, skip 2) and same horizon ridges to f84922 and f84922 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f86545 and f86546 have the same vertices (skip 3, skip 3) and same horizon ridges to f84922 and f84922 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f86545 and f86546 have the same vertices (skip 4, skip 4) and same horizon ridges to f84922 and f84922 QH6155 qhull topology error (qh_matchdupridge): missing qh_DUPLICATEridge at f86528 skip 3 for new f86520 skip 3 hash 2096 ismatch 1. Set by qh_matchneighbor Maximum distance of point above facet: 6.3e-13 (26.7x) Maximum distance of vertex below facet: -3.4e-13 (14.4x) Test -- t9 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r128601 and r111375. Nearest v29 and v134 dist 0.17 (8013113085774.5x) Test -- t10 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f85245 and f85343 have the same vertices (skip 1, skip 1) and same horizon ridges to f81217 and f81638 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f85245 and f85343 have the same vertices (skip 2, skip 2) and same horizon ridges to f81217 and f81638 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f85245 and f85343 have the same vertices (skip 3, skip 3) and same horizon ridges to f81217 and f81638 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f85245 and f85343 have the same vertices (skip 4, skip 4) and same horizon ridges to f81217 and f81638 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f85245 and f85343 have the same vertices (skip 5, skip 5) and same horizon ridges to f81217 and f81638 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f85275 and f85344 have the same vertices (skip 1, skip 1) and same horizon ridges to f81775 and f81455 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f85275 and f85344 have the same vertices (skip 4, skip 4) and same horizon ridges to f81775 and f81455 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f85275 and f85344 have the same vertices (skip 5, skip 5) and same horizon ridges to f81775 and f81455 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f86001 and f86099 have the same vertices (skip 1, skip 1) and same horizon ridges to f81217 and f81638 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f86001 and f86099 have the same vertices (skip 2, skip 2) and same horizon ridges to f81217 and f81638 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f86001 and f86099 have the same vertices (skip 3, skip 3) and same horizon ridges to f81217 and f81638 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f86001 and f86099 have the same vertices (skip 4, skip 4) and same horizon ridges to f81217 and f81638 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f86001 and f86099 have the same vertices (skip 5, skip 5) and same horizon ridges to f81217 and f81638 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f86031 and f86100 have the same vertices (skip 1, skip 1) and same horizon ridges to f81775 and f81455 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f86031 and f86100 have the same vertices (skip 4, skip 4) and same horizon ridges to f81775 and f81455 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f86031 and f86100 have the same vertices (skip 5, skip 5) and same horizon ridges to f81775 and f81455 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f86757 and f86855 have the same vertices (skip 1, skip 1) and same horizon ridges to f81217 and f81638 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f86757 and f86855 have the same vertices (skip 2, skip 2) and same horizon ridges to f81217 and f81638 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f86757 and f86855 have the same vertices (skip 3, skip 3) and same horizon ridges to f81217 and f81638 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f86757 and f86855 have the same vertices (skip 4, skip 4) and same horizon ridges to f81217 and f81638 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f86757 and f86855 have the same vertices (skip 5, skip 5) and same horizon ridges to f81217 and f81638 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f86787 and f86856 have the same vertices (skip 1, skip 1) and same horizon ridges to f81775 and f81455 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f86787 and f86856 have the same vertices (skip 4, skip 4) and same horizon ridges to f81775 and f81455 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f86787 and f86856 have the same vertices (skip 5, skip 5) and same horizon ridges to f81775 and f81455 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f87513 and f87611 have the same vertices (skip 1, skip 1) and same horizon ridges to f81217 and f81638 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f87513 and f87611 have the same vertices (skip 2, skip 2) and same horizon ridges to f81217 and f81638 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f87513 and f87611 have the same vertices (skip 3, skip 3) and same horizon ridges to f81217 and f81638 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f87513 and f87611 have the same vertices (skip 4, skip 4) and same horizon ridges to f81217 and f81638 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f87513 and f87611 have the same vertices (skip 5, skip 5) and same horizon ridges to f81217 and f81638 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f87543 and f87612 have the same vertices (skip 1, skip 1) and same horizon ridges to f81775 and f81455 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f87543 and f87612 have the same vertices (skip 4, skip 4) and same horizon ridges to f81775 and f81455 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f87543 and f87612 have the same vertices (skip 5, skip 5) and same horizon ridges to f81775 and f81455 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f88269 and f88367 have the same vertices (skip 1, skip 1) and same horizon ridges to f81217 and f81638 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f88269 and f88367 have the same vertices (skip 2, skip 2) and same horizon ridges to f81217 and f81638 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f88269 and f88367 have the same vertices (skip 3, skip 3) and same horizon ridges to f81217 and f81638 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f88269 and f88367 have the same vertices (skip 4, skip 4) and same horizon ridges to f81217 and f81638 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f88269 and f88367 have the same vertices (skip 5, skip 5) and same horizon ridges to f81217 and f81638 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f88299 and f88368 have the same vertices (skip 1, skip 1) and same horizon ridges to f81775 and f81455 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f88299 and f88368 have the same vertices (skip 4, skip 4) and same horizon ridges to f81775 and f81455 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f88299 and f88368 have the same vertices (skip 5, skip 5) and same horizon ridges to f81775 and f81455 QH7081 qhull precision warning (qh_getpinchedmerges): pinched vertices v256 and v92 (dist 0.051, 102248841159x) would produce a wide merge for f88419 and f88416. Will merge dupridge instead QH6361 qhull topological error (qh_mark_dupridges): multiple dupridges for f88269 and f88367, including reverse Maximum distance of vertex below facet: -5e-13 (22.0x) 1591314228 Test 10 runs in 3 seconds (ave. 300 msec) -- rbox 200 s W1e-13 C1,1e-13 D5 t1 | qhull Q14 d Tv Testing -- rbox 100 s W1e-13 C1,1e-13 D6 t1 | qhull Q14 d Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-944233.log Test -- t1 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r20591 and r20602. Nearest v9 and v14 dist 0.16 (5355849098491.0x) Test -- t2 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f36893 and f36910 have the same vertices (skip 1, skip 1) and same horizon ridges to f13135 and f13135 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f36893 and f36910 have the same vertices (skip 2, skip 2) and same horizon ridges to f13135 and f13135 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f36893 and f36910 have the same vertices (skip 3, skip 3) and same horizon ridges to f13135 and f13135 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f36893 and f36910 have the same vertices (skip 4, skip 4) and same horizon ridges to f13135 and f13135 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f36893 and f36910 have the same vertices (skip 6, skip 6) and same horizon ridges to f13135 and f13135 QH6155 qhull topology error (qh_matchdupridge): missing qh_DUPLICATEridge at f36910 skip 3 for new f36893 skip 3 hash 649 ismatch 1. Set by qh_matchneighbor Test -- t3 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f42897 and f42914 have the same vertices (skip 1, skip 1) and same horizon ridges to f25665 and f25167 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f42897 and f42914 have the same vertices (skip 3, skip 3) and same horizon ridges to f25665 and f25167 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f42897 and f42914 have the same vertices (skip 4, skip 4) and same horizon ridges to f25665 and f25167 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f42897 and f42914 have the same vertices (skip 6, skip 6) and same horizon ridges to f25665 and f25167 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f45327 and f45330 have the same vertices (skip 1, skip 1) and same horizon ridges to f7820 and f7820 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f45327 and f45330 have the same vertices (skip 3, skip 3) and same horizon ridges to f7820 and f7820 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f45327 and f45330 have the same vertices (skip 4, skip 4) and same horizon ridges to f7820 and f7820 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r25070 and r53364. Nearest v18 and v53 dist 0.22 (7683622046685.1x) Test -- t4 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f51508 and f51510 have the same vertices (skip 1, skip 1) and same horizon ridges to f30507 and f39669 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f51508 and f51510 have the same vertices (skip 2, skip 2) and same horizon ridges to f30507 and f39669 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f51508 and f51510 have the same vertices (skip 5, skip 5) and same horizon ridges to f30507 and f39669 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f51508 and f51510 have the same vertices (skip 6, skip 6) and same horizon ridges to f30507 and f39669 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f51507 and f51511 have the same vertices (skip 1, skip 1) and same horizon ridges to f19171 and f30753 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f51507 and f51511 have the same vertices (skip 2, skip 2) and same horizon ridges to f19171 and f30753 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f51507 and f51511 have the same vertices (skip 3, skip 3) and same horizon ridges to f19171 and f30753 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f51507 and f51511 have the same vertices (skip 5, skip 5) and same horizon ridges to f19171 and f30753 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f51507 and f51511 have the same vertices (skip 6, skip 6) and same horizon ridges to f19171 and f30753 QH6155 qhull topology error (qh_matchdupridge): missing qh_DUPLICATEridge at f51511 skip 5 for new f51507 skip 5 hash 459 ismatch 1. Set by qh_matchneighbor Test -- t5 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r33252 and r36487. Nearest v21 and v45 dist 0.37 (12223161979313.1x) Maximum distance of vertex below facet: -9.5e-13 (29.7x) Test -- t6 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r20356 and r21043. Nearest v17 and v41 dist 0.35 (11546961641179.1x) Maximum distance of vertex below facet: -4.5e-13 (14.0x) Test -- t7 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f22426 and f22461 have the same vertices (skip 2, skip 2) and same horizon ridges to f13937 and f13937 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f22426 and f22461 have the same vertices (skip 4, skip 4) and same horizon ridges to f13937 and f13937 QH7081 qhull precision warning (qh_getpinchedmerges): pinched vertices v59 and v24 (dist 0.12, 1174239239079x) would produce a wide merge for f22426 and f22461. Will merge dupridge instead QH6361 qhull topological error (qh_mark_dupridges): multiple dupridges for f22426 and f22461, including reverse Test -- t8 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r20549 and r12171. Nearest v11 and v37 dist 0.2 (6991485173088.3x) Test -- t9 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f9958 and f9968 have the same vertices (skip 1, skip 1) and same horizon ridges to f6116 and f3475 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f9958 and f9968 have the same vertices (skip 2, skip 2) and same horizon ridges to f6116 and f3475 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f9958 and f9968 have the same vertices (skip 3, skip 3) and same horizon ridges to f6116 and f3475 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f9958 and f9968 have the same vertices (skip 5, skip 5) and same horizon ridges to f6116 and f3475 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f9958 and f9968 have the same vertices (skip 6, skip 6) and same horizon ridges to f6116 and f3475 QH6361 qhull topological error (qh_mark_dupridges): multiple dupridges for f9958 and f9968, including reverse Maximum distance of vertex below facet: -5.4e-13 (18.5x) Test -- t10 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6391 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve opposite oriented ridges r553 and r464 in f569 and f42. Nearest v2 and v17 dist 0.5 (17642408039144.3x) 1591314232 Test 10 runs in 3 seconds (ave. 300 msec) -- rbox 100 s W1e-13 C1,1e-13 D6 t1 | qhull Q14 d Tv ==================== == Voronoi diagram of rotated mesh with wide, 1e-8 pairs == All fail at C1,1e-12 ==================== Testing -- rbox 10000 M3,4 C1,1e-8 D2 t1 | qhull QR3 Q14 v Qbb Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-544664.log Test -- t1 CPU seconds to compute hull (after input): 0.138 Test -- t2 CPU seconds to compute hull (after input): 0.133 Test -- t3 CPU seconds to compute hull (after input): 0.128 Test -- t4 CPU seconds to compute hull (after input): 0.13 Test -- t5 CPU seconds to compute hull (after input): 0.128 Test -- t6 CPU seconds to compute hull (after input): 0.128 Test -- t7 CPU seconds to compute hull (after input): 0.129 Test -- t8 CPU seconds to compute hull (after input): 0.149 Test -- t9 CPU seconds to compute hull (after input): 0.138 Test -- t10 CPU seconds to compute hull (after input): 0.133 1591314301 Test 10 runs in 68 seconds (ave. 6800 msec) -- rbox 10000 M3,4 C1,1e-8 D2 t1 | qhull QR3 Q14 v Qbb Tv Testing -- rbox 2000 M3,4,5 C1,1e-8 D3 t1 | qhull QR3 Q14 v Qbb Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-354577.log Test -- t1 QH7081 qhull precision warning (qh_getpinchedmerges): pinched vertices v1581 and v128 (dist 1.5e-08, 5900x) would produce a wide merge for f67521 and f67517. Will merge dupridge instead QH6271 qhull topology error (qh_check_dupridge): wide merge (45056588.6x wider) due to dupridge between f67521 and f67517 (vertex dist 1.5e-08), merge dist 0.00012, while processing p548 Test -- t2 CPU seconds to compute hull (after input): 0.111 Test -- t3 CPU seconds to compute hull (after input): 0.109 Test -- t4 QH7081 qhull precision warning (qh_getpinchedmerges): pinched vertices v942 and v599 (dist 1e-08, 4123x) would produce a wide merge for f60963 and f60977. Will merge dupridge instead QH6271 qhull topology error (qh_check_dupridge): wide merge (95642702.5x wider) due to dupridge between f60963 and f60977 (vertex dist 1e-08), merge dist 0.00024, while processing p1401 Test -- t5 QH7081 qhull precision warning (qh_getpinchedmerges): pinched vertices v658 and v408 (dist 1.3e-08, 5100x) would produce a wide merge for f17839 and f17857. Will merge dupridge instead QH6271 qhull topology error (qh_check_dupridge): wide merge (168477336.0x wider) due to dupridge between f17839 and f17857 (vertex dist 1.3e-08), merge dist 0.00042, while processing p643 Test -- t6 QH6271 qhull topology error (qh_check_dupridge): wide merge (145857611.2x wider) due to dupridge between f71951 and f71942 (vertex dist 1.5e-08), merge dist 0.00036, while processing p2410 Test -- t7 CPU seconds to compute hull (after input): 0.111 Test -- t8 QH7081 qhull precision warning (qh_getpinchedmerges): pinched vertices v2061 and v542 (dist 1.1e-08, 4571x) would produce a wide merge for f70338 and f70340. Will merge dupridge instead QH6271 qhull topology error (qh_check_dupridge): wide merge (123.4x wider) due to dupridge between f70338 and f70340 (vertex dist 1.1e-08), merge dist 3e-10, while processing p2537 Test -- t9 QH7081 qhull precision warning (qh_getpinchedmerges): pinched vertices v2465 and v1930 (dist 1.7e-08, 7048x) would produce a wide merge for f80589 and f80576. Will merge dupridge instead QH6271 qhull topology error (qh_check_dupridge): wide merge (106850984.5x wider) due to dupridge between f80589 and f80576 (vertex dist 1.7e-08), merge dist 0.00026, while processing p535 Test -- t10 CPU seconds to compute hull (after input): 0.106 1591314308 Test 10 runs in 7 seconds (ave. 700 msec) -- rbox 2000 M3,4,5 C1,1e-8 D3 t1 | qhull QR3 Q14 v Qbb Tv Testing -- rbox 600 M3,4,5 C1,1e-8 D4 t1 | qhull QR3 Q14 v Qbb Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-622393.log Test -- t1 CPU seconds to compute hull (after input): 0.221 Test -- t2 CPU seconds to compute hull (after input): 0.257 Test -- t3 CPU seconds to compute hull (after input): 0.23 Test -- t4 CPU seconds to compute hull (after input): 0.235 Test -- t5 CPU seconds to compute hull (after input): 0.247 Test -- t6 CPU seconds to compute hull (after input): 0.223 Test -- t7 QH7081 qhull precision warning (qh_getpinchedmerges): pinched vertices v529 and v929 (dist 8.7e-09, 7425x) would produce a wide merge for f112419 and f112421. Will merge dupridge instead QH6271 qhull topology error (qh_check_dupridge): wide merge (172594538.9x wider) due to dupridge between f112419 and f112421 (vertex dist 1.3e-08), merge dist 0.0002, while processing p380 Test -- t8 CPU seconds to compute hull (after input): 0.223 Test -- t9 CPU seconds to compute hull (after input): 0.22 Test -- t10 CPU seconds to compute hull (after input): 0.221 1591314317 Test 10 runs in 8 seconds (ave. 800 msec) -- rbox 600 M3,4,5 C1,1e-8 D4 t1 | qhull QR3 Q14 v Qbb Tv Testing -- rbox 300 M3,4,5 C1,1e-8 D5 t1 | qhull QR3 Q14 v Qbb Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-890209.log Test -- t1 CPU seconds to compute hull (after input): 0.803 Test -- t2 CPU seconds to compute hull (after input): 0.804 Test -- t3 CPU seconds to compute hull (after input): 0.833 Test -- t4 CPU seconds to compute hull (after input): 0.848 Test -- t5 CPU seconds to compute hull (after input): 0.785 Test -- t6 CPU seconds to compute hull (after input): 0.762 Test -- t7 CPU seconds to compute hull (after input): 0.878 Test -- t8 CPU seconds to compute hull (after input): 0.803 Test -- t9 CPU seconds to compute hull (after input): 0.819 Test -- t10 CPU seconds to compute hull (after input): 0.808 1591314334 Test 10 runs in 16 seconds (ave. 1600 msec) -- rbox 300 M3,4,5 C1,1e-8 D5 t1 | qhull QR3 Q14 v Qbb Tv skip D6, millions of vertices ============================ == Delaunay triangulation of nearly cospherical point pairs with Qbb drum == Qbb makes this the most difficult distribution for Qhull, only 100 points ============================ Testing -- rbox 1000 s C1,1e-13 D3 t1 | qhull Q14 d Qbb Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-492795.log Test -- t1 CPU seconds to compute hull (after input): 0.043 Test -- t2 CPU seconds to compute hull (after input): 0.042 Test -- t3 CPU seconds to compute hull (after input): 0.042 Test -- t4 CPU seconds to compute hull (after input): 0.042 Test -- t5 CPU seconds to compute hull (after input): 0.043 Test -- t6 CPU seconds to compute hull (after input): 0.043 Test -- t7 CPU seconds to compute hull (after input): 0.043 Test -- t8 CPU seconds to compute hull (after input): 0.046 Test -- t9 CPU seconds to compute hull (after input): 0.043 Test -- t10 CPU seconds to compute hull (after input): 0.042 1591314339 Test 10 runs in 4 seconds (ave. 400 msec) -- rbox 1000 s C1,1e-13 D3 t1 | qhull Q14 d Qbb Tv Testing -- rbox 100 s C1,1e-13 D4 t1 | qhull Q14 d Qbb Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-626703.log Test -- t1 CPU seconds to compute hull (after input): 0.02 Test -- t2 QH6271 qhull topology error (qh_check_dupridge): wide merge (499726909788.7x wider) due to dupridge between f15279 and f15281 (vertex dist 0.0026), merge dist 0.0088, while processing p150 Test -- t3 QH6271 qhull topology error (qh_check_dupridge): wide merge (707750430102.1x wider) due to dupridge between f11994 and f12093 (vertex dist 0.1), merge dist 0.012, while processing p104 Test -- t4 CPU seconds to compute hull (after input): 0.021 Test -- t5 QH6271 qhull topology error (qh_check_dupridge): wide merge (119659788166.1x wider) due to dupridge between f7842 and f7823 (vertex dist 0.0016), merge dist 0.0021, while processing p55 Test -- t6 CPU seconds to compute hull (after input): 0.02 Test -- t7 QH6271 qhull topology error (qh_check_dupridge): wide merge (826947278897.3x wider) due to dupridge between f10941 and f10938 (vertex dist 0.12), merge dist 0.014, while processing p174 Test -- t8 QH6271 qhull topology error (qh_check_dupridge): wide merge (332360605318.1x wider) due to dupridge between f12931 and f12932 (vertex dist 0.05), merge dist 0.0058, while processing p72 Test -- t9 CPU seconds to compute hull (after input): 0.02 Test -- t10 QH6271 qhull topology error (qh_check_dupridge): wide merge (279982910429.7x wider) due to dupridge between f13107 and f13053 (vertex dist 0.0087), merge dist 0.0049, while processing p148 1591314342 Test 10 runs in 2 seconds (ave. 200 msec) -- rbox 100 s C1,1e-13 D4 t1 | qhull Q14 d Qbb Tv Testing -- rbox 50 s C1,1e-13 D5 t1 | qhull Q14 d Qbb Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-227134.log Test -- t1 QH6271 qhull topology error (qh_check_dupridge): wide merge (4995107542900.0x wider) due to dupridge between f16194 and f16417 (vertex dist 0.14), merge dist 0.12, while processing p13 Test -- t2 CPU seconds to compute hull (after input): 0.045 Test -- t3 CPU seconds to compute hull (after input): 0.043 Test -- t4 CPU seconds to compute hull (after input): 0.042 Test -- t5 QH6271 qhull topology error (qh_check_dupridge): wide merge (145603403574.2x wider) due to dupridge between f18407 and f18342 (vertex dist 0.1), merge dist 0.0034, while processing p84 Test -- t6 CPU seconds to compute hull (after input): 0.044 Test -- t7 QH6271 qhull topology error (qh_check_dupridge): wide merge (45196191923.8x wider) due to dupridge between f18796 and f18794 (vertex dist 0.023), merge dist 0.00098, while processing p69 Test -- t8 CPU seconds to compute hull (after input): 0.043 Test -- t9 QH6271 qhull topology error (qh_check_dupridge): wide merge (423011392553.9x wider) due to dupridge between f23440 and f23439 (vertex dist 0.0016), merge dist 0.0097, while processing p38 Test -- t10 QH7081 qhull precision warning (qh_getpinchedmerges): pinched vertices v34 and v17 (dist 0.0067, 299162469040x) would produce a wide merge for f14316 and f14545. Will merge dupridge instead QH6271 qhull topology error (qh_check_dupridge): wide merge (878926583303.0x wider) due to dupridge between f14316 and f14545 (vertex dist 0.017), merge dist 0.02, while processing p66 1591314345 Test 10 runs in 2 seconds (ave. 200 msec) -- rbox 50 s C1,1e-13 D5 t1 | qhull Q14 d Qbb Tv Testing -- rbox 50 s C1,1e-13 D6 t1 | qhull Q14 d Qbb Tv >/d/bash/var/tmp/qtest-2020-06-04/qhull-827565.log Test -- t1 QH6271 qhull topology error (qh_check_dupridge): wide merge (5897312052479.2x wider) due to dupridge between f18531 and f18530 (vertex dist 0.092), merge dist 0.19, while processing p77 Test -- t2 QH6271 qhull topology error (qh_check_dupridge): wide merge (1724107680480.5x wider) due to dupridge between f25295 and f25296 (vertex dist 0.00061), merge dist 0.054, while processing p3 Test -- t3 QH6271 qhull topology error (qh_check_dupridge): wide merge (798302749670.2x wider) due to dupridge between f18579 and f18574 (vertex dist 0.084), merge dist 0.024, while processing p83 Test -- t4 QH7081 qhull precision warning (qh_getpinchedmerges): pinched vertices v33 and v2 (dist 0.016, 535923660887x) would produce a wide merge for f13575 and f13490. Will merge dupridge instead QH6271 qhull topology error (qh_check_dupridge): wide merge (527892127468.9x wider) due to dupridge between f13575 and f13490 (vertex dist 0.016), merge dist 0.016, while processing p23 Test -- t5 QH6271 qhull topology error (qh_check_dupridge): wide merge (50044710155.4x wider) due to dupridge between f13023 and f13391 (vertex dist 0.2), merge dist 0.0017, while processing p75 Test -- t6 QH7081 qhull precision warning (qh_getpinchedmerges): pinched vertices v57 and v22 (dist 0.0063, 221587513534x) would produce a wide merge for f39570 and f39365. Will merge dupridge instead QH6271 qhull topology error (qh_check_dupridge): wide merge (2548029701901.9x wider) due to dupridge between f39570 and f39365 (vertex dist 0.0063), merge dist 0.072, while processing p52 Test -- t7 QH7081 qhull precision warning (qh_getpinchedmerges): pinched vertices v25 and v57 (dist 0.0017, 55693747840x) would produce a wide merge for f30840 and f30837. Will merge dupridge instead QH6271 qhull topology error (qh_check_dupridge): wide merge (1650435777757.3x wider) due to dupridge between f30625 and f30623 (vertex dist 0.012), merge dist 0.051, while processing p52 Test -- t8 QH7081 qhull precision warning (qh_getpinchedmerges): pinched vertices v49 and v29 (dist 0.00012, 4740313861x) would produce a wide merge for f46587 and f46678. Will merge dupridge instead QH6271 qhull topology error (qh_check_dupridge): wide merge (139144921895.4x wider) due to dupridge between f46374 and f46372 (vertex dist 0.025), merge dist 0.0036, while processing p50 Test -- t9 QH6271 qhull topology error (qh_check_dupridge): wide merge (556932183829.0x wider) due to dupridge between f13608 and f13610 (vertex dist 0.022), merge dist 0.017, while processing p50 Test -- t10 QH7081 qhull precision warning (qh_getpinchedmerges): pinched vertices v56 and v42 (dist 0.00098, 34927769758x) would produce a wide merge for f30280 and f30270. Will merge dupridge instead QH6271 qhull topology error (qh_check_dupridge): wide merge (216561738457.3x wider) due to dupridge between f30280 and f30270 (vertex dist 0.00098), merge dist 0.0061, while processing p92 1591314348 Test 10 runs in 2 seconds (ave. 200 msec) -- rbox 50 s C1,1e-13 D6 t1 | qhull Q14 d Qbb Tv ============================ == Time for pinched Delaunay triangulation of random point pairs (Q14) with bounding box ============================ Testing -- rbox 50000 C1,2e-13 c G2.0 D2 t1 | qhull Q14 d Qbb >/d/bash/var/tmp/qtest-2020-06-04/qhull-427996.log Test -- t1 CPU seconds to compute hull (after input): 0.499 Test -- t2 CPU seconds to compute hull (after input): 0.475 Test -- t3 CPU seconds to compute hull (after input): 0.478 Test -- t4 CPU seconds to compute hull (after input): 0.478 Test -- t5 CPU seconds to compute hull (after input): 0.449 Test -- t6 CPU seconds to compute hull (after input): 0.496 Test -- t7 CPU seconds to compute hull (after input): 0.503 Test -- t8 CPU seconds to compute hull (after input): 0.494 Test -- t9 CPU seconds to compute hull (after input): 0.479 Test -- t10 CPU seconds to compute hull (after input): 0.48 1591314359 Test 10 runs in 10 seconds (ave. 1000 msec) -- rbox 50000 C1,2e-13 c G2.0 D2 t1 | qhull Q14 d Qbb Testing -- rbox 10000 C1,2e-13 c G2.0 D3 t1 | qhull Q14 d Qbb >/d/bash/var/tmp/qtest-2020-06-04/qhull-296243.log Test -- t1 CPU seconds to compute hull (after input): 0.392 Test -- t2 CPU seconds to compute hull (after input): 0.386 Test -- t3 CPU seconds to compute hull (after input): 0.411 Test -- t4 CPU seconds to compute hull (after input): 0.399 Test -- t5 CPU seconds to compute hull (after input): 0.407 Test -- t6 CPU seconds to compute hull (after input): 0.387 Test -- t7 CPU seconds to compute hull (after input): 0.386 Test -- t8 CPU seconds to compute hull (after input): 0.408 Test -- t9 CPU seconds to compute hull (after input): 0.404 Test -- t10 CPU seconds to compute hull (after input): 0.367 1591314366 Test 10 runs in 6 seconds (ave. 600 msec) -- rbox 10000 C1,2e-13 c G2.0 D3 t1 | qhull Q14 d Qbb Testing -- rbox 3000 C1,2e-13 c G2.0 D4 t1 | qhull Q14 d Qbb >/d/bash/var/tmp/qtest-2020-06-04/qhull-564059.log Test -- t1 QH6347 qhull precision error (qh_mergefacet): wide merge for facet f190685 into f190684 for mergetype 3 (concave). maxdist 0 (0.0x) mindist -9.2e-05 (1409066448.7x) vertexdist 0.11 Allow with 'Q12' (allow-wide) Test -- t2 QH7085 Qhull precision warning: repartition coplanar point p4824 from f261866 as an outside point above twisted facet f261713 dist 0.00066 nearest vertices 2e-13 CPU seconds to compute hull (after input): 0.976 Test -- t3 QH7085 Qhull precision warning: repartition coplanar point p5663 from f370475 as an outside point above twisted facet f370562 dist 0.0043 nearest vertices 3e-13 QH7085 Qhull precision warning: repartition coplanar point p2873 from f370475 as an outside point above twisted facet f370562 dist 0.00034 nearest vertices 3e-13 QH7085 Qhull precision warning: repartition coplanar point p2311 from f370475 as an outside point above twisted facet f370562 dist 0.015 nearest vertices 3e-13 CPU seconds to compute hull (after input): 0.956 Test -- t4 CPU seconds to compute hull (after input): 0.941 Test -- t5 QH7085 Qhull precision warning: repartition coplanar point p1727 from f29969 as an outside point above twisted facet f28893 dist 0.00066 nearest vertices 2e-13 CPU seconds to compute hull (after input): 0.989 Test -- t6 CPU seconds to compute hull (after input): 0.993 Test -- t7 QH7085 Qhull precision warning: repartition coplanar point p512 from f121648 as an outside point above twisted facet f121661 dist 0.0011 nearest vertices 2e-13 QH6347 qhull precision error (qh_mergefacet): wide merge for facet f231543 into f231542 for mergetype 3 (concave). maxdist 0 (0.0x) mindist -0.00026 (4040593870.1x) vertexdist 0.094 Allow with 'Q12' (allow-wide) Test -- t8 QH7085 Qhull precision warning: repartition coplanar point p2360 from f22149 as an outside point above twisted facet f20962 dist 0.0017 nearest vertices 2.1e-13 QH7085 Qhull precision warning: repartition coplanar point p5349 from f61378 as an outside point above twisted facet f61399 dist 0.0056 nearest vertices 1.5e-13 QH7085 Qhull precision warning: repartition coplanar point p366 from f61425 as an outside point above twisted facet f61399 dist 0.0063 nearest vertices 1.5e-13 QH7085 Qhull precision warning: repartition coplanar point p2878 from f74011 as an outside point above twisted facet f61399 dist 0.017 nearest vertices 1.5e-13 CPU seconds to compute hull (after input): 0.997 Test -- t9 CPU seconds to compute hull (after input): 0.924 Test -- t10 CPU seconds to compute hull (after input): 1.004 1591314378 Test 10 runs in 11 seconds (ave. 1100 msec) -- rbox 3000 C1,2e-13 c G2.0 D4 t1 | qhull Q14 d Qbb Testing -- rbox 500 C1,2e-13 c G2.0 D5 t1 | qhull Q14 d Qbb >/d/bash/var/tmp/qtest-2020-06-04/qhull-965783.log Test -- t1 CPU seconds to compute hull (after input): 0.901 Test -- t2 QH7085 Qhull precision warning: repartition coplanar point p441 from f155582 as an outside point above twisted facet f155687 dist 0.0012 nearest vertices 2.7e-13 CPU seconds to compute hull (after input): 1.069 Test -- t3 CPU seconds to compute hull (after input): 0.925 Test -- t4 QH7085 Qhull precision warning: repartition coplanar point p843 from f17592 as an outside point above twisted facet f17727 dist 0.0012 nearest vertices 3e-13 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r7446 and r7444. Nearest v41 and v78 dist 0.61 (6635311317759.2x) Test -- t5 QH7085 Qhull precision warning: repartition coplanar point p38 from f99761 as an outside point above twisted facet f84442 dist 0.0045 nearest vertices 2.8e-13 CPU seconds to compute hull (after input): 0.911 Test -- t6 CPU seconds to compute hull (after input): 0.961 Test -- t7 QH7085 Qhull precision warning: repartition coplanar point p268 from f291988 as an outside point above twisted facet f291679 dist 0.013 nearest vertices 2.3e-13 CPU seconds to compute hull (after input): 0.888 Test -- t8 CPU seconds to compute hull (after input): 0.938 Test -- t9 QH7085 Qhull precision warning: repartition coplanar point p925 from f317207 as an outside point above twisted facet f317303 dist 0.014 nearest vertices 2.7e-13 QH6348 qhull precision error (qh_mergefacet): wide merge for pinched facet f317430 into f317603 for mergetype 3 (concave). maxdist 0 (0x) mindist -0.002 (20692770256.2x) vertexdist 2.2e-13 Allow with 'Q12' (allow-wide) Test -- t10 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r44665 and r44664. Nearest v253 and v490 dist 0.58 (6291651853148.8x) 1591314389 Test 10 runs in 10 seconds (ave. 1000 msec) -- rbox 500 C1,2e-13 c G2.0 D5 t1 | qhull Q14 d Qbb Testing -- rbox 100 C1,2e-13 c G2.0 D6 t1 | qhull Q14 d Qbb >/d/bash/var/tmp/qtest-2020-06-04/qhull-834030.log Test -- t1 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r40264 and r40261. Nearest v24 and v29 dist 0.8 (6057456805330.6x) Test -- t2 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r22036 and r22035. Nearest v38 and v64 dist 1.2 (8992021169760.2x) Test -- t3 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r140925 and r140923. Nearest v124 and v149 dist 0.74 (5629429151422.8x) Test -- t4 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r41562 and r41555. Nearest v13 and v24 dist 0.52 (3937835544171.1x) Test -- t5 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r10090 and r10088. Nearest v21 and v45 dist 0.44 (3372974355622.5x) Test -- t6 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r104203 and r104152. Nearest v12 and v127 dist 0.51 (3899853567278.4x) Test -- t7 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r113761 and r113750. Nearest v90 and v144 dist 0.54 (4106052672638.0x) Test -- t8 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r64014 and r63556. Nearest v59 and v79 dist 0.72 (5474375529407.1x) Test -- t9 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r62473 and r62470. Nearest v23 and v86 dist 0.76 (5797319173797.8x) Test -- t10 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r56091 and r56070. Nearest v24 and v32 dist 0.68 (5202677736978.0x) 1591314396 Test 10 runs in 6 seconds (ave. 600 msec) -- rbox 100 C1,2e-13 c G2.0 D6 t1 | qhull Q14 d Qbb ============================ == Time for pinched Delaunay triangulation of random point pairs (Q14, Q12) == qh_next_facetmerge, qh_findbesthorizon (qh_distplane) ============================ Testing -- rbox 50000 C1,2e-13 D2 t1 | qhull Q14 d Qbb >/d/bash/var/tmp/qtest-2020-06-04/qhull-568369.log Test -- t1 CPU seconds to compute hull (after input): 0.529 Test -- t2 CPU seconds to compute hull (after input): 0.544 Test -- t3 CPU seconds to compute hull (after input): 0.462 Test -- t4 CPU seconds to compute hull (after input): 0.539 Test -- t5 CPU seconds to compute hull (after input): 0.514 Test -- t6 CPU seconds to compute hull (after input): 0.482 Test -- t7 CPU seconds to compute hull (after input): 0.46 Test -- t8 CPU seconds to compute hull (after input): 0.522 Test -- t9 CPU seconds to compute hull (after input): 0.499 Test -- t10 CPU seconds to compute hull (after input): 0.478 1591314407 Test 10 runs in 10 seconds (ave. 1000 msec) -- rbox 50000 C1,2e-13 D2 t1 | qhull Q14 d Qbb Testing -- rbox 5000 C1,2e-13 D3 t1 | qhull Q14 d Qbb >/d/bash/var/tmp/qtest-2020-06-04/qhull-436616.log Test -- t1 CPU seconds to compute hull (after input): 0.35 Maximum distance of vertex below facet: -1.1e-13 (11.0x) Test -- t2 CPU seconds to compute hull (after input): 0.311 Maximum distance of vertex below facet: -1.3e-13 (12.7x) Test -- t3 CPU seconds to compute hull (after input): 0.36 Maximum distance of vertex below facet: -1.5e-13 (15.2x) Test -- t4 CPU seconds to compute hull (after input): 0.321 Test -- t5 CPU seconds to compute hull (after input): 0.36 Test -- t6 CPU seconds to compute hull (after input): 0.347 Test -- t7 CPU seconds to compute hull (after input): 0.327 Maximum distance of point above facet: 1.4e-13 (13.6x) Maximum distance of vertex below facet: -1.4e-13 (13.6x) Test -- t8 CPU seconds to compute hull (after input): 0.32 Maximum distance of point above facet: 1.2e-13 (12.4x) Maximum distance of vertex below facet: -1.3e-13 (12.7x) Test -- t9 QH6271 qhull topology error (qh_check_dupridge): wide merge (2392033422.9x wider) due to dupridge between f123716 and f123715 (vertex dist 2.4e-13), merge dist 0.0004, while processing p8866 Maximum distance of point above facet: 1.7e-13 (16.5x) Test -- t10 CPU seconds to compute hull (after input): 0.291 1591314413 Test 10 runs in 5 seconds (ave. 500 msec) -- rbox 5000 C1,2e-13 D3 t1 | qhull Q14 d Qbb Testing -- rbox 500 C1,2e-13 D4 t1 | qhull Q12 Q14 d Qbb >/d/bash/var/tmp/qtest-2020-06-04/qhull-637478.log Test -- t1 CPU seconds to compute hull (after input): 0.265 Maximum distance of point above facet: 1.7e-13 (10.4x) Test -- t2 CPU seconds to compute hull (after input): 0.279 Test -- t3 CPU seconds to compute hull (after input): 0.265 Test -- t4 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r37323 and r37309. Nearest v145 and v655 dist 0.067 (4459578188183.3x) Test -- t5 CPU seconds to compute hull (after input): 0.259 Maximum distance of point above facet: 2.1e-13 (12.9x) Maximum distance of vertex below facet: -0.00072 (43999621075.0x) Test -- t6 CPU seconds to compute hull (after input): 0.243 Test -- t7 QH7085 Qhull precision warning: repartition coplanar point p939 from f58978 as an outside point above twisted facet f53492 dist 0.00041 nearest vertices 2.1e-13 CPU seconds to compute hull (after input): 0.252 Test -- t8 QH6391 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve opposite oriented ridges r49440 and r49431 in f83434 and f83454. Nearest v702 and v749 dist 0.13 (8887619111449.9x) Test -- t9 CPU seconds to compute hull (after input): 0.284 Test -- t10 CPU seconds to compute hull (after input): 0.283 Maximum distance of point above facet: 2.2e-13 (13.3x) Maximum distance of vertex below facet: -2.2e-13 (13.3x) 1591314419 Test 10 runs in 5 seconds (ave. 500 msec) -- rbox 500 C1,2e-13 D4 t1 | qhull Q12 Q14 d Qbb Testing -- rbox 300 C1,2e-13 D5 t1 | qhull Q12 Q14 d Qbb >/d/bash/var/tmp/qtest-2020-06-04/qhull-304863.log Test -- t1 QH6271 qhull topology error (qh_check_dupridge): wide merge (5570546919.7x wider) due to dupridge between f164113 and f164214 (vertex dist 2.2e-13), merge dist 0.0012, while processing p459 QH6418 qhull precision error (qh_merge_twisted): twisted facet f151765 with pinched vertices. Could merge vertices, but too wide to merge into neighbor. mindist -0.019 maxdist 0 vertexdist 3.3e-13 neighbor f170719 mindist -0.014 maxdist 0 Maximum distance of point above facet: 2.5e-13 (10.2x) Maximum distance of vertex below facet: -0.0012 (50158760830.2x) Test -- t2 QH6271 qhull topology error (qh_check_dupridge): wide merge (347037085657.3x wider) due to dupridge between f142397 and f202075 (vertex dist 2e-13), merge dist 0.1, while processing p329 QH6271 qhull topology error (qh_check_dupridge): wide merge (18938032507.7x wider) due to dupridge between f345584 and f345474 (vertex dist 2.9e-13), merge dist 0.0056, while processing p557 CPU seconds to compute hull (after input): 1.234 Maximum distance of point above facet: 2.9e-13 (11.9x) Maximum distance of vertex below facet: -0.017 (687191049377.1x) Test -- t3 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r23254 and r23262. Nearest v99 and v153 dist 0.14 (6271081023221.3x) Test -- t4 QH6271 qhull topology error (qh_check_dupridge): wide merge (454633750155.1x wider) due to dupridge between f270523 and f270385 (vertex dist 2.5e-13), merge dist 0.088, while processing p419 QH6391 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve opposite oriented ridges r200444 and r200522 in f270385 and f309294. Nearest v250 and v544 dist 0.39 (16854722445792.8x) Maximum distance of point above facet: 0.00092 (37271597143.0x) Maximum distance of vertex below facet: -0.088 (3584450304447.4x) Test -- t5 QH7085 Qhull precision warning: repartition coplanar point p35 from f123614 as an outside point above twisted facet f123219 dist 4.5e-05 nearest vertices 3.3e-13 QH6271 qhull topology error (qh_check_dupridge): wide merge (878413113784.2x wider) due to dupridge between f164350 and f164337 (vertex dist 2.4e-13), merge dist 0.19, while processing p499 CPU seconds to compute hull (after input): 4.97 Maximum distance of point above facet: 3.4e-13 (13.7x) Maximum distance of vertex below facet: -3.9e-13 (15.9x) Test -- t6 QH7085 Qhull precision warning: repartition coplanar point p6 from f150669 as an outside point above twisted facet f150322 dist 0.0024 nearest vertices 3e-13 CPU seconds to compute hull (after input): 1.122 Maximum distance of point above facet: 4.1e-13 (16.8x) Maximum distance of vertex below facet: -3.7e-13 (15.1x) Test -- t7 QH7085 Qhull precision warning: repartition coplanar point p444 from f199948 as an outside point above twisted facet f265269 dist 0.0018 nearest vertices 3e-13 QH6271 qhull topology error (qh_check_dupridge): wide merge (569356935583.7x wider) due to dupridge between f270435 and f270400 (vertex dist 2.7e-13), merge dist 0.17, while processing p182 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r215922 and r276482. Nearest v67 and v208 dist 0.13 (5873339593550.7x) Maximum distance of point above facet: 0.0028 (112586859288.4x) Maximum distance of vertex below facet: -0.17 (6865829933136.7x) Test -- t8 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f138124 and f138129 have the same vertices (skip 1, skip 1) and same horizon ridges to f82053 and f58330 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f138124 and f138129 have the same vertices (skip 2, skip 2) and same horizon ridges to f82053 and f58330 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f138124 and f138129 have the same vertices (skip 3, skip 3) and same horizon ridges to f82053 and f58330 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r161343 and r161333. Nearest v277 and v461 dist 0.3 (13107519691555.2x) Test -- t9 QH6391 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve opposite oriented ridges r162905 and r162900 in f219542 and f219513. Nearest v431 and v470 dist 0.33 (14493670237305.6x) Maximum distance of point above facet: 2.8e-13 (11.2x) Test -- t10 QH6391 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve opposite oriented ridges r54841 and r54808 in f98872 and f98951. Nearest v103 and v151 dist 0.24 (10377121912131.9x) 1591314432 Test 10 runs in 13 seconds (ave. 1300 msec) -- rbox 300 C1,2e-13 D5 t1 | qhull Q12 Q14 d Qbb Testing -- rbox 100 C1,2e-13 D6 t1 | qhull Q14 d Qbb >/d/bash/var/tmp/qtest-2020-06-04/qhull-773541.log Test -- t1 CPU seconds to compute hull (after input): 1.056 Maximum distance of vertex below facet: -3.7e-13 (10.6x) Test -- t2 CPU seconds to compute hull (after input): 0.983 Test -- t3 CPU seconds to compute hull (after input): 0.951 Test -- t4 CPU seconds to compute hull (after input): 1.057 Maximum distance of point above facet: 3.6e-13 (10.3x) Maximum distance of vertex below facet: -3.6e-13 (10.4x) Test -- t5 CPU seconds to compute hull (after input): 1.024 Maximum distance of point above facet: 3.9e-13 (11.2x) Maximum distance of vertex below facet: -3.5e-13 (10.0x) Test -- t6 CPU seconds to compute hull (after input): 1.096 Maximum distance of point above facet: 3.6e-13 (10.2x) Maximum distance of vertex below facet: -3.6e-13 (10.2x) Test -- t7 CPU seconds to compute hull (after input): 1.125 Maximum distance of point above facet: 3.6e-13 (10.3x) Maximum distance of vertex below facet: -3.9e-13 (11.2x) Test -- t8 CPU seconds to compute hull (after input): 0.959 Maximum distance of point above facet: 3.9e-13 (11.2x) Test -- t9 CPU seconds to compute hull (after input): 0.996 Maximum distance of vertex below facet: -3.5e-13 (10.1x) Test -- t10 CPU seconds to compute hull (after input): 1.042 1591314446 Test 10 runs in 13 seconds (ave. 1300 msec) -- rbox 100 C1,2e-13 D6 t1 | qhull Q14 d Qbb =========================== === N_TIMING test cases === =========================== ============================ == Time for random points in a cube ============================ Testing -- rbox 1000000 D2 t1 | qhull >/d/bash/var/tmp/qtest-2020-06-04/qhull-242219.log Test -- t1 CPU seconds to compute hull (after input): 0.105 Test -- t2 CPU seconds to compute hull (after input): 0.099 Test -- t3 CPU seconds to compute hull (after input): 0.099 Test -- t4 CPU seconds to compute hull (after input): 0.099 Test -- t5 CPU seconds to compute hull (after input): 0.098 Test -- t6 CPU seconds to compute hull (after input): 0.103 Test -- t7 CPU seconds to compute hull (after input): 0.109 Test -- t8 CPU seconds to compute hull (after input): 0.103 Test -- t9 CPU seconds to compute hull (after input): 0.121 Test -- t10 CPU seconds to compute hull (after input): 0.102 1591314472 Test 10 runs in 24 seconds (ave. 2400 msec) -- rbox 1000000 D2 t1 | qhull Testing -- rbox 500000 D3 t1 | qhull >/d/bash/var/tmp/qtest-2020-06-04/qhull-112621.log Test -- t1 CPU seconds to compute hull (after input): 0.105 Test -- t2 CPU seconds to compute hull (after input): 0.092 Test -- t3 CPU seconds to compute hull (after input): 0.099 Test -- t4 CPU seconds to compute hull (after input): 0.106 Test -- t5 CPU seconds to compute hull (after input): 0.109 Test -- t6 CPU seconds to compute hull (after input): 0.114 Test -- t7 CPU seconds to compute hull (after input): 0.109 Test -- t8 CPU seconds to compute hull (after input): 0.095 Test -- t9 CPU seconds to compute hull (after input): 0.122 Test -- t10 CPU seconds to compute hull (after input): 0.103 1591314492 Test 10 runs in 19 seconds (ave. 1900 msec) -- rbox 500000 D3 t1 | qhull Testing -- rbox 200000 D4 t1 | qhull >/d/bash/var/tmp/qtest-2020-06-04/qhull-248684.log Test -- t1 CPU seconds to compute hull (after input): 0.107 Test -- t2 CPU seconds to compute hull (after input): 0.127 Test -- t3 CPU seconds to compute hull (after input): 0.134 Test -- t4 CPU seconds to compute hull (after input): 0.149 Test -- t5 CPU seconds to compute hull (after input): 0.116 Test -- t6 CPU seconds to compute hull (after input): 0.147 Test -- t7 CPU seconds to compute hull (after input): 0.141 Test -- t8 CPU seconds to compute hull (after input): 0.142 Test -- t9 CPU seconds to compute hull (after input): 0.181 Test -- t10 CPU seconds to compute hull (after input): 0.145 1591314505 Test 10 runs in 12 seconds (ave. 1200 msec) -- rbox 200000 D4 t1 | qhull Testing -- rbox 100000 D5 t1 | qhull Q12 >/d/bash/var/tmp/qtest-2020-06-04/qhull-183885.log Test -- t1 CPU seconds to compute hull (after input): 0.712 Test -- t2 CPU seconds to compute hull (after input): 0.763 Test -- t3 CPU seconds to compute hull (after input): 0.707 Test -- t4 CPU seconds to compute hull (after input): 0.688 Test -- t5 CPU seconds to compute hull (after input): 0.767 Test -- t6 CPU seconds to compute hull (after input): 0.763 Test -- t7 CPU seconds to compute hull (after input): 0.635 Test -- t8 CPU seconds to compute hull (after input): 0.688 Test -- t9 CPU seconds to compute hull (after input): 0.752 Test -- t10 CPU seconds to compute hull (after input): 0.65 1591314520 Test 10 runs in 15 seconds (ave. 1500 msec) -- rbox 100000 D5 t1 | qhull Q12 Testing -- rbox 3000 D6 t1 | qhull >/d/bash/var/tmp/qtest-2020-06-04/qhull-186040.log Test -- t1 CPU seconds to compute hull (after input): 0.931 Test -- t2 CPU seconds to compute hull (after input): 0.959 Test -- t3 CPU seconds to compute hull (after input): 1.084 Test -- t4 CPU seconds to compute hull (after input): 0.908 Test -- t5 CPU seconds to compute hull (after input): 0.785 Test -- t6 CPU seconds to compute hull (after input): 0.979 Test -- t7 CPU seconds to compute hull (after input): 0.887 Test -- t8 CPU seconds to compute hull (after input): 0.995 Test -- t9 CPU seconds to compute hull (after input): 0.959 Test -- t10 CPU seconds to compute hull (after input): 0.903 1591314532 Test 10 runs in 12 seconds (ave. 1200 msec) -- rbox 3000 D6 t1 | qhull ============================ == Time for random cospherical points ============================ Testing -- rbox 100000 s D2 t1 | qhull >/d/bash/var/tmp/qtest-2020-06-04/qhull-121241.log Test -- t1 CPU seconds to compute hull (after input): 0.257 Test -- t2 CPU seconds to compute hull (after input): 0.251 Test -- t3 CPU seconds to compute hull (after input): 0.222 Test -- t4 CPU seconds to compute hull (after input): 0.223 Test -- t5 CPU seconds to compute hull (after input): 0.238 Test -- t6 CPU seconds to compute hull (after input): 0.26 Test -- t7 CPU seconds to compute hull (after input): 0.218 Test -- t8 CPU seconds to compute hull (after input): 0.234 Test -- t9 CPU seconds to compute hull (after input): 0.231 Test -- t10 CPU seconds to compute hull (after input): 0.231 1591314541 Test 10 runs in 7 seconds (ave. 700 msec) -- rbox 100000 s D2 t1 | qhull Testing -- rbox 100000 s D3 t1 | qhull >/d/bash/var/tmp/qtest-2020-06-04/qhull-389057.log Test -- t1 CPU seconds to compute hull (after input): 0.478 Test -- t2 CPU seconds to compute hull (after input): 0.517 Test -- t3 CPU seconds to compute hull (after input): 0.504 Test -- t4 CPU seconds to compute hull (after input): 0.453 Test -- t5 CPU seconds to compute hull (after input): 0.483 Test -- t6 CPU seconds to compute hull (after input): 0.494 Test -- t7 CPU seconds to compute hull (after input): 0.466 Test -- t8 CPU seconds to compute hull (after input): 0.448 Test -- t9 CPU seconds to compute hull (after input): 0.523 Test -- t10 CPU seconds to compute hull (after input): 0.446 1591314552 Test 10 runs in 11 seconds (ave. 1100 msec) -- rbox 100000 s D3 t1 | qhull Testing -- rbox 50000 s D4 t1 | qhull >/d/bash/var/tmp/qtest-2020-06-04/qhull-790781.log Test -- t1 CPU seconds to compute hull (after input): 1.135 Test -- t2 CPU seconds to compute hull (after input): 1.031 Test -- t3 CPU seconds to compute hull (after input): 1.127 Test -- t4 CPU seconds to compute hull (after input): 1.056 Test -- t5 CPU seconds to compute hull (after input): 1.086 Test -- t6 CPU seconds to compute hull (after input): 1.04 Test -- t7 CPU seconds to compute hull (after input): 1.149 Test -- t8 CPU seconds to compute hull (after input): 1.089 Test -- t9 CPU seconds to compute hull (after input): 1.102 Test -- t10 CPU seconds to compute hull (after input): 1.07 1591314571 Test 10 runs in 18 seconds (ave. 1800 msec) -- rbox 50000 s D4 t1 | qhull == Repeat with qconvex, bin/qconvex is built with libqhull instead of libqhull_r Testing -- rbox 50000 s D4 t1 | qconvex >/d/bash/var/tmp/qtest-2020-06-04/qhull-393367.log Test -- t1 CPU seconds to compute hull (after input): 1.01 Test -- t2 CPU seconds to compute hull (after input): 1.052 Test -- t3 CPU seconds to compute hull (after input): 0.953 Test -- t4 CPU seconds to compute hull (after input): 1.005 Test -- t5 CPU seconds to compute hull (after input): 1.006 Test -- t6 CPU seconds to compute hull (after input): 1.004 Test -- t7 CPU seconds to compute hull (after input): 1.096 Test -- t8 CPU seconds to compute hull (after input): 1.073 Test -- t9 CPU seconds to compute hull (after input): 1.025 Test -- t10 CPU seconds to compute hull (after input): 1.068 1591314588 Test 10 runs in 16 seconds (ave. 1600 msec) -- rbox 50000 s D4 t1 | qconvex Testing -- rbox 10000 s D5 t1 | qhull >/d/bash/var/tmp/qtest-2020-06-04/qhull-995953.log Test -- t1 CPU seconds to compute hull (after input): 1.423 Test -- t2 CPU seconds to compute hull (after input): 1.367 Test -- t3 CPU seconds to compute hull (after input): 1.44 Test -- t4 CPU seconds to compute hull (after input): 1.375 Test -- t5 CPU seconds to compute hull (after input): 1.406 Test -- t6 CPU seconds to compute hull (after input): 1.421 Test -- t7 CPU seconds to compute hull (after input): 1.475 Test -- t8 CPU seconds to compute hull (after input): 1.464 Test -- t9 CPU seconds to compute hull (after input): 1.4 Test -- t10 CPU seconds to compute hull (after input): 1.453 1591314608 Test 10 runs in 19 seconds (ave. 1900 msec) -- rbox 10000 s D5 t1 | qhull Testing -- rbox 1000 s D6 t1 | qhull >/d/bash/var/tmp/qtest-2020-06-04/qhull-665493.log Test -- t1 CPU seconds to compute hull (after input): 0.705 Test -- t2 CPU seconds to compute hull (after input): 0.735 Test -- t3 CPU seconds to compute hull (after input): 0.681 Test -- t4 CPU seconds to compute hull (after input): 0.66 Test -- t5 CPU seconds to compute hull (after input): 0.716 Test -- t6 CPU seconds to compute hull (after input): 0.694 Test -- t7 CPU seconds to compute hull (after input): 0.669 Test -- t8 CPU seconds to compute hull (after input): 0.655 Test -- t9 CPU seconds to compute hull (after input): 0.682 Test -- t10 CPU seconds to compute hull (after input): 0.655 1591314619 Test 10 runs in 10 seconds (ave. 1000 msec) -- rbox 1000 s D6 t1 | qhull ============================ == Time for extreme post-merge of random cospherical points ============================ Testing -- rbox 100000 s D2 t1 | qhull C0.01 >/d/bash/var/tmp/qtest-2020-06-04/qhull-533740.log Test -- t1 CPU seconds to compute hull (after input): 0.647 Test -- t2 CPU seconds to compute hull (after input): 0.575 Test -- t3 CPU seconds to compute hull (after input): 0.604 Test -- t4 CPU seconds to compute hull (after input): 0.652 Test -- t5 CPU seconds to compute hull (after input): 0.599 Test -- t6 CPU seconds to compute hull (after input): 0.668 Test -- t7 CPU seconds to compute hull (after input): 0.639 Test -- t8 CPU seconds to compute hull (after input): 0.629 Test -- t9 CPU seconds to compute hull (after input): 0.644 Test -- t10 CPU seconds to compute hull (after input): 0.639 1591314632 Test 10 runs in 12 seconds (ave. 1200 msec) -- rbox 100000 s D2 t1 | qhull C0.01 Testing -- rbox 10000 s D3 t1 | qhull C0.01 >/d/bash/var/tmp/qtest-2020-06-04/qhull-935464.log Test -- t1 CPU seconds to compute hull (after input): 0.14 Test -- t2 CPU seconds to compute hull (after input): 0.147 Test -- t3 CPU seconds to compute hull (after input): 0.174 Test -- t4 CPU seconds to compute hull (after input): 0.165 Test -- t5 CPU seconds to compute hull (after input): 0.148 Test -- t6 CPU seconds to compute hull (after input): 0.149 Test -- t7 CPU seconds to compute hull (after input): 0.144 Test -- t8 CPU seconds to compute hull (after input): 0.142 Test -- t9 CPU seconds to compute hull (after input): 0.142 Test -- t10 CPU seconds to compute hull (after input): 0.145 1591314636 Test 10 runs in 3 seconds (ave. 300 msec) -- rbox 10000 s D3 t1 | qhull C0.01 Testing -- rbox 5000 s D4 t1 | qhull C0.01 >/d/bash/var/tmp/qtest-2020-06-04/qhull-602849.log Test -- t1 CPU seconds to compute hull (after input): 0.395 Test -- t2 CPU seconds to compute hull (after input): 0.426 Test -- t3 CPU seconds to compute hull (after input): 0.403 Test -- t4 CPU seconds to compute hull (after input): 0.375 Test -- t5 CPU seconds to compute hull (after input): 0.407 Test -- t6 CPU seconds to compute hull (after input): 0.409 Test -- t7 CPU seconds to compute hull (after input): 0.399 Test -- t8 CPU seconds to compute hull (after input): 0.415 Test -- t9 CPU seconds to compute hull (after input): 0.374 Test -- t10 CPU seconds to compute hull (after input): 0.437 1591314643 Test 10 runs in 6 seconds (ave. 600 msec) -- rbox 5000 s D4 t1 | qhull C0.01 == Repeat with qconvex, bin/qconvex is built with libqhull instead of libqhull_r Testing -- rbox 5000 s D4 t1 | qconvex C0.01 >/d/bash/var/tmp/qtest-2020-06-04/qhull-337188.log Test -- t1 CPU seconds to compute hull (after input): 0.42 Test -- t2 CPU seconds to compute hull (after input): 0.384 Test -- t3 CPU seconds to compute hull (after input): 0.362 Test -- t4 CPU seconds to compute hull (after input): 0.393 Test -- t5 CPU seconds to compute hull (after input): 0.42 Test -- t6 CPU seconds to compute hull (after input): 0.43 Test -- t7 CPU seconds to compute hull (after input): 0.392 Test -- t8 CPU seconds to compute hull (after input): 0.376 Test -- t9 CPU seconds to compute hull (after input): 0.444 Test -- t10 CPU seconds to compute hull (after input): 0.406 1591314650 Test 10 runs in 6 seconds (ave. 600 msec) -- rbox 5000 s D4 t1 | qconvex C0.01 Testing -- rbox 2000 s D5 t1 | qhull C0.01 >/d/bash/var/tmp/qtest-2020-06-04/qhull-71527.log Test -- t1 CPU seconds to compute hull (after input): 0.805 Test -- t2 CPU seconds to compute hull (after input): 0.8 Test -- t3 CPU seconds to compute hull (after input): 0.847 Test -- t4 CPU seconds to compute hull (after input): 0.809 Test -- t5 CPU seconds to compute hull (after input): 0.872 Test -- t6 CPU seconds to compute hull (after input): 0.877 Test -- t7 CPU seconds to compute hull (after input): 0.819 Test -- t8 CPU seconds to compute hull (after input): 0.826 Test -- t9 CPU seconds to compute hull (after input): 0.806 Test -- t10 CPU seconds to compute hull (after input): 0.811 1591314662 Test 10 runs in 11 seconds (ave. 1100 msec) -- rbox 2000 s D5 t1 | qhull C0.01 Testing -- rbox 500 s D6 t1 | qhull C0.01 >/d/bash/var/tmp/qtest-2020-06-04/qhull-473251.log Test -- t1 CPU seconds to compute hull (after input): 0.826 Test -- t2 CPU seconds to compute hull (after input): 0.848 Test -- t3 CPU seconds to compute hull (after input): 0.812 Test -- t4 CPU seconds to compute hull (after input): 0.907 Test -- t5 CPU seconds to compute hull (after input): 0.879 Test -- t6 CPU seconds to compute hull (after input): 0.907 Test -- t7 CPU seconds to compute hull (after input): 0.852 Test -- t8 CPU seconds to compute hull (after input): 0.825 Test -- t9 CPU seconds to compute hull (after input): 0.851 Test -- t10 CPU seconds to compute hull (after input): 0.884 1591314675 Test 10 runs in 12 seconds (ave. 1200 msec) -- rbox 500 s D6 t1 | qhull C0.01 ============================ == Time for rotated cubical points with large merged facets ============================ Testing -- rbox 5000000 W0 D2 t1 | qhull QR3 >/d/bash/var/tmp/qtest-2020-06-04/qhull-874975.log Test -- t1 CPU seconds to compute hull (after input): 0.922 Test -- t2 CPU seconds to compute hull (after input): 0.854 Test -- t3 CPU seconds to compute hull (after input): 0.892 Test -- t4 CPU seconds to compute hull (after input): 0.862 Test -- t5 CPU seconds to compute hull (after input): 0.985 Test -- t6 CPU seconds to compute hull (after input): 0.838 Test -- t7 CPU seconds to compute hull (after input): 0.826 Test -- t8 CPU seconds to compute hull (after input): 0.801 Test -- t9 CPU seconds to compute hull (after input): 0.833 Test -- t10 CPU seconds to compute hull (after input): 0.863 1591314778 Test 10 runs in 102 seconds (ave. 10200 msec) -- rbox 5000000 W0 D2 t1 | qhull QR3 Testing -- rbox 1000000 W0 D3 t1 | qhull QR3 >/d/bash/var/tmp/qtest-2020-06-04/qhull-823106.log Test -- t1 CPU seconds to compute hull (after input): 0.621 Test -- t2 CPU seconds to compute hull (after input): 0.721 Test -- t3 CPU seconds to compute hull (after input): 0.549 Test -- t4 CPU seconds to compute hull (after input): 0.6 Test -- t5 CPU seconds to compute hull (after input): 0.575 Test -- t6 CPU seconds to compute hull (after input): 0.635 Test -- t7 CPU seconds to compute hull (after input): 0.591 Test -- t8 CPU seconds to compute hull (after input): 0.646 Test -- t9 CPU seconds to compute hull (after input): 0.742 Test -- t10 CPU seconds to compute hull (after input): 0.614 1591314815 Test 10 runs in 36 seconds (ave. 3600 msec) -- rbox 1000000 W0 D3 t1 | qhull QR3 Testing -- rbox 100000 W0 D4 t1 | qhull QR3 >/d/bash/var/tmp/qtest-2020-06-04/qhull-95232.log Test -- t1 CPU seconds to compute hull (after input): 0.437 Test -- t2 CPU seconds to compute hull (after input): 0.417 Test -- t3 CPU seconds to compute hull (after input): 0.403 Test -- t4 CPU seconds to compute hull (after input): 0.419 Test -- t5 CPU seconds to compute hull (after input): 0.416 Test -- t6 CPU seconds to compute hull (after input): 0.423 Test -- t7 CPU seconds to compute hull (after input): 0.417 Test -- t8 CPU seconds to compute hull (after input): 0.381 Test -- t9 CPU seconds to compute hull (after input): 0.413 Test -- t10 CPU seconds to compute hull (after input): 0.46 1591314826 Test 10 runs in 10 seconds (ave. 1000 msec) -- rbox 100000 W0 D4 t1 | qhull QR3 Testing -- rbox 10000 W0 D5 t1 | qhull QR3 >/d/bash/var/tmp/qtest-2020-06-04/qhull-430002.log Test -- t1 CPU seconds to compute hull (after input): 0.654 Test -- t2 CPU seconds to compute hull (after input): 0.685 Test -- t3 CPU seconds to compute hull (after input): 0.657 Test -- t4 CPU seconds to compute hull (after input): 0.628 Test -- t5 CPU seconds to compute hull (after input): 0.699 Test -- t6 CPU seconds to compute hull (after input): 0.618 Test -- t7 CPU seconds to compute hull (after input): 0.614 Test -- t8 CPU seconds to compute hull (after input): 0.655 Test -- t9 CPU seconds to compute hull (after input): 0.69 Test -- t10 CPU seconds to compute hull (after input): 0.807 1591314836 Test 10 runs in 9 seconds (ave. 900 msec) -- rbox 10000 W0 D5 t1 | qhull QR3 Testing -- rbox 1000 W0 D6 t1 | qhull QR3 >/d/bash/var/tmp/qtest-2020-06-04/qhull-764772.log Test -- t1 CPU seconds to compute hull (after input): 0.91 Test -- t2 CPU seconds to compute hull (after input): 0.918 Test -- t3 CPU seconds to compute hull (after input): 0.874 Test -- t4 CPU seconds to compute hull (after input): 0.827 Test -- t5 CPU seconds to compute hull (after input): 0.827 Test -- t6 CPU seconds to compute hull (after input): 0.923 Test -- t7 CPU seconds to compute hull (after input): 0.821 Test -- t8 CPU seconds to compute hull (after input): 1 Test -- t9 CPU seconds to compute hull (after input): 0.839 Test -- t10 CPU seconds to compute hull (after input): 0.908 1591314848 Test 10 runs in 11 seconds (ave. 1100 msec) -- rbox 1000 W0 D6 t1 | qhull QR3 ============================ == Time for joggled, rotated cubical points with multiple retries ============================ Testing -- rbox 5000000 W0 D2 t1 | qhull QR3 QJ >/d/bash/var/tmp/qtest-2020-06-04/qhull-699973.log Test -- t1 CPU seconds to compute hull (after input): 0.837 Test -- t2 CPU seconds to compute hull (after input): 0.764 Test -- t3 CPU seconds to compute hull (after input): 0.733 Test -- t4 CPU seconds to compute hull (after input): 0.723 Test -- t5 CPU seconds to compute hull (after input): 0.819 Test -- t6 CPU seconds to compute hull (after input): 0.81 Test -- t7 CPU seconds to compute hull (after input): 0.732 Test -- t8 CPU seconds to compute hull (after input): 0.799 Test -- t9 CPU seconds to compute hull (after input): 0.803 Test -- t10 CPU seconds to compute hull (after input): 0.712 1591314950 Test 10 runs in 101 seconds (ave. 10100 msec) -- rbox 5000000 W0 D2 t1 | qhull QR3 QJ Testing -- rbox 1000000 W0 D3 t1 | qhull QR3 QJ >/d/bash/var/tmp/qtest-2020-06-04/qhull-114627.log Test -- t1 CPU seconds to compute hull (after input): 1.327 After 2 retries, input joggled by: 3.5e-10 Test -- t2 CPU seconds to compute hull (after input): 1.996 After 3 retries, input joggled by: 3.5e-09 Test -- t3 CPU seconds to compute hull (after input): 1.311 After 2 retries, input joggled by: 3.5e-10 Test -- t4 CPU seconds to compute hull (after input): 0.522 Test -- t5 CPU seconds to compute hull (after input): 0.478 Test -- t6 CPU seconds to compute hull (after input): 1.074 After 1 retries, input joggled by: 3.5e-11 Test -- t7 CPU seconds to compute hull (after input): 1.308 After 2 retries, input joggled by: 3.5e-10 Test -- t8 CPU seconds to compute hull (after input): 1.455 After 2 retries, input joggled by: 3.5e-10 Test -- t9 CPU seconds to compute hull (after input): 1.62 After 2 retries, input joggled by: 3.5e-10 Test -- t10 CPU seconds to compute hull (after input): 1.542 After 2 retries, input joggled by: 3.5e-10 1591314995 Test 10 runs in 44 seconds (ave. 4400 msec) -- rbox 1000000 W0 D3 t1 | qhull QR3 QJ Testing -- rbox 100000 W0 D4 t1 | qhull QR3 QJ >/d/bash/var/tmp/qtest-2020-06-04/qhull-587615.log Test -- t1 CPU seconds to compute hull (after input): 0.326 After 3 retries, input joggled by: 5.7e-09 Test -- t2 CPU seconds to compute hull (after input): 0.433 After 3 retries, input joggled by: 5.7e-09 Test -- t3 CPU seconds to compute hull (after input): 0.347 After 2 retries, input joggled by: 5.7e-10 Test -- t4 CPU seconds to compute hull (after input): 0.345 After 2 retries, input joggled by: 5.6e-10 Test -- t5 CPU seconds to compute hull (after input): 0.383 After 2 retries, input joggled by: 5.7e-10 Test -- t6 CPU seconds to compute hull (after input): 0.325 After 2 retries, input joggled by: 5.7e-10 Test -- t7 CPU seconds to compute hull (after input): 0.385 After 2 retries, input joggled by: 5.7e-10 Test -- t8 CPU seconds to compute hull (after input): 0.339 After 2 retries, input joggled by: 5.7e-10 Test -- t9 CPU seconds to compute hull (after input): 0.309 After 2 retries, input joggled by: 5.7e-10 Test -- t10 CPU seconds to compute hull (after input): 0.465 After 3 retries, input joggled by: 5.7e-09 1591315005 Test 10 runs in 10 seconds (ave. 1000 msec) -- rbox 100000 W0 D4 t1 | qhull QR3 QJ Testing -- rbox 10000 W0 D5 t1 | qhull QR3 QJ >/d/bash/var/tmp/qtest-2020-06-04/qhull-922385.log Test -- t1 CPU seconds to compute hull (after input): 0.967 After 4 retries, input joggled by: 8.3e-08 Test -- t2 CPU seconds to compute hull (after input): 0.716 After 3 retries, input joggled by: 8.3e-09 Test -- t3 CPU seconds to compute hull (after input): 0.922 After 4 retries, input joggled by: 8.4e-08 Test -- t4 CPU seconds to compute hull (after input): 0.478 After 2 retries, input joggled by: 7.9e-10 Test -- t5 CPU seconds to compute hull (after input): 0.638 After 3 retries, input joggled by: 8.4e-09 Test -- t6 CPU seconds to compute hull (after input): 0.624 After 3 retries, input joggled by: 8.1e-09 Test -- t7 CPU seconds to compute hull (after input): 0.614 After 3 retries, input joggled by: 8.4e-09 Test -- t8 CPU seconds to compute hull (after input): 0.462 After 2 retries, input joggled by: 8.4e-10 Test -- t9 CPU seconds to compute hull (after input): 0.456 After 3 retries, input joggled by: 8.5e-09 Test -- t10 CPU seconds to compute hull (after input): 0.448 After 2 retries, input joggled by: 8.3e-10 1591315014 Test 10 runs in 9 seconds (ave. 900 msec) -- rbox 10000 W0 D5 t1 | qhull QR3 QJ Testing -- rbox 1000 W0 D6 t1 | qhull QR3 QJ >/d/bash/var/tmp/qtest-2020-06-04/qhull-723678.log Test -- t1 CPU seconds to compute hull (after input): 1.123 After 3 retries, input joggled by: 1e-08 Test -- t2 CPU seconds to compute hull (after input): 0.903 After 2 retries, input joggled by: 1e-09 Test -- t3 CPU seconds to compute hull (after input): 0.804 After 2 retries, input joggled by: 1e-09 Test -- t4 CPU seconds to compute hull (after input): 0.721 After 3 retries, input joggled by: 1e-08 Test -- t5 CPU seconds to compute hull (after input): 0.608 After 2 retries, input joggled by: 1.1e-09 Test -- t6 CPU seconds to compute hull (after input): 0.937 After 3 retries, input joggled by: 9.9e-09 Test -- t7 CPU seconds to compute hull (after input): 0.735 After 2 retries, input joggled by: 9.8e-10 Test -- t8 CPU seconds to compute hull (after input): 0.559 After 2 retries, input joggled by: 9.7e-10 Test -- t9 CPU seconds to compute hull (after input): 0.842 After 2 retries, input joggled by: 1.1e-09 Test -- t10 CPU seconds to compute hull (after input): 0.663 After 2 retries, input joggled by: 9.9e-10 1591315026 Test 10 runs in 11 seconds (ave. 1100 msec) -- rbox 1000 W0 D6 t1 | qhull QR3 QJ ============================ == Time for joggled, nearly cubical points ============================ Testing -- rbox 1000000 W1e-13 D2 t1 | qhull QJ >/d/bash/var/tmp/qtest-2020-06-04/qhull-125402.log Test -- t1 CPU seconds to compute hull (after input): 0.321 After 1 retries, input joggled by: 1.3e-11 Test -- t2 CPU seconds to compute hull (after input): 0.157 Test -- t3 CPU seconds to compute hull (after input): 0.193 Test -- t4 CPU seconds to compute hull (after input): 0.165 Test -- t5 CPU seconds to compute hull (after input): 0.174 Test -- t6 CPU seconds to compute hull (after input): 0.169 Test -- t7 CPU seconds to compute hull (after input): 0.357 After 1 retries, input joggled by: 1.3e-11 Test -- t8 CPU seconds to compute hull (after input): 0.184 Test -- t9 CPU seconds to compute hull (after input): 0.205 Test -- t10 CPU seconds to compute hull (after input): 0.172 1591315053 Test 10 runs in 26 seconds (ave. 2600 msec) -- rbox 1000000 W1e-13 D2 t1 | qhull QJ Testing -- rbox 500000 W1e-13 D3 t1 | qhull QJ >/d/bash/var/tmp/qtest-2020-06-04/qhull-529281.log Test -- t1 CPU seconds to compute hull (after input): 1.32 After 4 retries, input joggled by: 2.1e-08 Test -- t2 CPU seconds to compute hull (after input): 1.079 After 3 retries, input joggled by: 2.1e-09 Test -- t3 CPU seconds to compute hull (after input): 1.055 After 3 retries, input joggled by: 2.1e-09 Test -- t4 CPU seconds to compute hull (after input): 1.303 After 4 retries, input joggled by: 2.1e-08 Test -- t5 CPU seconds to compute hull (after input): 1.163 After 3 retries, input joggled by: 2.1e-09 Test -- t6 CPU seconds to compute hull (after input): 1.109 After 3 retries, input joggled by: 2.1e-09 Test -- t7 CPU seconds to compute hull (after input): 1.053 After 3 retries, input joggled by: 2.1e-09 Test -- t8 CPU seconds to compute hull (after input): 0.983 After 3 retries, input joggled by: 2.1e-09 Test -- t9 CPU seconds to compute hull (after input): 1.361 After 4 retries, input joggled by: 2.1e-08 Test -- t10 CPU seconds to compute hull (after input): 0.981 After 3 retries, input joggled by: 2.1e-09 1591315083 Test 10 runs in 29 seconds (ave. 2900 msec) -- rbox 500000 W1e-13 D3 t1 | qhull QJ Testing -- rbox 100000 W1e-13 D4 t1 | qhull QJ >/d/bash/var/tmp/qtest-2020-06-04/qhull-533591.log Test -- t1 CPU seconds to compute hull (after input): 0.653 After 4 retries, input joggled by: 3e-08 Test -- t2 CPU seconds to compute hull (after input): 0.463 After 3 retries, input joggled by: 3e-09 Test -- t3 CPU seconds to compute hull (after input): 0.65 After 4 retries, input joggled by: 3e-08 Test -- t4 CPU seconds to compute hull (after input): 0.47 After 3 retries, input joggled by: 3e-09 Test -- t5 CPU seconds to compute hull (after input): 0.583 After 4 retries, input joggled by: 3e-08 Test -- t6 CPU seconds to compute hull (after input): 0.657 After 4 retries, input joggled by: 3e-08 Test -- t7 CPU seconds to compute hull (after input): 0.453 After 3 retries, input joggled by: 3e-09 Test -- t8 CPU seconds to compute hull (after input): 0.434 After 3 retries, input joggled by: 3e-09 Test -- t9 CPU seconds to compute hull (after input): 0.55 After 3 retries, input joggled by: 3e-09 Test -- t10 CPU seconds to compute hull (after input): 0.668 After 4 retries, input joggled by: 3e-08 1591315095 Test 10 runs in 11 seconds (ave. 1100 msec) -- rbox 100000 W1e-13 D4 t1 | qhull QJ Testing -- rbox 10000 W1e-13 D5 t1 | qhull QJ >/d/bash/var/tmp/qtest-2020-06-04/qhull-468792.log Test -- t1 CPU seconds to compute hull (after input): 0.5 After 3 retries, input joggled by: 4.1e-09 Test -- t2 CPU seconds to compute hull (after input): 0.86 After 3 retries, input joggled by: 4.1e-09 Test -- t3 CPU seconds to compute hull (after input): 0.796 After 4 retries, input joggled by: 4.1e-08 Test -- t4 CPU seconds to compute hull (after input): 0.894 After 4 retries, input joggled by: 4.1e-08 Test -- t5 CPU seconds to compute hull (after input): 0.575 After 3 retries, input joggled by: 4.1e-09 Test -- t6 CPU seconds to compute hull (after input): 0.83 After 4 retries, input joggled by: 4.1e-08 Test -- t7 CPU seconds to compute hull (after input): 0.545 After 3 retries, input joggled by: 4.1e-09 Test -- t8 CPU seconds to compute hull (after input): 0.593 After 3 retries, input joggled by: 4.1e-09 Test -- t9 CPU seconds to compute hull (after input): 0.852 After 4 retries, input joggled by: 4.1e-08 Test -- t10 CPU seconds to compute hull (after input): 0.759 After 4 retries, input joggled by: 4.1e-08 1591315106 Test 10 runs in 10 seconds (ave. 1000 msec) -- rbox 10000 W1e-13 D5 t1 | qhull QJ Testing -- rbox 1000 W1e-13 D6 t1 | qhull QJ >/d/bash/var/tmp/qtest-2020-06-04/qhull-337039.log Test -- t1 CPU seconds to compute hull (after input): 0.658 After 2 retries, input joggled by: 5.3e-10 Test -- t2 CPU seconds to compute hull (after input): 0.741 After 2 retries, input joggled by: 5.3e-10 Test -- t3 CPU seconds to compute hull (after input): 0.782 After 2 retries, input joggled by: 5.3e-10 Test -- t4 CPU seconds to compute hull (after input): 1.135 After 2 retries, input joggled by: 5.3e-10 Test -- t5 CPU seconds to compute hull (after input): 1.04 After 3 retries, input joggled by: 5.3e-09 Test -- t6 CPU seconds to compute hull (after input): 0.693 After 2 retries, input joggled by: 5.3e-10 Test -- t7 CPU seconds to compute hull (after input): 0.981 After 3 retries, input joggled by: 5.3e-09 Test -- t8 CPU seconds to compute hull (after input): 0.884 After 3 retries, input joggled by: 5.3e-09 Test -- t9 CPU seconds to compute hull (after input): 1.183 After 3 retries, input joggled by: 5.3e-09 Test -- t10 CPU seconds to compute hull (after input): 0.862 After 3 retries, input joggled by: 5.3e-09 1591315119 Test 10 runs in 12 seconds (ave. 1200 msec) -- rbox 1000 W1e-13 D6 t1 | qhull QJ ============================ == Time for merging nearly cubical points ============================ Testing -- rbox 1000000 W1e-13 D2 t1 | qhull >/d/bash/var/tmp/qtest-2020-06-04/qhull-272240.log Test -- t1 CPU seconds to compute hull (after input): 0.208 Test -- t2 CPU seconds to compute hull (after input): 0.197 Test -- t3 CPU seconds to compute hull (after input): 0.232 Test -- t4 CPU seconds to compute hull (after input): 0.213 Test -- t5 CPU seconds to compute hull (after input): 0.179 Test -- t6 CPU seconds to compute hull (after input): 0.209 Test -- t7 CPU seconds to compute hull (after input): 0.194 Test -- t8 CPU seconds to compute hull (after input): 0.214 Test -- t9 CPU seconds to compute hull (after input): 0.193 Test -- t10 CPU seconds to compute hull (after input): 0.223 1591315146 Test 10 runs in 26 seconds (ave. 2600 msec) -- rbox 1000000 W1e-13 D2 t1 | qhull Testing -- rbox 1000000 W1e-13 D3 t1 | qhull >/d/bash/var/tmp/qtest-2020-06-04/qhull-142642.log Test -- t1 CPU seconds to compute hull (after input): 1.418 Test -- t2 CPU seconds to compute hull (after input): 1.07 Test -- t3 CPU seconds to compute hull (after input): 1.273 Test -- t4 CPU seconds to compute hull (after input): 1.124 Test -- t5 CPU seconds to compute hull (after input): 1.111 Test -- t6 CPU seconds to compute hull (after input): 1.152 Test -- t7 CPU seconds to compute hull (after input): 1.083 Test -- t8 CPU seconds to compute hull (after input): 1.255 Test -- t9 CPU seconds to compute hull (after input): 1.102 Test -- t10 CPU seconds to compute hull (after input): 1.237 1591315193 Test 10 runs in 46 seconds (ave. 4600 msec) -- rbox 1000000 W1e-13 D3 t1 | qhull Testing -- rbox 100000 W1e-13 D4 t1 | qhull Q12 >/d/bash/var/tmp/qtest-2020-06-04/qhull-216061.log Test -- t1 CPU seconds to compute hull (after input): 0.958 Test -- t2 CPU seconds to compute hull (after input): 0.998 Test -- t3 CPU seconds to compute hull (after input): 1.68 Test -- t4 CPU seconds to compute hull (after input): 1.194 Test -- t5 CPU seconds to compute hull (after input): 1.471 Maximum distance of point above facet: 1.7e-13 (16.9x) Maximum distance of vertex below facet: -1.4e-13 (13.9x) Test -- t6 CPU seconds to compute hull (after input): 1.17 Test -- t7 CPU seconds to compute hull (after input): 0.964 Test -- t8 CPU seconds to compute hull (after input): 1.509 Test -- t9 CPU seconds to compute hull (after input): 2.097 Maximum distance of vertex below facet: -1.3e-13 (12.6x) Test -- t10 CPU seconds to compute hull (after input): 1.882 1591315213 Test 10 runs in 20 seconds (ave. 2000 msec) -- rbox 100000 W1e-13 D4 t1 | qhull Q12 Testing -- rbox 2000 W1e-13 D5 t1 | qhull Q12 >/d/bash/var/tmp/qtest-2020-06-04/qhull-885601.log Test -- t1 CPU seconds to compute hull (after input): 0.504 Test -- t2 CPU seconds to compute hull (after input): 0.509 Test -- t3 CPU seconds to compute hull (after input): 0.513 Test -- t4 CPU seconds to compute hull (after input): 0.505 Test -- t5 CPU seconds to compute hull (after input): 0.446 Test -- t6 CPU seconds to compute hull (after input): 0.517 Test -- t7 CPU seconds to compute hull (after input): 0.485 Test -- t8 QH6271 qhull topology error (qh_check_dupridge): wide merge (100.6x wider) due to dupridge between f23261 and f23245 (vertex dist 0.16), merge dist 2e-12, while processing p54 CPU seconds to compute hull (after input): 0.543 Test -- t9 CPU seconds to compute hull (after input): 0.55 Test -- t10 CPU seconds to compute hull (after input): 0.531 1591315221 Test 10 runs in 7 seconds (ave. 700 msec) -- rbox 2000 W1e-13 D5 t1 | qhull Q12 Testing -- rbox 500 W1e-13 D6 t1 | qhull >/d/bash/var/tmp/qtest-2020-06-04/qhull-153417.log Test -- t1 CPU seconds to compute hull (after input): 0.41 Test -- t2 CPU seconds to compute hull (after input): 0.455 Test -- t3 CPU seconds to compute hull (after input): 0.491 Test -- t4 CPU seconds to compute hull (after input): 0.428 Test -- t5 CPU seconds to compute hull (after input): 0.394 Test -- t6 CPU seconds to compute hull (after input): 0.436 Test -- t7 CPU seconds to compute hull (after input): 0.465 Test -- t8 CPU seconds to compute hull (after input): 0.464 Test -- t9 CPU seconds to compute hull (after input): 0.378 Test -- t10 CPU seconds to compute hull (after input): 0.408 1591315228 Test 10 runs in 6 seconds (ave. 600 msec) -- rbox 500 W1e-13 D6 t1 | qhull ============================ == Time for Delaunay triangulation of random points == qh_findbesthorizon, qh_distplane, qh_update_vertexneighbors_cone, qh_makenew_simplicial ============================ Testing -- rbox 100000 D2 t1 | qhull d Qbb Qz >/d/bash/var/tmp/qtest-2020-06-04/qhull-421233.log Test -- t1 CPU seconds to compute hull (after input): 0.782 Test -- t2 CPU seconds to compute hull (after input): 0.756 Test -- t3 CPU seconds to compute hull (after input): 0.778 Test -- t4 CPU seconds to compute hull (after input): 0.742 Test -- t5 CPU seconds to compute hull (after input): 0.724 Test -- t6 CPU seconds to compute hull (after input): 0.807 Test -- t7 CPU seconds to compute hull (after input): 0.717 Test -- t8 CPU seconds to compute hull (after input): 0.807 Test -- t9 CPU seconds to compute hull (after input): 0.745 Test -- t10 CPU seconds to compute hull (after input): 0.721 1591315243 Test 10 runs in 14 seconds (ave. 1400 msec) -- rbox 100000 D2 t1 | qhull d Qbb Qz Testing -- rbox 50000 D3 t1 | qhull d Qbb Qz >/d/bash/var/tmp/qtest-2020-06-04/qhull-889911.log Test -- t1 CPU seconds to compute hull (after input): 1.703 Test -- t2 CPU seconds to compute hull (after input): 1.693 Test -- t3 CPU seconds to compute hull (after input): 1.048 Test -- t4 CPU seconds to compute hull (after input): 1.599 Test -- t5 CPU seconds to compute hull (after input): 1.669 Test -- t6 CPU seconds to compute hull (after input): 1.064 Test -- t7 CPU seconds to compute hull (after input): 1.661 Test -- t8 CPU seconds to compute hull (after input): 1.646 Test -- t9 CPU seconds to compute hull (after input): 1.031 Test -- t10 CPU seconds to compute hull (after input): 1.027 1591315265 Test 10 runs in 21 seconds (ave. 2100 msec) -- rbox 50000 D3 t1 | qhull d Qbb Qz Testing -- rbox 10000 D4 t1 | qhull d Qbb Qz >/d/bash/var/tmp/qtest-2020-06-04/qhull-626405.log Test -- t1 CPU seconds to compute hull (after input): 1.413 Test -- t2 CPU seconds to compute hull (after input): 1.377 Test -- t3 CPU seconds to compute hull (after input): 1.453 Test -- t4 CPU seconds to compute hull (after input): 1.396 Test -- t5 CPU seconds to compute hull (after input): 1.384 Test -- t6 CPU seconds to compute hull (after input): 1.453 Test -- t7 CPU seconds to compute hull (after input): 1.359 Test -- t8 CPU seconds to compute hull (after input): 1.515 Test -- t9 CPU seconds to compute hull (after input): 1.427 Test -- t10 CPU seconds to compute hull (after input): 1.385 1591315286 Test 10 runs in 20 seconds (ave. 2000 msec) -- rbox 10000 D4 t1 | qhull d Qbb Qz Testing -- rbox 1000 D5 t1 | qhull d Qbb Qz >/d/bash/var/tmp/qtest-2020-06-04/qhull-829422.log Test -- t1 CPU seconds to compute hull (after input): 0.674 Test -- t2 CPU seconds to compute hull (after input): 0.662 Test -- t3 CPU seconds to compute hull (after input): 0.683 Test -- t4 CPU seconds to compute hull (after input): 0.677 Test -- t5 CPU seconds to compute hull (after input): 0.697 Test -- t6 CPU seconds to compute hull (after input): 0.638 Test -- t7 CPU seconds to compute hull (after input): 0.67 Test -- t8 CPU seconds to compute hull (after input): 0.667 Test -- t9 CPU seconds to compute hull (after input): 0.658 Test -- t10 CPU seconds to compute hull (after input): 0.696 1591315296 Test 10 runs in 10 seconds (ave. 1000 msec) -- rbox 1000 D5 t1 | qhull d Qbb Qz Testing -- rbox 200 D6 t1 | qhull d Qbb Qz >/d/bash/var/tmp/qtest-2020-06-04/qhull-164192.log Test -- t1 CPU seconds to compute hull (after input): 0.353 Test -- t2 CPU seconds to compute hull (after input): 0.376 Test -- t3 CPU seconds to compute hull (after input): 0.384 Test -- t4 CPU seconds to compute hull (after input): 0.366 Test -- t5 CPU seconds to compute hull (after input): 0.405 Test -- t6 CPU seconds to compute hull (after input): 0.374 Test -- t7 CPU seconds to compute hull (after input): 0.382 Test -- t8 CPU seconds to compute hull (after input): 0.353 Test -- t9 CPU seconds to compute hull (after input): 0.388 Test -- t10 CPU seconds to compute hull (after input): 0.375 1591315303 Test 10 runs in 6 seconds (ave. 600 msec) -- rbox 200 D6 t1 | qhull d Qbb Qz ==================== == Time for Delaunay triangulation of regular mesh, integer coordinates ==================== Testing -- rbox 100000 M3,4 z D2 t1 | qhull QR3 d Qt Qbb >/d/bash/var/tmp/qtest-2020-06-04/qhull-432008.log Test -- t1 CPU seconds to compute hull (after input): 0.81 Test -- t2 CPU seconds to compute hull (after input): 0.784 Test -- t3 CPU seconds to compute hull (after input): 0.791 Test -- t4 CPU seconds to compute hull (after input): 0.812 Test -- t5 CPU seconds to compute hull (after input): 0.795 Test -- t6 CPU seconds to compute hull (after input): 0.761 Test -- t7 CPU seconds to compute hull (after input): 0.789 Test -- t8 CPU seconds to compute hull (after input): 0.772 Test -- t9 CPU seconds to compute hull (after input): 0.851 Test -- t10 CPU seconds to compute hull (after input): 0.794 1591315322 Test 10 runs in 18 seconds (ave. 1800 msec) -- rbox 100000 M3,4 z D2 t1 | qhull QR3 d Qt Qbb Testing -- rbox 20000 M3,4,5 z D3 t1 | qhull QR3 d Qt Qbb >/d/bash/var/tmp/qtest-2020-06-04/qhull-568071.log Test -- t1 CPU seconds to compute hull (after input): 0.908 Test -- t2 CPU seconds to compute hull (after input): 0.847 Test -- t3 CPU seconds to compute hull (after input): 0.887 Test -- t4 CPU seconds to compute hull (after input): 0.869 Test -- t5 CPU seconds to compute hull (after input): 0.862 Test -- t6 CPU seconds to compute hull (after input): 0.89 Test -- t7 CPU seconds to compute hull (after input): 0.889 Test -- t8 CPU seconds to compute hull (after input): 0.893 Test -- t9 CPU seconds to compute hull (after input): 0.899 Test -- t10 CPU seconds to compute hull (after input): 0.91 1591315337 Test 10 runs in 14 seconds (ave. 1400 msec) -- rbox 20000 M3,4,5 z D3 t1 | qhull QR3 d Qt Qbb Testing -- rbox 5000 M3,4,5 z D4 t1 | qhull QR3 d Qt Qbb >/d/bash/var/tmp/qtest-2020-06-04/qhull-570226.log Test -- t1 CPU seconds to compute hull (after input): 0.867 Test -- t2 CPU seconds to compute hull (after input): 0.924 Test -- t3 CPU seconds to compute hull (after input): 0.867 Test -- t4 CPU seconds to compute hull (after input): 0.966 Test -- t5 CPU seconds to compute hull (after input): 0.852 Test -- t6 CPU seconds to compute hull (after input): 0.85 Test -- t7 CPU seconds to compute hull (after input): 0.957 Test -- t8 CPU seconds to compute hull (after input): 0.881 Test -- t9 CPU seconds to compute hull (after input): 0.89 Test -- t10 CPU seconds to compute hull (after input): 0.874 1591315352 Test 10 runs in 14 seconds (ave. 1400 msec) -- rbox 5000 M3,4,5 z D4 t1 | qhull QR3 d Qt Qbb Testing -- rbox 1500 M3,4,5 z D5 t1 | qhull QR3 d Qt Qbb >/d/bash/var/tmp/qtest-2020-06-04/qhull-38904.log Test -- t1 CPU seconds to compute hull (after input): 0.97 Test -- t2 CPU seconds to compute hull (after input): 0.985 Test -- t3 CPU seconds to compute hull (after input): 0.998 Test -- t4 CPU seconds to compute hull (after input): 1.012 Test -- t5 CPU seconds to compute hull (after input): 0.998 Test -- t6 CPU seconds to compute hull (after input): 0.978 Test -- t7 CPU seconds to compute hull (after input): 0.97 Test -- t8 CPU seconds to compute hull (after input): 0.988 Test -- t9 CPU seconds to compute hull (after input): 0.96 Test -- t10 CPU seconds to compute hull (after input): 1.035 1591315367 Test 10 runs in 14 seconds (ave. 1400 msec) -- rbox 1500 M3,4,5 z D5 t1 | qhull QR3 d Qt Qbb Testing -- rbox 500 M3,4,5 z D6 t1 | qhull QR3 d Qt Qbb >/d/bash/var/tmp/qtest-2020-06-04/qhull-41059.log Test -- t1 CPU seconds to compute hull (after input): 0.807 Test -- t2 CPU seconds to compute hull (after input): 0.789 Test -- t3 CPU seconds to compute hull (after input): 0.877 Test -- t4 CPU seconds to compute hull (after input): 0.866 Test -- t5 CPU seconds to compute hull (after input): 0.853 Test -- t6 CPU seconds to compute hull (after input): 0.779 Test -- t7 CPU seconds to compute hull (after input): 0.794 Test -- t8 CPU seconds to compute hull (after input): 0.838 Test -- t9 CPU seconds to compute hull (after input): 0.792 Test -- t10 CPU seconds to compute hull (after input): 0.854 1591315380 Test 10 runs in 13 seconds (ave. 1300 msec) -- rbox 500 M3,4,5 z D6 t1 | qhull QR3 d Qt Qbb ==================== == Time for Voronoi diagram of regular mesh ==================== Testing -- rbox 100000 M3,4 z D2 | qhull v Qbb >/d/bash/var/tmp/qtest-2020-06-04/qhull-976260.log Test -- QR1 CPU seconds to compute hull (after input): 0.786 Test -- QR2 CPU seconds to compute hull (after input): 0.794 Test -- QR3 CPU seconds to compute hull (after input): 0.794 Test -- QR4 CPU seconds to compute hull (after input): 0.758 Test -- QR5 CPU seconds to compute hull (after input): 0.809 Test -- QR6 CPU seconds to compute hull (after input): 0.774 Test -- QR7 CPU seconds to compute hull (after input): 0.792 Test -- QR8 CPU seconds to compute hull (after input): 0.825 Test -- QR9 CPU seconds to compute hull (after input): 0.758 Test -- QR10 CPU seconds to compute hull (after input): 0.777 1591315393 Test 10 runs in 12 seconds (average 1200 msec) -- rbox 100000 M3,4 z D2 | qhull v Qbb Testing -- rbox 20000 M3,4,5 z | qhull v Qbb >/d/bash/var/tmp/qtest-2020-06-04/qhull-911461.log Test -- QR1 CPU seconds to compute hull (after input): 0.861 Test -- QR2 CPU seconds to compute hull (after input): 0.86 Test -- QR3 CPU seconds to compute hull (after input): 0.973 Test -- QR4 CPU seconds to compute hull (after input): 0.854 Test -- QR5 CPU seconds to compute hull (after input): 0.888 Test -- QR6 CPU seconds to compute hull (after input): 0.917 Test -- QR7 CPU seconds to compute hull (after input): 0.922 Test -- QR8 CPU seconds to compute hull (after input): 0.883 Test -- QR9 CPU seconds to compute hull (after input): 0.882 Test -- QR10 CPU seconds to compute hull (after input): 0.893 1591315405 Test 10 runs in 12 seconds (average 1200 msec) -- rbox 20000 M3,4,5 z | qhull v Qbb Testing -- rbox 5000 M3,4,5 z D4 | qhull v Qbb >/d/bash/var/tmp/qtest-2020-06-04/qhull-313185.log Test -- QR1 CPU seconds to compute hull (after input): 0.917 Test -- QR2 CPU seconds to compute hull (after input): 0.894 Test -- QR3 CPU seconds to compute hull (after input): 0.838 Test -- QR4 CPU seconds to compute hull (after input): 0.893 Test -- QR5 CPU seconds to compute hull (after input): 0.918 Test -- QR6 CPU seconds to compute hull (after input): 0.879 Test -- QR7 CPU seconds to compute hull (after input): 0.895 Test -- QR8 CPU seconds to compute hull (after input): 0.993 Test -- QR9 CPU seconds to compute hull (after input): 0.885 Test -- QR10 CPU seconds to compute hull (after input): 1.034 1591315417 Test 10 runs in 11 seconds (average 1100 msec) -- rbox 5000 M3,4,5 z D4 | qhull v Qbb Testing -- rbox 1500 M3,4,5 z D5 | qhull v Qbb >/d/bash/var/tmp/qtest-2020-06-04/qhull-714909.log Test -- QR1 CPU seconds to compute hull (after input): 1.049 Test -- QR2 CPU seconds to compute hull (after input): 0.996 Test -- QR3 CPU seconds to compute hull (after input): 0.989 Test -- QR4 CPU seconds to compute hull (after input): 0.974 Test -- QR5 CPU seconds to compute hull (after input): 0.936 Test -- QR6 CPU seconds to compute hull (after input): 0.959 Test -- QR7 CPU seconds to compute hull (after input): 0.872 Test -- QR8 CPU seconds to compute hull (after input): 0.95 Test -- QR9 CPU seconds to compute hull (after input): 0.952 Test -- QR10 CPU seconds to compute hull (after input): 1.055 1591315429 Test 10 runs in 12 seconds (average 1200 msec) -- rbox 1500 M3,4,5 z D5 | qhull v Qbb Testing -- rbox 500 M3,4,5 z D6 | qhull v Qbb >/d/bash/var/tmp/qtest-2020-06-04/qhull-116633.log Test -- QR1 CPU seconds to compute hull (after input): 0.927 Test -- QR2 CPU seconds to compute hull (after input): 0.773 Test -- QR3 CPU seconds to compute hull (after input): 0.841 Test -- QR4 CPU seconds to compute hull (after input): 0.837 Test -- QR5 CPU seconds to compute hull (after input): 0.872 Test -- QR6 CPU seconds to compute hull (after input): 0.696 Test -- QR7 CPU seconds to compute hull (after input): 0.789 Test -- QR8 CPU seconds to compute hull (after input): 0.905 Test -- QR9 CPU seconds to compute hull (after input): 0.793 Test -- QR10 CPU seconds to compute hull (after input): 0.796 1591315440 Test 10 runs in 10 seconds (average 1000 msec) -- rbox 500 M3,4,5 z D6 | qhull v Qbb qhull-2020.2/eg/q_eg0000755060175106010010000000736313473514626012446 0ustar bbarber#!/bin/sh # writes examples to eg/ # see html/qh_eg.htm if ! which qconvex >/dev/null 2>&1; then if [ ! -d bin ]; then echo 'eg/q_eg: Run eg/q_eg from the Qhull directory with bin/qconvex, or add qconvex/etc. to $PATH' exit 1 fi if [ ! -e bin/qconvex -a ! -e bin/qconvex.exe ]; then echo 'eg/q_eg: Build qhull first. qconvex is missing from bin/ directory and $PATH' exit 1 fi echo 'eg/q_eg: Temporarily add "$PWD/bin" to $PATH for access to qconvex,etc.' PATH=$PWD/bin:$PATH if ! which qconvex >/dev/null 2>&1; then echo 'eg/q_eg: PATH=... failed. Please execute "export PATH=$PWD/bin:$PATH" and repeat' exit 1 fi fi mkdir -p eg echo ============================== echo ========= eg/q_eg ============ echo == Create geomview examples == echo ============================== echo set -v rbox c D3 | qconvex s G >eg/eg.01.cube rbox c d G2.0 | qconvex s G >eg/eg.02.diamond.cube rbox s 100 D3 | qconvex s G >eg/eg.03.sphere rbox s 100 D2 | qconvex s G >eg/eg.04.circle rbox 10 l | qconvex s G >eg/eg.05.spiral rbox 1000 D2 | qconvex s C-0.03 Qc Gapcv >eg/eg.06.merge.square rbox 1000 D3 | qconvex s G >eg/eg.07.box rbox c G0.4 s 500 | qconvex s G >eg/eg.08a.cube.sphere rbox d G0.6 s 500 | qconvex s G >eg/eg.08b.diamond.sphere rbox 100 L3 G0.5 s | qconvex s G >eg/eg.09.lens rbox 100 s P0.5,0.5,0.5 | qconvex s Ga QG0 >eg/eg.10a.sphere.visible rbox 100 s P0.5,0.5,0.5 | qconvex s Ga QG-0 >eg/eg.10b.sphere.beyond rbox 100 s P0.5,0.5,0.5 | qconvex s Ga QG0 PG >eg/eg.10c.sphere.horizon rbox 100 s P0.5,0.5,0.5 | qconvex s Ga QV0 PgG >eg/eg.10d.sphere.cone rbox 100 s P0.5,0.5,0.5 | qconvex s Ga >eg/eg.10e.sphere.new rbox 100 s P0.5,0.5,0.5 | qhull s Ga QV0g Q0 >eg/eg.14.sphere.corner rbox 500 W0 | qconvex s QR0 Qc Gvp >eg/eg.15a.surface rbox 500 W0 | qconvex s QR0 Qt Qc Gvp >eg/eg.15b.triangle rbox 500 W0 | qconvex s QR0 QJ5e-2 Qc Gvp >eg/eg.15c.joggle echo 2 = rbox 6 r s D2, rbox 15 B0.3 W0.25, c G0.5 >eg/eg.data.17 echo 25 >>eg/eg.data.17 rbox 15 D2 B0.3 W0.25 c G0.5 | tail -n +3 >>eg/eg.data.17 rbox 6 r s D2 B0.2 | tail -n +3 >>eg/eg.data.17 qdelaunay s Qt eg/eg.17a.delaunay.2 qdelaunay s eg/eg.17b.delaunay.2i qdelaunay s eg/eg.17c.delaunay.2-3 qvoronoi s QJ eg/eg.17d.voronoi.2 qvoronoi s eg/eg.17e.voronoi.2i rbox c G0.1 d | qdelaunay Gt Qz >eg/eg.17f.delaunay.3 rbox 10 D2 d | qdelaunay s Qu G >eg/eg.18a.furthest.2-3 rbox 10 D2 d | qdelaunay s Qu Pd2 G >eg/eg.18b.furthest-up.2-3 rbox 10 D2 d | qvoronoi s Qu Gv >eg/eg.18c.furthest.2 rbox 10 D3 | qvoronoi s FQ QV5 p | qconvex s G >eg/eg.19.voronoi.region.3 rbox r s 20 Z1 G0.2 | qconvex s QR1 G >eg/eg.20.cone rbox 200 s | qconvex s Qc R0.014 Gpav >eg/eg.21b.roundoff.fixed rbox 1000 s| qconvex s C0.01 Qc Gcrp >eg/eg.22a.merge.sphere.01 rbox 1000 s| qconvex s C-0.01 Qc Gcrp >eg/eg.22b.merge.sphere.-01 rbox 1000 s| qconvex s C0.05 Qc Gcrpv >eg/eg.22c.merge.sphere.05 rbox 1000 s| qconvex s C-0.05 Qc Gcrpv >eg/eg.22d.merge.sphere.-05 rbox 1000 | qconvex s Gcprvah C0.1 Qc >eg/eg.23.merge.cube rbox 5000 D4 | qconvex s GD0v Pd0:0.5 C-0.02 C0.1 >eg/eg.24.merge.cube.4d-in-3d rbox 5000 D4 | qconvex s s C-0.02 C0.1 Gh >eg/eg.30.4d.merge.cube rbox 20 D3 | qdelaunay s G >eg/eg.31.4d.delaunay rbox 30 s D4 | qconvex s G Pd0d1d2D3 >eg/eg.32.4d.octant rbox 10 r s Z1 G0.3 | qconvex G >eg/eg.33a.cone rbox 10 r s Z1 G0.3 | qconvex FQ FV n | qhalf G >eg/eg.33b.cone.dual rbox 10 r s Z1 G0.3 | qconvex FQ FV n | qhalf FQ s Fp | qconvex G >eg/eg.33c.cone.halfspace echo ==the following should generate flipped and concave facets== >/dev/null rbox 200 s | qhull Q0 s R0.014 Gav Po >eg/eg.21a.roundoff.errors echo ==the preceding should report flipped and concave facets== >/dev/null echo END eg/q_eg >/dev/null qhull-2020.2/eg/q_egtest0000755060175106010010000000501413473514635013335 0ustar bbarber#!/bin/sh # writes examples to eg/ if ! which qconvex >/dev/null 2>&1; then if [ ! -d bin ]; then echo 'eg/q_egtest: Run eg/q_egtest from the Qhull directory with bin/qconvex, or add qconvex/etc. to $PATH' exit fi if [ ! -e bin/qconvex -a ! -e bin/qconvex.exe ]; then echo 'eg/q_egtest: Build qhull first. qconvex is missing from bin/ directory and $PATH' exit fi echo 'eg/q_egtest: Temporarily add "$PWD/bin" to $PATH for access to qconvex,etc.' PATH=$PWD/bin:$PATH if ! which qconvex >/dev/null 2>&1; then echo 'eg/q_egtest: PATH=... failed. Please execute "export PATH=$PWD/bin:$PATH" and repeat' exit 1 fi fi mkdir -p eg echo ============================== echo ========= eg/q_egtest ======== echo == Create geomview tests ===== echo ============================== echo set -v rbox d D3 | qconvex s Gnrv Tc Tv >eg/eg.t01.spheres.3 rbox d D2 | qconvex s Gnv Tc Tv >eg/eg.t02.spheres.2 rbox d D3 | qconvex s Gnrp Tc Tv >eg/eg.t03.points.3 rbox d D2 | qconvex s Gnp Tc Tv >eg/eg.t04.points.2 rbox c D4 | qconvex s C0.05 GnpcD3 Pd3:0.5 Tc Tv >eg/eg.t05.centrum.points.4-3 rbox d D3 | qconvex s Gnrc Tc Tv >eg/eg.t06.centrums.3.precise rbox d D3 | qconvex s C0.05 Gnrc Tc Tv >eg/eg.t07.centrums.3 rbox d D2 | qconvex s C0.05 Gc Tc Tv >eg/eg.t08.centrums.2 rbox d D3 | qconvex s Gnha Tc Tv >eg/eg.t09.intersect.3 rbox d D3 | qconvex s GaD0 Pd0 Tc Tv >eg/eg.t10.faces.3-2 rbox d D3 | qconvex s GnrpD0 Pd0 Tc Tv >eg/eg.t11.points.3-2 rbox d D3 | qconvex s C0.05 GnrcD0 Pd0 Tc Tv >eg/eg.t12.centrums.3-2 rbox d D3 | qconvex s GnhaD0 Pd0 Tc Tv >eg/eg.t13.intersect.3-2 rbox d D3 | qconvex s GnrvD0 Pd0 Tc Tv >eg/eg.t14.spheres.3-2 rbox c D4 | qconvex s GvD0 Pd0:0.5 Tc Tv >eg/eg.t15.spheres.4-3 rbox c D4 | qhull s Q0 C0 GpD0 Pd0:0.5 Tc Tv >eg/eg.t16.points.4-3 rbox c D4 | qconvex s GahD0 Pd0:0.5 Tc Tv >eg/eg.t17.intersect.4-3 rbox 100 s | qconvex s C-0.05 Qc Gicvprh Tc Tv >eg/eg.t18.imprecise.3 rbox 30 s D4 | qconvex s GhD0 Pd0d1d2D3 Tc >eg/eg.t19.intersect.precise.4-3 rbox 100 s P1,1,1 | qconvex s QG-0 Pgp Tc G >eg/eg.t20.notvisible rbox 100 s | qconvex s QV-10 Pgp Tc G >eg/eg.t21.notvertex rbox 100 r D2 P1,1 | qhull s Pd0:0.7 PD0:0.8 QgG0 G Tv >eg/eg.t22.split rbox 100 D2 c G1.0 | qvoronoi s A-0.95 Gna Tv >eg/eg.t23.voronoi.imprecise rbox 30 s D4 | qconvex s Gh Pd0d1d2D3 Tc >eg/eg.t24.intersect.precise.4d echo ==the following generates an error== >/dev/null rbox 1000 D4 | qhull Q0 s Po R0.005 Ga Tc Tv >eg/eg.t25.neighbors.4d echo ==the previous should generate an error== >/dev/null echo END eg/q_egtest >/dev/null qhull-2020.2/eg/q_test0000755060175106010010000003755313666250233013031 0ustar bbarber#!/bin/sh # # NOTE: all tests duplicated in q_test.bat if ! which qconvex >/dev/null 2>&1; then if [ ! -d bin ]; then echo 'eg/q_test: Run eg/q_test from the Qhull directory with bin/qconvex, or add qconvex/etc. to $PATH' exit 1 fi if [ ! -e bin/qconvex -a ! -e bin/qconvex.exe ]; then echo 'eg/q_test: Build qhull first. qconvex is missing from bin/ directory and $PATH' exit 1 fi echo 'eg/q_test: Temporarily add "$PWD/bin" to $PATH for access to qconvex,etc.' PATH=$PWD/bin:$PATH if ! which qconvex >/dev/null 2>&1; then echo 'eg/q_test: PATH=... failed. Please execute "export PATH=$PWD/bin:$PATH" and repeat' exit 1 fi fi if ! user_eg >/dev/null; then echo eg/q_test: user_eg failed to run. It uses the shared qhull library echo 'On Linux, export LD_LIBRARY_PATH=$PWD/lib:$LD_LIBRARY_PATH' echo 'On Windows with mingw, cp -p lib/libqhull_r.dll bin/' fi echo ============================== echo ========= eg/q_test ========== echo == Check qhull programs ====== echo ============================== echo echo "qhull => $(qhull -V)" echo "qconvex => $(qconvex -V)" echo "qvoronoi => $(qconvex -V)" echo "qdelaunay => $(qdelaunay -V)" echo "qhalf => $(qhalf -V)" (ls -ld $(which qhull) \ $(which qconvex) \ $(which qvoronoi) \ $(which qdelaunay) \ $(which qhalf) \ $(which user_eg) \ $(which user_eg2) \ $(which user_eg3)) 2>/dev/null echo ============================== echo == check user_eg, user_eg2, and user_eg3 echo == errors if 'user_eg' and 'user_eg2' not found echo ============================== set -v # echo commands to stdout user_eg user_eg 'QR1 p n Qt' 'v p' 'Fp' user_eg2 user_eg2 'QR1 p' 'v p' 'Fp' user_eg3 user_eg3 eg-100 user_eg3 eg-convex user_eg3 eg-delaunay user_eg3 eg-voronoi user_eg3 eg-fifo user_eg3 rbox qhull user_eg3 rbox qhull T1 user_eg3 rbox qhull d user_eg3 rbox y c user_eg3 rbox D2 10 2 "s r 5" qhull 's p' facets user_eg3 rbox "10 D2" eg-convex user_eg3 rbox '10 D2' qhull s eg-convex user_eg3 rbox 10 eg-delaunay qhull 'd o' user_eg3 rbox D5 c P2 qhull d eg-delaunay user_eg3 rbox '10 D2' eg-voronoi user_eg3 rbox "D5 c P2" qhull v eg-voronoi o user_eg3 rbox '10 D2' eg-fifo user_eg3 rbox D2 10 qhull v eg-fifo p Fi Fo set +v echo === check front ends and examples ${d:-`date`} ================== set -v qconvex - qconvex . qconvex -? # [mar'19] isatty does not work for Git for Windows rbox c D3 | qconvex s n Qt rbox c D2 | qconvex s i rbox c D2 | qconvex s n rbox c D2 | qconvex o rbox 1000 s | qconvex s Tv FA rbox c d D2 | qconvex s Qc Fx rbox y 1000 W0 | qconvex Qc s n rbox y 1000 W0 | qconvex s QJ rbox d G1 D12 | qconvex QR0 FA rbox c D6 | qconvex s FA TF500 rbox c D7 | qconvex s FA TF1000 rbox d G1 D12 | qconvex QR0 FA Pp rbox c P0 d D2 | qconvex p Fa Fc FP FI Fn FN FS Fv Fx rbox c d D2 | qconvex s i QV0 rbox c | qconvex Q0 qvoronoi - qvoronoi . qvoronoi -? # [mar'19] isatty does not work for Git for Windows rbox c P0 D2 | qvoronoi s o rbox c P0 D2 | qvoronoi Fi Tv rbox c P0 D2 | qvoronoi Fo Tv rbox c P0 D2 | qvoronoi Fv rbox c P0 D2 | qvoronoi s Qu Fv rbox c P0 D2 | qvoronoi s Qu Qt Fv rbox c P0 D2 | qvoronoi Qu Fo rbox c G1 d D2 | qvoronoi s p rbox c G1 d D2 | qvoronoi QJ p rbox c P-0.1 P+0.1 P+0.1 D2 | qvoronoi s Fc FP FQ Fn FN rbox P0 c D2 | qvoronoi s Fv QV0 qdelaunay - qdelaunay . qdelaunay -? # [mar'19] isatty does not work for Git for Windows rbox c P0 D2 | qdelaunay s o rbox c P0 D2 | qdelaunay i rbox c P0 D2 | qdelaunay Fv rbox c P0 D2 | qdelaunay s Qu Qt Fv rbox c G1 d D2 | qdelaunay s i rbox c G1 d D2 | qhull d Qbb Ft rbox c G1 d D2 | qhull d Qbb QJ s Ft rbox M3,4 z 100 D2 | qdelaunay s rbox c P-0.1 P+0.1 P+0.1 D2 | qdelaunay s Fx Fa Fc FP FQ Fn FN rbox P0 P0 c D2 | qdelaunay s FP QV0 qhalf - qhalf . qhalf -? # [mar'19] isatty does not work for Git for Windows rbox d | qhull FQ n | qhalf s Qt H0,0,0 Fp rbox c | qhull FQ FV n | qhalf s i rbox c | qhull FQ FV n | qhalf o rbox d D2 | qhull FQ n | qhalf s H0 Fc FP Fn FN FQ Fv Fx # qhull - printed at end qhull . qhull -? # [mar'19] isatty does not work for Git for Windows rbox 1000 s | qhull Tv s FA rbox 10 D2 | qhull d QJ s i TO q_test.log.1 cat q_test.log.1 rbox 10 D2 | qhull v Qbb Qt p rbox 10 D2 | qhull d Qu QJ m rbox 10 D2 | qhull v Qu QJ o rbox c d D2 | qhull Qc s f Fx rbox c | qhull FV n | qhull H Fp rbox d D12 | qhull QR0 FA rbox c D7 | qhull FA TF1000 rbox y 1000 W0 | qhull Qc rbox c | qhull n rbox c | qhull TA1 rbox 10 s | qhull C1e-5 T1P-1f set +v echo === check quality of Qhull for ${d:-`hostname`} ${d:-`date`} set -v rbox 1000 W0 | qhull QR2 QJ s Fs Tv rbox 1000 W0 | qhull QR2 s Fs Tv rbox 1000 s | qhull C0.02 Qc Tv rbox 500 s D4 | qhull C0.01 Qc Tv rbox 1000 s | qhull C-0.02 Qc Tv rbox 1000 s D4 | qhull C-0.01 Qc Tv rbox 200 s D5 | qhull C-0.01 Qx Qc Tv rbox 100 s D6 | qhull C-0.001 Qx Qc Tv rbox 1000 W1e-4 | qhull C-1e-6 Qc Tv rbox 1000 W5e-4 D4 | qhull C-1e-5 Qc Tv rbox 400 W1e-3 D5 | qhull C-1e-5 Qx Qc Tv set +v echo === check input format etc. ${d:-`date`} set -v qhull <r.x qhull TIr.x qhull p TI r.x TO x.x cat x.x set +v echo === check qhull output formats ${d:-`date`} set -v rbox 5 r s D2 | qhull Tcv rbox 5 r s D2 | qhull s rbox 5 r s D2 | qhull s o rbox 5 r s D2 | qhull f rbox 5 r s D2 | qhull i rbox 5 r s D2 | qhull m rbox 5 r s D2 | qhull FM rbox 5 r s D2 | qhull n rbox 5 r s D2 | qhull p rbox 5 r s D2 | qhull o rbox 5 r s D2 | qhull Ft rbox 5 r s D2 | qhull Fx rbox 5 r s D2 | qhull p n i p p rbox 10 D3 | qhull f Tcv rbox 10 D3 | qhull i rbox 10 D3 | qhull p rbox 10 D3 | qhull o rbox 10 D3 | qhull Fx rbox 27 M1,0,1 | qhull Qc rbox 50 D3 s | qhull C0.1 Qc Pd0d1d2 Pg s p Tcv rbox 10 D2 P0 P1e-15 | qhull d Qc FP s Tcv rbox 100 s | qhull C-0.003 Qc FP s rbox 100 s D2 | qhull C0.1 i Fx Tcv rbox 4 s D3 | qhull Qc Ghipv Tcv rbox 6 D4 | qhull f Tcv rbox 6 D4 | qhull i rbox 6 D4 | qhull p rbox 6 D4 | qhull o rbox 1000 s D2 | qhull FA Tcv rbox 1000 s | qhull FA Tcv rbox c D4 | qhull FA Tcv rbox c D5 | qhull FA Tcv rbox c D5 | qhull FA Qt Tcv rbox 10 D2 | qhull d FA Tcv rbox 10 D2 | qhull d Qu FA Tcv rbox 10 D2 | qhull FA Tcv rbox 10 c D2 | qhull Fx Tcv rbox 1000 s | qhull FS Tcv rbox 10 W0 D2 | qhull p Qc FcC Tcv rbox 4 z h s D2 | qhull Fd s n FD Tcv rbox 6 s D3 | qhull C-0.1 Qc FF s FQ Fi n Fo FQ FI Fm Fn FN FO FO FQ Fs FS FV Fv Tcv rbox P0.5,0.5 P0.5,0.5 W0 5 D2 | qhull d FN Qc rbox 10 D3 | qhull Fa PA5 rbox 10 D3 | qhull Fa PF0.4 set +v echo === test Qt ${d:-`date`} set -v rbox c | qhull Qt s o Tcv rbox c | qhull Qt f i rbox c | qhull Qt m FM n rbox c | qhull Qt p o rbox c | qhull Qt Fx rbox c | qhull Qt FA s Fa rbox 6 r s c G0.1 D2 | qhull Qt d FA Tcv rbox 6 r s c G0.1 D2 | qhull d FA Tcv rbox 6 r s c G0.1 D2 | qhull Qt v p Tcv rbox c | qhull Qt C-0.1 Qc FF s FQ Fi n Fo FQ FI Fm Fn FN FO FO FQ Fs FS FV Fv Tcv rbox 6 r s c G0.1 D2 P0.1,0.1 | qhull s FP d FO Qt rbox 100 W0 | qhull Tv Q11 FO set +v echo === test unbounded intersection ${d:-`date`} set -v rbox c | qhull PD0:0.5 n | qhull H0 Fp Tcv rbox 1000 W1e-3 D3 | qhull PA8 Fa FS s n Tcv rbox 1000 W1e-3 D3 | qhull C-0.01 PM10 Fm n Tcv Qc rbox 1000 W1e-3 D3 | qhull C-0.01 PA8 PG n Tcv Qc rbox 10 | qhull FO Tz TO q_test.log.1 cat q_test.log.1 set +v echo === check Delaunay/Voronoi ${d:-`date`} set -v rbox 10 D2 | qhull d Tcv rbox 10 D2 | qhull d Qz Tcv rbox 10 D3 | qhull d Tcv rbox c | qhull d Qz Ft Tcv rbox 10 s D2 c | qhull d Tcv rbox 10 s D2 | qhull d Tcv Qz Q8 rbox 10 D2 | qhull d Tcv p rbox 10 D2 | qhull d Tcv i rbox 10 D2 | qhull d Tcv o rbox 10 D2 | qhull v Tcv o rbox 10 D2 | qhull v Tcv p rbox 10 D2 | qhull v Tcv G rbox 10 D2 | qhull v Tcv Fv rbox 10 D2 | qhull v Tcv Fi rbox 10 D2 | qhull v Tcv Fo rbox 10 D2 | qhull v Qu o Fv Fi Fo Tcv rbox 10 D3 | qhull v Fv Tcv rbox 10 D3 | qhull v Fi Tcv rbox 10 D3 | qhull v Fo Tcv rbox 10 D3 | qhull v Qu o Fv Fi Fo Tcv rbox 5 D2 | qhull v f FnN o set +v echo === check Halfspace and Qhull identity pipeline, showing the input ${d:-`date`} echo === the Qhull pipeline recreates 100 4-D cospherical points with the same area and volume set -v rbox 100 s D4 | qhull FA FV s n | head rbox 100 s D4 | qhull FQ FA FV n s | qhull s H Fp | head rbox 100 s D4 | qhull FQ FA FV n s Tcv | qhull FQ s H Fp Tcv | qhull FA Tcv echo === the Qhull pipeline recreates a 3-D tetrahedron rbox d D3 | qhull n FD rbox d D3 | qhull s n FD Tcv | qhull s Fd H0.1,0.1 Fp Tcv echo === the Qhull pipeline recreates a regular 2-D pentagon rbox 5 r D2 | qhull FQ n rbox 5 r D2 | qhull s FQ n Tcv | qhull s H0 Fp Tcv set +v echo === check qhull ${d:-`date`} set -v rbox 10 s D3 | qhull Tcv rbox 10 s D3 | qhull f Pd0:0.5 Pd2 Pg Tcv rbox 10 s D3 | qhull f Tcv PD2:-0.5 Pg rbox 10 s D3 | qhull QR-1 rbox 10 s D3 | qhull QR-40 rbox 1000 D3 | qhull Tcvs # Test tracing 'Tn', combine stderr/stdout 'Tz', flush fprintf 'Tf' rbox 100 D3 | qhull T1 Tz Tf TA1 TO q_test.log.1 tail -n -10 q_test.log.1 rm q_test.log.1 rbox 100 s D3 | qhull TcvA10 rbox 100 s D3 | qhull TcvV-2 rbox 100 s D3 | qhull TcvC2 rbox 100 s D3 | qhull TcvV2 rbox 100 s D3 | qhull T1cvV2P2 rbox 100 s D3 | qhull TcvF100 rbox 100 s D3 | qhull Qf Tcv rbox 100 D3 | qhull Tcv rbox 100 D3 | qhull Qs Tcv rbox 100 D5 | qhull Qs Tcv rbox 100 D3 | qhull Qr Tcv rbox 100 D3 | qhull Qxv Tcv rbox 100 D3 | qhull Qi f Pd0 Pd1 Pd2 Pg Tcv rbox c d | qhull Qc f Tcv rbox c d | qhull Qc p Tcv rbox 100 D3 | qhull QbB FO Tcv rbox 1000 D2 B1e6 | qhull d Qbb FO Tcv rbox 10 D3 | qhull QbB p Tcv rbox 10 D3 | qhull Qbb p Tcv rbox 10 D3 | qhull Qb0:-10B2:20 p Tcv rbox 10 D3 | qhull Qb0:-10B2:20 p Tcv | qhull QbB p Tcv rbox 10 D3 | qhull Qb1:0B1:0 d Tcv Q8 rbox 10 D3 | qhull Qb1:0B1:0B2:0 d Tcv Q8 rbox 10 D3 | qhull Qb1:0 d Tcv rbox 10 D3 | qhull Qb1:0B1:0 Tcv echo "== next command will error ${d:-`date`} ==" rbox 10 D2 | qhull Qb1:1B1:1 Tcv rbox 200 L20 D2 t | qhull FO Tcv C-0 rbox 1000 L20 t | qhull FO Tcv C-0 rbox 200 L20 D4 t | qhull FO Tcv C-0 rbox 200 L20 D5 t | qhull FO Tcv Qx rbox 1000 W1e-3 s D2 t | qhull d FO Tcv Qu Q0 rbox 1000 W1e-3 s D2 t | qhull d FO Tcv Qu C-0 set +v echo === check joggle and TRn ${d:-`date`} set -v rbox 100 W0 | qhull QJ1e-14 Qc TR100 Tv rbox 100 W0 | qhull QJ1e-13 Qc TR100 Tv rbox 100 W0 | qhull QJ1e-12 Qc TR100 Tv rbox 100 W0 | qhull QJ1e-11 Qc TR100 Tv rbox 100 W0 | qhull QJ1e-10 Qc TR100 Tv rbox 100 | qhull d QJ Qb0:1e4 QB0:1e5 Qb1:1e4 QB1:1e6 Qb2:1e5 QB2:1e7 FO Tv set +v echo === check precision options ${d:-`date`} set -v rbox 100 D3 s | qhull E0.01 Qx Tcv FO rbox 100 D3 W1e-1 | qhull W1e-3 Tcv rbox 100 D3 W1e-1 | qhull W1e-2 Tcv Q0 rbox 100 D3 W1e-1 | qhull W1e-2 Tcv rbox 100 D3 W1e-1 | qhull W1e-1 Tcv rbox 15 D2 P0 P1e-14,1e-14 | qhull d Quc Tcv rbox 15 D3 P0 P1e-12,1e-14,1e-14 | qhull d Qcu Tcv rbox 1000 s D3 | qhull C-0.01 Tcv Qc rbox 1000 s D3 | qhull C-0.01 V0 Qc Tcv rbox 1000 s D3 | qhull C-0.01 U0 Qc Tcv rbox 1000 s D3 | qhull C-0.01 V0 Qcm Tcv rbox 1000 s D3 | qhull C-0.01 Qcm Tcv rbox 1000 s D3 | qhull C-0.01 Q1 FO Tcv Qc rbox 1000 s D3 | qhull C-0.01 Q2 FO Tcv Qc rbox 1000 s D3 | qhull C-0.01 Q3 FO Tcv Qc rbox 1000 s D3 | qhull C-0.01 Q4 FO Tcv Qc echo === this may generate an error ${d:-`date`} rbox 1000 s D3 | qhull C-0.01 Q5 FO Tcv echo === this should generate an error ${d:-`date`} rbox 1000 s D3 | qhull C-0.01 Q6 FO Po Tcv Qc rbox 1000 s D3 | qhull C-0.01 Q7 FO Tcv Qc rbox 1000 s D3 | qhull C-0.01 Qx Tcv Qc echo === this may generate an error e.g., t1263080158 ${d:-`date`} rbox 100 s D3 t | qhull R1e-3 Tcv Qc rbox 100 s D3 t | qhull R1e-2 Tcv Qc rbox 500 s D3 t | qhull R0.05 A-1 Tcv Qc rbox 100 W0 D3 t | qhull R1e-3 Tcv Qc rbox 100 W0 D3 t | qhull R1e-3 Qx Tcv Qc rbox 100 W0 D3 t | qhull R1e-2 Tcv Qc rbox 100 W0 D3 t | qhull R1e-2 Qx Tcv Qc rbox 500 W0 D3 t | qhull R0.05 A-1 Tcv Qc rbox 500 W0 D3 t | qhull R0.05 Qx Tcv Qc rbox 1000 W1e-20 t | qhull Tcv Qc rbox 1000 W1e-20 D4 t | qhull Tcv Qc rbox 500 W1e-20 D5 t | qhull Tv Qc rbox 100 W1e-20 D6 t | qhull Tv Qc rbox 50 W1e-20 D6 t | qhull Qv Tv Qc rbox 10000 D4 t | qhull QR0 Qc C-0.01 A0.3 Tv rbox 1000 D2 t | qhull d QR0 Qc C-1e-8 Qu Tv rbox 300 D5 t |qhull A-0.999 Qx Qc Tcv rbox 100 D6 t |qhull A-0.9999 Qx Qc Tcv rbox 50 D7 t |qhull A-0.99999 Qx Qc Tcv W0.1 set +v echo ======================================================= echo === The following commands may cause errors ${d:-`date`} echo ======================================================= echo echo === check bad cases for Qhull ${d:-`date`} set -v rbox 1000 L100000 s G1e-6 t | qhull Tv rbox 1000 L100000 s G1e-6 t | qhull Tv Q10 rbox 1000 s Z1 G1e-13 t | qhull Tv rbox 1000 s W1e-13 P0 t | qhull d Qbb Qc Q12 Tv rbox 1000 s W1e-13 t | qhull d Q12 Tv rbox 1000 s W1e-13 t D2 | qhull d Tv set +v echo === check Qhull without merging Q0 ${d:-`date`} set -v rbox c D7 | qhull Q0 Tcv rbox 100 s D3 | qhull Q0 E1e-3 Tc Po rbox 100 s D3 | qhull Q0 E1e-2 Tc Po rbox 100 s D3 | qhull Q0 E1e-1 Tc Po rbox 100 s D3 | qhull Q0 R1e-3 Tc Po rbox 100 s D3 | qhull Q0 R1e-2 Tc Po rbox 100 s D3 | qhull Q0 R0.05 Tc rbox 100 s D3 | qhull Q0 R0.05 Tc Po rbox 1000 W1e-7 | qhull Q0 Tc Po rbox 50 s | qhull Q0 V0.05 W0.01 Tc Po rbox 100 s D5 | qhull Q0 R1e-2 Tc Po set +v echo === check nearly incident points ${d:-`date`} set -v rbox L100 2000 D4 s C1,1e-13 t2 | qhull rbox L100 2000 D4 s C1,1e-13 t2 | qhull Q12 rbox 50 C1,1E-13 t1447644703 | qhull d rbox 50 C1,1E-13 t1447644703 | qhull d Q12 rbox 50 C1,1E-13 t1447644703 | qhull d Q14 set +v echo ======================================================= echo === Testing done. Print documentation echo ======================================================= set -v qhull - rbox cat html/qhull.txt html/rbox.txt # end of q_test qhull-2020.2/eg/q_test-ok.txt0000644060175106010010000213714613710365751014256 0ustar bbarber============================================ == make qtest ============================== ============================================ == Fri, Jul 24, 2020 10:27:09 PM ============================================ == Test non-reentrant qset.c with mem.c ==== ============================================ bin/testqset 10000 qh_meminitbuffers: memory initialized with alignment 8 qh_memsize: quick memory of 16 bytes qh_memsize: quick memory of 24 bytes qh_memsize: quick memory of 32 bytes qh_memsize: quick memory of 40 bytes SETelemsize is 4 bytes for pointer-to-int Testing qh_setappend 0..9999. Test i0 i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i100 i1000 i9999 Testing qh_settruncate 5000 and 0. Test n0 Testing qh_setappend2ndlast 0,0..9999. Test 0 i0 i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i100 i1000 i9999 Testing SETtruncate_ 5000 and 0. Test n0 Testing qh_setdelnthsorted and qh_setaddnth 1..9999. Test j1 j2 j3 j4 j5 j6 j7 j8 j9 j10 j100 j1000 j9999 Testing qh_setappend_set 0..9999. Test j0 j1 j2 j3 j4 j5 j6 j7 j8 j9 j10 j100 j1000 j9999 Testing qh_setcompact and qh_setcopy 0..9999. Test j0 j1 j2 j3 j4 j5 j6 j7 j8 j9 j10 j100 j1000 j9999 Testing qh_setequal*, qh_setin*, qh_setdel, qh_setdelnth, and qh_setlarger 0..9999. Test j0 j1 j2 j3 j4 j5 j6 j7 j8 j9 j10 j100 j1000 j9999 Testing qh_settemp* 0..9999. Test j0 j1 j2 j3 j4 j5 j6 j7 j8 j9 j10 j100 j1000 j9999 Testing qh_setlast, qh_setnew_delnthsorted, qh_setunique, and qh_setzero 0..9999. Test j0 j1 j2 j3 j4 j5 j6 j7 j8 j9 j10 j100 j1000 j9999 Testing qh_setdel*, qh_setaddsorted, and 0..9999. Test j0 j1 j2 j3 j4 j5 j6 j7 j8 j9 j10 j100 j1000 j9999 Not testing qh_setduplicate and qh_setfree2. These routines use heap-allocated, set contents. See qhull tests in eg/q_test and bin/qhulltest. qh_memcheck: check size of freelists on qhmem qh_memcheck: A segmentation fault indicates an overwrite of qhmem qh_memcheck: total size of freelists totfree is the same as qhmem.totfree memory statistics: 124 quick allocations 25 short allocations 8230 long allocations 148 short frees 8230 long frees 24 bytes of short memory in use 760 bytes of short memory in freelists 130280 bytes of dropped short memory 68 bytes of unused short memory (estimated) 105548 bytes of long memory allocated (max, except for input) 0 bytes of long memory in use (in 0 pieces) 131064 bytes of short memory buffers (minus links) 65536 bytes per short memory buffer (initially 131072 bytes) 1135 calls to qh_setlarger 5.6e+02 average copy size freelists(bytes->count): 16->3 24->5 32->6 40->10 testqset: OK ============================================ == Test reentrant qset_r.c with mem_r.c ==== ============================================ bin/testqset_r 10000 qh_meminitbuffers: memory initialized with alignment 8 qh_memsize: quick memory of 16 bytes qh_memsize: quick memory of 24 bytes qh_memsize: quick memory of 32 bytes qh_memsize: quick memory of 40 bytes SETelemsize is 4 bytes for pointer-to-int Testing qh_setappend 0..9999. Test i0 i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i100 i1000 i9999 Testing qh_settruncate 5000 and 0. Test n0 Testing qh_setappend2ndlast 0,0..9999. Test 0 i0 i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i100 i1000 i9999 Testing SETtruncate_ 5000 and 0. Test n0 Testing qh_setdelnthsorted and qh_setaddnth 1..9999. Test j1 j2 j3 j4 j5 j6 j7 j8 j9 j10 j100 j1000 j9999 Testing qh_setappend_set 0..9999. Test j0 j1 j2 j3 j4 j5 j6 j7 j8 j9 j10 j100 j1000 j9999 Testing qh_setcompact and qh_setcopy 0..9999. Test j0 j1 j2 j3 j4 j5 j6 j7 j8 j9 j10 j100 j1000 j9999 Testing qh_setequal*, qh_setin*, qh_setdel, qh_setdelnth, and qh_setlarger 0..9999. Test j0 j1 j2 j3 j4 j5 j6 j7 j8 j9 j10 j100 j1000 j9999 Testing qh_settemp* 0..9999. Test j0 j1 j2 j3 j4 j5 j6 j7 j8 j9 j10 j100 j1000 j9999 Testing qh_setlast, qh_setnew_delnthsorted, qh_setunique, and qh_setzero 0..9999. Test j0 j1 j2 j3 j4 j5 j6 j7 j8 j9 j10 j100 j1000 j9999 Testing qh_setdel*, qh_setaddsorted, and 0..9999. Test j0 j1 j2 j3 j4 j5 j6 j7 j8 j9 j10 j100 j1000 j9999 Not testing qh_setduplicate and qh_setfree2. These routines use heap-allocated, set contents. See qhull tests in eg/q_test and bin/qhulltest. qh_memcheck: check size of freelists on qh->qhmem qh_memcheck: A segmentation fault indicates an overwrite of qh->qhmem qh_memcheck: total size of freelists totfree is the same as qh->qhmem.totfree memory statistics: 124 quick allocations 25 short allocations 8230 long allocations 148 short frees 8230 long frees 24 bytes of short memory in use 760 bytes of short memory in freelists 130280 bytes of dropped short memory 68 bytes of unused short memory (estimated) 105548 bytes of long memory allocated (max, except for input) 0 bytes of long memory in use (in 0 pieces) 131064 bytes of short memory buffers (minus links) 65536 bytes per short memory buffer (initially 131072 bytes) 1135 calls to qh_setlarger 5.6e+02 average copy size freelists(bytes->count): 16->3 24->5 32->6 40->10 testqset_r: OK ============================================ == Run the qhull smoketest ==== ============================================ bin/rbox D4 | bin/qhull Tv Starting the rbox smoketest for qhull. An immediate failure indicates that non-reentrant rbox was linked to reentrant routines. An immediate failure of qhull may indicate that qhull was linked to the wrong qhull library. Also try 'rbox D4 | qhull T1' Convex hull of 50 points in 4-d: Number of vertices: 50 Number of facets: 260 Statistics for: rbox D4 | qhull Tv Number of points processed: 50 Number of hyperplanes created: 711 Number of distance tests for qhull: 1432 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below 2.8e-15 of all facets. Will make 13000 distance computations. ============================================ == make test, after running qtest ========== ============================================ ============================== ========= rbox/qhull ======= ============================== bin/rbox D4 | bin/qhull Tv Starting the rbox smoketest for qhull. An immediate failure indicates that non-reentrant rbox was linked to reentrant routines. An immediate failure of qhull may indicate that qhull was linked to the wrong qhull library. Also try 'rbox D4 | qhull T1' Convex hull of 50 points in 4-d: Number of vertices: 50 Number of facets: 260 Statistics for: rbox D4 | qhull Tv Number of points processed: 50 Number of hyperplanes created: 711 Number of distance tests for qhull: 1432 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below 2.8e-15 of all facets. Will make 13000 distance computations. ============================== ========= qconvex ============ ============================== bin/rbox 10 | bin/qconvex Tv Convex hull of 10 points in 3-d: Number of vertices: 10 Number of facets: 16 Statistics for: rbox 10 | qconvex Tv Number of points processed: 10 Number of hyperplanes created: 26 Number of distance tests for qhull: 43 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below 2e-15 of all facets. Will make 160 distance computations. ============================== ========= qdelaunay ========== ============================== bin/rbox 10 | bin/qdelaunay Tv Delaunay triangulation by the convex hull of 10 points in 4-d: Number of input sites: 10 Number of Delaunay regions: 15 Statistics for: rbox 10 | qdelaunay Tv Number of points processed: 10 Number of hyperplanes created: 47 Number of facets in hull: 25 Number of distance tests for qhull: 68 CPU seconds to compute hull (after input): 0.001 Output completed. Verifying that all points are below 3e-15 of all facets. Will make 150 distance computations. ============================== ========= qhalf ============== ============================== bin/rbox 10 | bin/qconvex FQ FV n Tv | bin/qhalf Tv Output completed. Verifying that all points are below 2e-15 of all facets. Will make 160 distance computations. Halfspace intersection by the convex hull of 16 points in 3-d: Number of halfspaces: 16 Number of non-redundant halfspaces: 16 Number of intersection points: 10 Number of non-simplicial intersection points: 10 Statistics for: rbox 10 | qconvex FQ FV n Tv | qhalf Tv Number of points processed: 16 Number of hyperplanes created: 29 Number of distance tests for qhull: 99 Number of distance tests for merging: 300 Number of distance tests for checking: 188 Number of merged facets: 18 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 160 distance computations. ============================== ========= qvoronoi =========== ============================== bin/rbox 10 | bin/qvoronoi Tv Voronoi diagram by the convex hull of 10 points in 4-d: Number of Voronoi regions: 10 Number of Voronoi vertices: 15 Statistics for: rbox 10 | qvoronoi Tv Number of points processed: 10 Number of hyperplanes created: 47 Number of facets in hull: 25 Number of distance tests for qhull: 68 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below 3e-15 of all facets. Will make 150 distance computations. ================================= ========= user_eg =============== == if fails under Windows ======= == cp lib/libqhull_r.dll bin/ == ================================= bin/user_eg ======== user_eg 'cube qhull options' 'Delaunay options' 'halfspace options' This is the output from user_eg_r.c. It shows how qhull() may be called from an application, via Qhull's shared, reentrant library. user_eg is not part of Qhull itself. If user_eg fails immediately, user_eg_r.c was incorrectly linked to Qhull's non-reentrant library, libqhull. Try -- user_eg 'T1' 'T1' 'T1' ======== compute convex hull of cube after rotating input input -1 -1 -1 1 -1 -1 -1 1 -1 1 1 -1 -1 -1 1 1 -1 1 -1 1 1 1 1 1 Convex hull of 8 points in 3-d: Number of vertices: 8 Number of facets: 6 Number of non-simplicial facets: 6 Statistics for: | qhull s Tcv Number of points processed: 8 Number of hyperplanes created: 11 Number of distance tests for qhull: 34 Number of distance tests for merging: 96 Number of distance tests for checking: 100 Number of merged facets: 6 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 48 distance computations. 8 vertices and 6 facets with normals: -0 -0 -1 0 -1 0 1 -0 -0 -1 -0 -0 0 1 -0 -0 -0 1 ======== compute 3-d Delaunay triangulation seed: 1595644031 input -0.801 0.00317 -0.695 -0.358 -0.422 0.394 -0.893 -0.345 -0.494 -0.548 0.646 0.388 -0.0159 0.604 0.693 0.43 0.224 0.755 0.0381 -0.37 -0.66 -0.737 0.146 -0.926 Delaunay triangulation by the convex hull of 8 points in 4-d: Number of input sites: 8 Number of Delaunay regions: 8 Statistics for: | qhull s d Tcv Number of points processed: 8 Number of hyperplanes created: 25 Number of facets in hull: 16 Number of distance tests for qhull: 27 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below 8.6e-15 of all facets. Will make 64 distance computations. 8 vertices and 16 facets with normals: 0.44 -0.53 -0.014 0.72 0.34 -0.77 0.14 0.52 -0.071 -0.12 0.39 0.91 -0.2 -0.037 0.42 0.88 -0.31 -0.32 0.65 0.62 -0.38 -0.28 0.66 0.58 0.62 0.65 -0.45 0.03 0.31 0.76 -0.47 -0.32 0.17 0.3 -0.021 -0.94 0.03 0.36 -0.071 -0.93 -0.76 0.11 -0.041 -0.64 -0.55 -0.11 -0.29 -0.78 -0.43 0.24 -0.24 -0.84 -0.94 0.3 0.069 0.11 -0.36 -0.39 -0.78 -0.34 -0.13 0.6 -0.48 -0.63 find 3-d Delaunay triangle or adjacent triangle closest to [0.5, 0.5, ...] -0.02 0.60 0.69 0.04 -0.37 -0.66 -0.74 0.15 -0.93 -0.55 0.65 0.39 ======== Compute a new triangulation as a separate instance of Qhull seed: 1595644032 input -0.801 0.266 0.816 0.559 0.644 0.832 -0.799 -0.987 0.864 -0.678 -0.587 -0.573 -0.354 0.674 0.8 -0.511 -0.433 0.77 0.805 -0.236 0.175 0.637 -0.676 0.935 Delaunay triangulation by the convex hull of 8 points in 4-d: Number of input sites: 8 Number of Delaunay regions: 12 Statistics for: | qhull s d Tcv Number of points processed: 8 Number of hyperplanes created: 29 Number of facets in hull: 18 Number of distance tests for qhull: 28 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below 1.4e-14 of all facets. Will make 96 distance computations. 8 vertices and 18 facets with normals: -0.24 0.52 -0.46 0.68 -0.91 -0.24 0.12 -0.31 -0.49 0.2 -0.02 -0.85 -0.27 0.19 -0.052 -0.94 0.063 -0.9 0.065 -0.43 0.028 -0.92 0.075 -0.39 -0.086 -0.048 0.99 -0.11 -0.033 0.0066 0.98 -0.18 0.13 0.076 0.69 -0.71 0.23 -0.066 0.78 -0.58 0.024 0.013 0.96 -0.26 0.099 0.71 -0.66 -0.24 0.46 0.12 -0.63 0.61 -0.12 0.5 -0.48 0.71 0.32 0.15 -0.57 0.74 -0.074 0.2 0.95 0.21 -0.039 0.091 0.99 0.068 -0.033 0.076 1 -0.0011 ======== Free memory allocated by the new instance of Qhull, and redisplay the old results. 8 vertices and 16 facets with normals: 0.44 -0.53 -0.014 0.72 0.34 -0.77 0.14 0.52 -0.071 -0.12 0.39 0.91 -0.2 -0.037 0.42 0.88 -0.31 -0.32 0.65 0.62 -0.38 -0.28 0.66 0.58 0.62 0.65 -0.45 0.03 0.31 0.76 -0.47 -0.32 0.17 0.3 -0.021 -0.94 0.03 0.36 -0.071 -0.93 -0.76 0.11 -0.041 -0.64 -0.55 -0.11 -0.29 -0.78 -0.43 0.24 -0.24 -0.84 -0.94 0.3 0.069 0.11 -0.36 -0.39 -0.78 -0.34 -0.13 0.6 -0.48 -0.63 ======== compute halfspace intersection about the origin for a diamond input as halfspace coefficients + offsets -1 -1 -1 -1 1 -1 -1 -1 -1 1 -1 -1 1 1 -1 -1 -1 -1 1 -1 1 -1 1 -1 -1 1 1 -1 1 1 1 -1 Halfspace intersection by the convex hull of 8 points in 3-d: Number of halfspaces: 8 Number of non-redundant halfspaces: 8 Number of intersection points: 6 Number of non-simplicial intersection points: 6 Statistics for: | qhull H0 s Tcv Fp Number of points processed: 8 Number of hyperplanes created: 11 Number of distance tests for qhull: 34 Number of distance tests for merging: 96 Number of distance tests for checking: 100 Number of merged facets: 6 CPU seconds to compute hull (after input): 0 3 6 0 0 -1 0 -1 0 1 0 0 -1 0 0 0 1 0 0 0 1 Output completed. Verifying that all points are below outer planes of all facets. Will make 48 distance computations. 8 vertices and 6 facets with normals: -0 -0 -1 0 -1 0 1 -0 -0 -1 -0 -0 0 1 -0 -0 -0 1 ============================== ========= user_eg2 =========== ============================== bin/user_eg2 ======== user_eg2 'cube qhull options' 'Delaunay options' 'halfspace options' This is the output from user_eg2_r.c. It shows how qhull() may be called from an application, via Qhull's static, reentrant library. user_eg2 is not part of Qhull itself. If user_eg2 fails immediately, user_eg2_r.c was incorrectly linked to Qhull's non-reentrant library, libqhullstatic. Try -- user_eg2 'T1' 'T1' 'T1' ======== compute triangulated convex hull of cube after rotating input Output completed. Verifying that all points are below outer planes of all facets. Will make 96 distance computations. 8 vertices and 12 facets with normals: -0 -0 -1 -0 -0 -1 0 -1 0 0 -1 0 1 -0 -0 1 -0 -0 -1 -0 -0 -1 -0 -0 0 1 -0 0 1 -0 -0 -0 1 -0 -0 1 add points in a diamond 9 vertices and 14 facets 10 vertices and 16 facets 11 vertices and 16 facets 12 vertices and 16 facets 13 vertices and 14 facets 14 vertices and 12 facets 14 vertices and 12 facets with normals: 0.71 -0.71 -0 -0.71 -0.71 0 -0.71 0.71 -0 0.71 0.71 -0 -0.71 -0 -0.71 -0 0.71 -0.71 0 -0.71 -0.71 0.71 0 -0.71 -0 -0.71 0.71 -0.71 0 0.71 0.71 0 0.71 -0 0.71 0.71 Convex hull of 14 points in 3-d: Number of vertices: 14 Number of facets: 12 Number of non-simplicial facets: 12 Statistics for: user_eg2 cube example | qhull s Tcv Q11 Number of points processed: 14 Number of hyperplanes created: 23 Number of distance tests for qhull: 64 Number of distance tests for merging: 276 Number of distance tests for checking: 324 Number of merged facets: 18 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 168 distance computations. ======== compute 2-d Delaunay triangulation seed: 1595644031 8 vertices and 12 facets with normals: -0.17 0.61 0.77 0.39 -0.56 0.73 0.19 -0.23 -0.95 0.4 0.75 -0.52 0.63 -0.77 0.026 0.21 -0.24 -0.95 -0.23 0.64 0.73 -0.44 0.78 0.45 -0.45 -0.16 -0.88 -0.57 -0.097 -0.82 -0.69 -0.58 -0.42 -0.83 -0.2 -0.53 Delaunay triangulation by the convex hull of 8 points in 3-d: Number of input sites: 8 Number of Delaunay regions: 7 Statistics for: user_eg2 Delaunay example | qhull s d Tcv Number of points processed: 8 Number of hyperplanes created: 18 Number of facets in hull: 12 Number of distance tests for qhull: 34 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below 3.8e-15 of all facets. Will make 56 distance computations. ======== add points to triangulation added point p8: -1 -0.7369 1.543 9 points, 0 extra points, 9 vertices, and 14 facets in total added point p9: 0.5112 -0.0827 0.2682 10 points, 0 extra points, 10 vertices, and 16 facets in total added point p10: 0.06553 -0.5621 0.3202 11 points, 0 extra points, 11 vertices, and 18 facets in total added point p11: -0.9059 0.3577 0.9486 12 points, 0 extra points, 12 vertices, and 20 facets in total added point p12: 0.3586 0.8694 0.8844 13 points, 0 extra points, 13 vertices, and 22 facets in total added point p13: -0.233 0.03883 0.0558 14 points, 0 extra points, 14 vertices, and 24 facets in total find Delaunay triangle or adjacent triangle closest to [0.5, 0.5, ...] 0.36 0.87 0.65 0.39 -0.02 0.60 Delaunay triangulation by the convex hull of 14 points in 3-d: Number of input sites: 14 Number of Delaunay regions: 20 Statistics for: user_eg2 Delaunay example | qhull s d Tcv Number of points processed: 14 Number of hyperplanes created: 53 Number of facets in hull: 24 Number of distance tests for qhull: 84 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below 3.8e-15 of all facets. Will make 280 distance computations. ======== compute halfspace intersection about the origin for a diamond Halfspace intersection by the convex hull of 8 points in 3-d: Number of halfspaces: 8 Number of non-redundant halfspaces: 8 Number of intersection points: 6 Number of non-simplicial intersection points: 6 Statistics for: user_eg2 halfspace example | qhull H0 s Tcv Number of points processed: 8 Number of hyperplanes created: 11 Number of distance tests for qhull: 34 Number of distance tests for merging: 96 Number of distance tests for checking: 100 Number of merged facets: 6 CPU seconds to compute hull (after input): 0.001 Output completed. Verifying that all points are below outer planes of all facets. Will make 48 distance computations. ======== add halfspaces for cube to intersection added offset -1 and normal 1.732 0 0 8 points, 1 extra points, 9 vertices, and 9 facets in total added offset -1 and normal -1.732 0 0 8 points, 2 extra points, 10 vertices, and 12 facets in total added offset -1 and normal 0 1.732 0 8 points, 3 extra points, 11 vertices, and 15 facets in total added offset -1 and normal 0 -1.732 0 8 points, 4 extra points, 12 vertices, and 18 facets in total added offset -1 and normal 0 0 1.732 8 points, 5 extra points, 13 vertices, and 21 facets in total added offset -1 and normal 0 0 -1.732 8 points, 6 extra points, 14 vertices, and 24 facets in total Halfspace intersection by the convex hull of 14 points in 3-d: Number of halfspaces: 14 Number of non-redundant halfspaces: 14 Number of intersection points: 24 Statistics for: user_eg2 halfspace example | qhull H0 s Tcv Number of points processed: 14 Number of hyperplanes created: 35 Number of distance tests for qhull: 58 Number of distance tests for merging: 248 Number of distance tests for checking: 256 Number of merged facets: 6 CPU seconds to compute hull (after input): 0.001 Output completed. Verifying that all points are below outer planes of all facets. Will make 192 distance computations. ============================== ========= user_eg3 =========== ============================== bin/user_eg3 ======== user_eg3 commands... -- demonstrate calling rbox and qhull from C++. user_eg3 is statically linked to qhullcpp and reentrant qhull. If user_eg3 fails immediately, it is probably linked to the non-reentrant qhull library. Commands: eg-100 Run the example in qh-code.htm eg-convex 'rbox d | qconvex o' with std::vector and C++ classes eg-delaunay 'rbox y c | qdelaunay o' with std::vector and C++ classes eg-voronoi 'rbox y c | qvoronoi o' with std::vector and C++ classes eg-fifo 'rbox y c | qvoronoi FN Fi Fo' with QhullUser and qh_fprintf Rbox and Qhull commands: rbox "200 D4" ... Generate points from rbox qhull "d p" ... Run qhull with options and produce output qhull-cout "o" ... Run qhull with options and produce output to cout qhull "T1" ... Run qhull with level-1 trace to cerr qhull-cout "T1z" ... Run qhull with level-1 trace to cout facets Print qhull's facets when done For example user_eg3 rbox qhull user_eg3 rbox qhull T1 user_eg3 rbox qhull d user_eg3 rbox D2 10 2 "s r 5" qhull "s p" facets user_eg3 eg-convex user_eg3 rbox 10 eg-delaunay qhull "d o" user_eg3 rbox D5 c P2 qhull d eg-delaunay user_eg3 rbox "D5 c P2" qhull v eg-voronoi o user_eg3 rbox D2 10 qhull "v" eg-fifo p Fi Fo bin/user_eg3 rbox "10 D2" "2 D2" qhull "s p" facets rbox 10 D2 rbox 2 D2 Results of s p Convex hull of 12 points in 2-d: Number of vertices: 5 Number of facets: 5 Statistics for: rbox "10 D2" "2 D2 D2" | qhull s p Number of points processed: 5 Number of hyperplanes created: 8 Number of distance tests for qhull: 56 CPU seconds to compute hull (after input): 0 2 5 -0.02222276248244826 -0.4979727817680433 -0.4285431913366012 0.4745826469497594 0.3790312361708201 0.3779794437605696 0.3443122672329771 -0.1437312230875075 -0.4999921736307369 -0.3684622117955817 Facets created by Qhull::runQhull() - f2 - flags: top simplicial - normal: -0.996428 0.0844484 - offset: -0.46709 - vertices: p1(v3) p10(v1) - neighboring facets: f4 f3 - f3 - flags: bottom simplicial - normal: 0.118775 0.992921 - offset: -0.420323 - vertices: p1(v3) p4(v2) - neighboring facets: f6 f2 - f4 - flags: bottom simplicial - normal: -0.261631 -0.965168 - offset: -0.486442 - vertices: p0(v4) p10(v1) - neighboring facets: f2 f7 - f6 - flags: top simplicial - normal: 0.997793 -0.0664014 - offset: -0.353096 - vertices: p8(v5) p4(v2) - neighboring facets: f3 f7 - f7 - flags: bottom simplicial - normal: 0.694945 -0.719063 - offset: -0.34263 - vertices: p8(v5) p0(v4) - neighboring facets: f4 f6 ================================================ == make testall, after running qtest and test == ================================================ == Fri, Jul 24, 2020 10:27:12 PM eg/q_eg eg/q_eg: Temporarily add "$PWD/bin" to $PATH for access to qconvex,etc. ============================== ========= eg/q_eg ============ == Create geomview examples == ============================== rbox c D3 | qconvex s G >eg/eg.01.cube Convex hull of 8 points in 3-d: Number of vertices: 8 Number of facets: 6 Number of non-simplicial facets: 6 Statistics for: rbox c D3 | qconvex s G Number of points processed: 8 Number of hyperplanes created: 11 Number of distance tests for qhull: 34 Number of distance tests for merging: 90 Number of distance tests for checking: 48 Number of merged facets: 6 CPU seconds to compute hull (after input): 0 rbox c d G2.0 | qconvex s G >eg/eg.02.diamond.cube Convex hull of 14 points in 3-d: Number of vertices: 6 Number of facets: 8 Statistics for: rbox c d G2.0 | qconvex s G Number of points processed: 6 Number of hyperplanes created: 11 Number of distance tests for qhull: 88 Number of distance tests for merging: 51 Number of distance tests for checking: 48 Number of merged facets: 1 CPU seconds to compute hull (after input): 0 rbox s 100 D3 | qconvex s G >eg/eg.03.sphere Convex hull of 100 points in 3-d: Number of vertices: 100 Number of facets: 196 Statistics for: rbox s 100 D3 | qconvex s G Number of points processed: 100 Number of hyperplanes created: 502 Number of distance tests for qhull: 1630 CPU seconds to compute hull (after input): 0 rbox s 100 D2 | qconvex s G >eg/eg.04.circle Convex hull of 100 points in 2-d: Number of vertices: 100 Number of facets: 100 Statistics for: rbox s 100 D2 | qconvex s G Number of points processed: 100 Number of hyperplanes created: 198 Number of distance tests for qhull: 890 CPU seconds to compute hull (after input): 0 rbox 10 l | qconvex s G >eg/eg.05.spiral Convex hull of 10 points in 3-d: Number of vertices: 10 Number of facets: 16 Statistics for: rbox 10 l | qconvex s G Number of points processed: 10 Number of hyperplanes created: 25 Number of distance tests for qhull: 39 CPU seconds to compute hull (after input): 0 rbox 1000 D2 | qconvex s C-0.03 Qc Gapcv >eg/eg.06.merge.square Convex hull of 1000 points in 2-d: Number of vertices: 4 Number of coplanar points: 103 Number of facets: 4 Statistics for: rbox 1000 D2 | qconvex s C-0.03 Qc Gapcv Number of points processed: 6 Number of hyperplanes created: 7 Number of distance tests for qhull: 11448 Number of distance tests for merging: 41 Number of distance tests for checking: 3540 Number of merged facets: 2 CPU seconds to compute hull (after input): 0 Maximum distance of point above facet: 0.019 (0.3x) Maximum distance of vertex below facet: -0.019 (0.3x) rbox 1000 D3 | qconvex s G >eg/eg.07.box Convex hull of 1000 points in 3-d: Number of vertices: 73 Number of facets: 142 Statistics for: rbox 1000 D3 | qconvex s G Number of points processed: 81 Number of hyperplanes created: 367 Number of distance tests for qhull: 12879 CPU seconds to compute hull (after input): 0.001 rbox c G0.4 s 500 | qconvex s G >eg/eg.08a.cube.sphere Convex hull of 508 points in 3-d: Number of vertices: 63 Number of facets: 122 Statistics for: rbox c G0.4 s 500 | qconvex s G Number of points processed: 99 Number of hyperplanes created: 443 Number of distance tests for qhull: 9651 CPU seconds to compute hull (after input): 0 rbox d G0.6 s 500 | qconvex s G >eg/eg.08b.diamond.sphere Convex hull of 506 points in 3-d: Number of vertices: 397 Number of facets: 790 Statistics for: rbox d G0.6 s 500 | qconvex s G Number of points processed: 407 Number of hyperplanes created: 2053 Number of distance tests for qhull: 9900 Number of distance tests for merging: 8243 Number of distance tests for checking: 4671 Number of merged facets: 1 CPU seconds to compute hull (after input): 0.002 rbox 100 L3 G0.5 s | qconvex s G >eg/eg.09.lens Convex hull of 100 points in 3-d: Number of vertices: 100 Number of facets: 196 Statistics for: rbox 100 L3 G0.5 s | qconvex s G Number of points processed: 100 Number of hyperplanes created: 483 Number of distance tests for qhull: 1641 CPU seconds to compute hull (after input): 0 rbox 100 s P0.5,0.5,0.5 | qconvex s Ga QG0 >eg/eg.10a.sphere.visible Convex hull of 100 points in 3-d: Number of vertices: 100 Number of facets: 196 Number of 'good' facets: 44 Statistics for: rbox 100 s P0.5,0.5,0.5 | qconvex s Ga QG0 Number of points processed: 100 Number of hyperplanes created: 512 Number of distance tests for qhull: 1703 CPU seconds to compute hull (after input): 0 rbox 100 s P0.5,0.5,0.5 | qconvex s Ga QG-0 >eg/eg.10b.sphere.beyond Convex hull of 100 points in 3-d: Number of vertices: 100 Number of facets: 196 Number of 'good' facets: 152 Statistics for: rbox 100 s P0.5,0.5,0.5 | qconvex s Ga QG-0 Number of points processed: 100 Number of hyperplanes created: 512 Number of distance tests for qhull: 1703 CPU seconds to compute hull (after input): 0 rbox 100 s P0.5,0.5,0.5 | qconvex s Ga QG0 PG >eg/eg.10c.sphere.horizon Convex hull of 100 points in 3-d: Number of vertices: 100 Number of facets: 196 Number of 'good' facets: 44 Statistics for: rbox 100 s P0.5,0.5,0.5 | qconvex s Ga QG0 PG Number of points processed: 100 Number of hyperplanes created: 512 Number of distance tests for qhull: 1703 CPU seconds to compute hull (after input): 0 rbox 100 s P0.5,0.5,0.5 | qconvex s Ga QV0 PgG >eg/eg.10d.sphere.cone Convex hull of 101 points in 3-d: Number of vertices: 85 Number of facets: 166 Number of 'good' facets: 14 Statistics for: rbox 100 s P0.5,0.5,0.5 | qconvex s Ga QV0 PgG Number of points processed: 88 Number of hyperplanes created: 429 Number of distance tests for qhull: 1586 CPU seconds to compute hull (after input): 0 rbox 100 s P0.5,0.5,0.5 | qconvex s Ga >eg/eg.10e.sphere.new Convex hull of 101 points in 3-d: Number of vertices: 85 Number of facets: 166 Statistics for: rbox 100 s P0.5,0.5,0.5 | qconvex s Ga Number of points processed: 88 Number of hyperplanes created: 429 Number of distance tests for qhull: 1586 CPU seconds to compute hull (after input): 0 rbox 100 s P0.5,0.5,0.5 | qhull s Ga QV0g Q0 >eg/eg.14.sphere.corner Convex hull of 101 points in 3-d: Number of vertices: 42 Number of facets: 80 Number of 'good' facets: 14 Statistics for: rbox 100 s P0.5,0.5,0.5 | qhull s Ga QV0g Q0 Number of points processed: 45 Number of hyperplanes created: 194 Number of distance tests for qhull: 1426 CPU seconds to compute hull (after input): 0 rbox 500 W0 | qconvex s QR0 Qc Gvp >eg/eg.15a.surface Convex hull of 500 points in 3-d: Number of vertices: 66 Number of coplanar points: 434 Number of facets: 80 Number of non-simplicial facets: 6 Statistics for: rbox 500 W0 | qconvex s QR0 Qc Gvp QR1595644033 Number of points processed: 73 Number of hyperplanes created: 223 Number of distance tests for qhull: 8533 Number of distance tests for merging: 2022 Number of distance tests for checking: 6699 Number of merged facets: 62 CPU seconds to compute hull (after input): 0.001 rbox 500 W0 | qconvex s QR0 Qt Qc Gvp >eg/eg.15b.triangle Convex hull of 500 points in 3-d: Number of vertices: 66 Number of coplanar points: 434 Number of facets: 128 Number of triangulated facets: 6 Statistics for: rbox 500 W0 | qconvex s QR0 Qt Qc Gvp QR1595644033 Number of points processed: 73 Number of hyperplanes created: 223 Number of distance tests for qhull: 8533 Number of distance tests for merging: 2022 Number of distance tests for checking: 6699 Number of merged facets: 62 CPU seconds to compute hull (after input): 0 rbox 500 W0 | qconvex s QR0 QJ5e-2 Qc Gvp >eg/eg.15c.joggle Convex hull of 500 points in 3-d: Number of vertices: 76 Number of coplanar points: 424 Number of facets: 148 Statistics for: rbox 500 W0 | qconvex s QR0 QJ5e-2 Qc Gvp QR1595644033 Number of points processed: 89 Number of hyperplanes created: 409 Number of distance tests for qhull: 18381 CPU seconds to compute hull (after input): 0 Input joggled by: 0.05 echo 2 = rbox 6 r s D2, rbox 15 B0.3 W0.25, c G0.5 >eg/eg.data.17 echo 25 >>eg/eg.data.17 rbox 15 D2 B0.3 W0.25 c G0.5 | tail -n +3 >>eg/eg.data.17 rbox 6 r s D2 B0.2 | tail -n +3 >>eg/eg.data.17 qdelaunay s Qt eg/eg.17a.delaunay.2 Delaunay triangulation by the convex hull of 25 points in 3-d: Number of input sites: 25 Number of Delaunay regions: 44 Number of triangulated facets: 1 Statistics for: = rbox 6 r s D2, rbox 15 B0.3 W0.25, c G0.5 | qdelaunay s Qt GnraD2 Number of points processed: 25 Number of hyperplanes created: 89 Number of facets in hull: 46 Number of distance tests for qhull: 287 Number of distance tests for merging: 487 Number of distance tests for checking: 282 Number of merged facets: 4 CPU seconds to compute hull (after input): 0 qdelaunay s eg/eg.17b.delaunay.2i Delaunay triangulation by the convex hull of 25 points in 3-d: Number of input sites: 25 Number of Delaunay regions: 41 Number of non-simplicial Delaunay regions: 1 Statistics for: = rbox 6 r s D2, rbox 15 B0.3 W0.25, c G0.5 | qdelaunay s GnraD2 Number of points processed: 25 Number of hyperplanes created: 89 Number of facets in hull: 42 Number of distance tests for qhull: 287 Number of distance tests for merging: 487 Number of distance tests for checking: 282 Number of merged facets: 4 CPU seconds to compute hull (after input): 0 qdelaunay s eg/eg.17c.delaunay.2-3 Delaunay triangulation by the convex hull of 25 points in 3-d: Number of input sites: 25 Number of Delaunay regions: 0 Number of non-simplicial Delaunay regions: 2 Statistics for: = rbox 6 r s D2, rbox 15 B0.3 W0.25, c G0.5 | qdelaunay s C-0 Ga Number of points processed: 25 Number of hyperplanes created: 89 Number of facets in hull: 42 Number of distance tests for qhull: 287 Number of distance tests for merging: 487 Number of distance tests for checking: 282 Number of merged facets: 4 CPU seconds to compute hull (after input): 0 qvoronoi s QJ eg/eg.17d.voronoi.2 Voronoi diagram by the convex hull of 25 points in 3-d: Number of Voronoi regions: 25 Number of Voronoi vertices: 44 Statistics for: = rbox 6 r s D2, rbox 15 B0.3 W0.25, c G0.5 | qvoronoi s QJ Gna Number of points processed: 25 Number of hyperplanes created: 110 Number of facets in hull: 46 Number of distance tests for qhull: 281 CPU seconds to compute hull (after input): 0.001 Input joggled by: 4.2e-11 qvoronoi s eg/eg.17e.voronoi.2i Voronoi diagram by the convex hull of 25 points in 3-d: Number of Voronoi regions: 25 Number of Voronoi vertices: 41 Number of non-simplicial Voronoi vertices: 1 Statistics for: = rbox 6 r s D2, rbox 15 B0.3 W0.25, c G0.5 | qvoronoi s Gna Number of points processed: 25 Number of hyperplanes created: 89 Number of facets in hull: 42 Number of distance tests for qhull: 287 Number of distance tests for merging: 487 Number of distance tests for checking: 282 Number of merged facets: 4 CPU seconds to compute hull (after input): 0 rbox c G0.1 d | qdelaunay Gt Qz >eg/eg.17f.delaunay.3 rbox 10 D2 d | qdelaunay s Qu G >eg/eg.18a.furthest.2-3 Furthest-site Delaunay triangulation by the convex hull of 14 points in 3-d: Number of input sites: 14 Number of Delaunay regions: 0 Statistics for: rbox 10 D2 d | qdelaunay s Qu G Number of points processed: 14 Number of hyperplanes created: 50 Number of facets in hull: 24 Number of distance tests for qhull: 96 Number of distance tests for merging: 229 Number of distance tests for checking: 138 Number of merged facets: 1 CPU seconds to compute hull (after input): 0 rbox 10 D2 d | qdelaunay s Qu Pd2 G >eg/eg.18b.furthest-up.2-3 Furthest-site Delaunay triangulation by the convex hull of 14 points in 3-d: Number of input sites: 14 Number of Delaunay regions: 7 Statistics for: rbox 10 D2 d | qdelaunay s Qu Pd2 G Number of points processed: 14 Number of hyperplanes created: 50 Number of facets in hull: 24 Number of distance tests for qhull: 96 Number of distance tests for merging: 229 Number of distance tests for checking: 138 Number of merged facets: 1 CPU seconds to compute hull (after input): 0 rbox 10 D2 d | qvoronoi s Qu Gv >eg/eg.18c.furthest.2 Furthest-site Voronoi vertices by the convex hull of 14 points in 3-d: Number of Voronoi regions: 14 Number of Voronoi vertices: 7 Statistics for: rbox 10 D2 d | qvoronoi s Qu Gv Number of points processed: 14 Number of hyperplanes created: 50 Number of facets in hull: 24 Number of distance tests for qhull: 96 Number of distance tests for merging: 229 Number of distance tests for checking: 138 Number of merged facets: 1 CPU seconds to compute hull (after input): 0 rbox 10 D3 | qvoronoi s FQ QV5 p | qconvex s G >eg/eg.19.voronoi.region.3 Voronoi diagram by the convex hull of 10 points in 4-d: Number of Voronoi regions: 10 Number of 'good' Voronoi vertices: 10 Statistics for: rbox 10 D3 | qvoronoi s FQ QV5 p Number of points processed: 10 Number of hyperplanes created: 43 Number of facets in hull: 27 Number of distance tests for qhull: 66 CPU seconds to compute hull (after input): 0 Convex hull of 10 points in 3-d: Number of vertices: 10 Number of facets: 9 Number of non-simplicial facets: 5 Statistics for: rbox 10 D3 | qvoronoi s FQ QV5 p | qconvex s G Number of points processed: 10 Number of hyperplanes created: 17 Number of distance tests for qhull: 44 Number of distance tests for merging: 135 Number of distance tests for checking: 79 Number of merged facets: 7 CPU seconds to compute hull (after input): 0 rbox r s 20 Z1 G0.2 | qconvex s QR1 G >eg/eg.20.cone Convex hull of 41 points in 3-d: Number of vertices: 41 Number of facets: 41 Number of non-simplicial facets: 21 Statistics for: rbox r s 20 Z1 G0.2 | qconvex s QR1 G QR1 Number of points processed: 41 Number of hyperplanes created: 117 Number of distance tests for qhull: 630 Number of distance tests for merging: 1607 Number of distance tests for checking: 680 Number of merged facets: 61 CPU seconds to compute hull (after input): 0 rbox 200 s | qconvex s Qc R0.014 Gpav >eg/eg.21b.roundoff.fixed Convex hull of 200 points in 3-d: Number of vertices: 65 Number of coplanar points: 135 Number of facets: 59 Number of non-simplicial facets: 41 Statistics for: rbox 200 s | qconvex s Qc R0.014 Gpav Number of points processed: 71 Number of hyperplanes created: 298 Number of distance tests for qhull: 11700 Number of distance tests for merging: 4151 Number of distance tests for checking: 5318 Number of merged facets: 153 CPU seconds to compute hull (after input): 0.001 Maximum distance of point above facet: 0.047 (0.8x) Maximum distance of vertex below facet: -0.075 (1.3x) rbox 1000 s| qconvex s C0.01 Qc Gcrp >eg/eg.22a.merge.sphere.01 Convex hull of 1000 points in 3-d: Number of vertices: 224 Number of coplanar points: 776 Number of facets: 119 Number of non-simplicial facets: 117 Statistics for: rbox 1000 s | qconvex s C0.01 Qc Gcrp Number of points processed: 1000 Number of hyperplanes created: 5544 Number of distance tests for qhull: 122395 Number of distance tests for merging: 77744 Number of distance tests for checking: 7926 Number of merged facets: 1877 CPU seconds to compute hull (after input): 0.009 Maximum distance of vertex below facet: -0.041 (1.4x) rbox 1000 s| qconvex s C-0.01 Qc Gcrp >eg/eg.22b.merge.sphere.-01 Convex hull of 1000 points in 3-d: Number of vertices: 103 Number of coplanar points: 897 Number of facets: 96 Number of non-simplicial facets: 77 Statistics for: rbox 1000 s | qconvex s C-0.01 Qc Gcrp Number of points processed: 105 Number of hyperplanes created: 447 Number of distance tests for qhull: 60561 Number of distance tests for merging: 6257 Number of distance tests for checking: 21333 Number of merged facets: 240 CPU seconds to compute hull (after input): 0.002 Maximum distance of point above facet: 0.025 (0.8x) Maximum distance of vertex below facet: -0.03 (1.0x) rbox 1000 s| qconvex s C0.05 Qc Gcrpv >eg/eg.22c.merge.sphere.05 Convex hull of 1000 points in 3-d: Number of vertices: 36 Number of coplanar points: 964 Number of facets: 20 Number of non-simplicial facets: 20 Statistics for: rbox 1000 s | qconvex s C0.05 Qc Gcrpv Number of points processed: 1000 Number of hyperplanes created: 5544 Number of distance tests for qhull: 50001 Number of distance tests for merging: 82257 Number of distance tests for checking: 7446 Number of merged facets: 1976 CPU seconds to compute hull (after input): 0.015 Maximum distance of vertex below facet: -0.21 (1.4x) rbox 1000 s| qconvex s C-0.05 Qc Gcrpv >eg/eg.22d.merge.sphere.-05 Convex hull of 1000 points in 3-d: Number of vertices: 18 Number of coplanar points: 982 Number of facets: 15 Number of non-simplicial facets: 13 Statistics for: rbox 1000 s | qconvex s C-0.05 Qc Gcrpv Number of points processed: 22 Number of hyperplanes created: 68 Number of distance tests for qhull: 41237 Number of distance tests for merging: 1029 Number of distance tests for checking: 12702 Number of merged facets: 41 CPU seconds to compute hull (after input): 0.002 Maximum distance of point above facet: 0.14 (0.9x) Maximum distance of vertex below facet: -0.15 (1.0x) rbox 1000 | qconvex s Gcprvah C0.1 Qc >eg/eg.23.merge.cube Convex hull of 1000 points in 3-d: Number of vertices: 8 Number of coplanar points: 743 Number of facets: 6 Number of non-simplicial facets: 6 Statistics for: rbox 1000 | qconvex s Gcprvah C0.1 Qc Number of points processed: 95 Number of hyperplanes created: 453 Number of distance tests for qhull: 59218 Number of distance tests for merging: 5460 Number of distance tests for checking: 6022 Number of merged facets: 146 CPU seconds to compute hull (after input): 0.002 Maximum distance of vertex below facet: -0.18 (0.6x) rbox 5000 D4 | qconvex s GD0v Pd0:0.5 C-0.02 C0.1 >eg/eg.24.merge.cube.4d-in-3d Convex hull of 5000 points in 4-d: Number of vertices: 16 Number of facets: 8 Number of 'good' facets: 1 Number of 'good' non-simplicial facets: 1 Statistics for: rbox 5000 D4 | qconvex s GD0v Pd0:0.5 C-0.02 C0.1 Number of points processed: 28 Number of hyperplanes created: 161 Number of distance tests for qhull: 606114 Number of distance tests for merging: 8562 Number of distance tests for checking: 40020 Number of merged facets: 159 CPU seconds to compute hull (after input): 0.012 Maximum distance of point above facet: 0.14 (0.4x) Maximum distance of vertex below facet: -0.28 (0.7x) rbox 5000 D4 | qconvex s s C-0.02 C0.1 Gh >eg/eg.30.4d.merge.cube Convex hull of 5000 points in 4-d: Number of vertices: 16 Number of facets: 8 Number of non-simplicial facets: 8 Statistics for: rbox 5000 D4 | qconvex s s C-0.02 C0.1 Gh Number of points processed: 28 Number of hyperplanes created: 161 Number of distance tests for qhull: 606114 Number of distance tests for merging: 8562 Number of distance tests for checking: 40020 Number of merged facets: 159 CPU seconds to compute hull (after input): 0.012 Maximum distance of point above facet: 0.14 (0.4x) Maximum distance of vertex below facet: -0.28 (0.7x) rbox 20 D3 | qdelaunay s G >eg/eg.31.4d.delaunay Delaunay triangulation by the convex hull of 20 points in 4-d: Number of input sites: 20 Number of Delaunay regions: 0 Statistics for: rbox 20 D3 | qdelaunay s G Number of points processed: 20 Number of hyperplanes created: 162 Number of facets in hull: 81 Number of distance tests for qhull: 303 CPU seconds to compute hull (after input): 0 rbox 30 s D4 | qconvex s G Pd0d1d2D3 >eg/eg.32.4d.octant Convex hull of 30 points in 4-d: Number of vertices: 30 Number of facets: 138 Number of 'good' facets: 9 Statistics for: rbox 30 s D4 | qconvex s G Pd0d1d2D3 Number of points processed: 30 Number of hyperplanes created: 340 Number of distance tests for qhull: 649 CPU seconds to compute hull (after input): 0 rbox 10 r s Z1 G0.3 | qconvex G >eg/eg.33a.cone rbox 10 r s Z1 G0.3 | qconvex FQ FV n | qhalf G >eg/eg.33b.cone.dual rbox 10 r s Z1 G0.3 | qconvex FQ FV n | qhalf FQ s Fp | qconvex G >eg/eg.33c.cone.halfspace Halfspace intersection by the convex hull of 21 points in 3-d: Number of halfspaces: 21 Number of non-redundant halfspaces: 21 Number of intersection points: 21 Number of non-simplicial intersection points: 11 Statistics for: rbox 10 r s Z1 G0.3 | qconvex FQ FV n | qhalf FQ s Fp Number of points processed: 21 Number of hyperplanes created: 49 Number of distance tests for qhull: 170 Number of distance tests for merging: 445 Number of distance tests for checking: 240 Number of merged facets: 17 CPU seconds to compute hull (after input): 0 echo ==the following should generate flipped and concave facets== >/dev/null rbox 200 s | qhull Q0 s R0.014 Gav Po >eg/eg.21a.roundoff.errors QH6136 qhull precision error: facet f577 is flipped, distance= 0.444437742328 QH6136 qhull precision error: facet f598 is flipped, distance= 0.397912421371 QH6115 qhull precision error: f136 is concave to f206, since p13(v33) is 0.04846 above f206 QH6115 qhull precision error: f175 is concave to f491, since p63(v41) is 0.02842 above f491 QH6115 qhull precision error: f188 is concave to f357, since p13(v33) is 0.05044 above f357 QH6115 qhull precision error: f192 is concave to f430, since p165(v44) is 0.01805 above f430 QH6115 qhull precision error: f206 is concave to f136, since p51(v47) is 0.007003 above f136 QH6115 qhull precision error: f231 is concave to f495, since p53(v5) is 0.01049 above f495 QH6115 qhull precision error: f264 is concave to f539, since p70(v31) is 0.02908 above f539 QH6115 qhull precision error: f275 is concave to f442, since p176(v60) is 0.03539 above f442 QH6115 qhull precision error: f276 is concave to f256, since p131(v61) is 0.01036 above f256 QH6115 qhull precision error: f294 is concave to f465, since p13(v33) is 0.009524 above f465 QH6115 qhull precision error: f307 is concave to f485, since p99(v67) is 0.0106 above f485 QH6115 qhull precision error: f311 is concave to f476, since p87(v16) is 0.03213 above f476 QH6115 qhull precision error: f345 is concave to f344, since p13(v33) is 0.01277 above f344 QH6115 qhull precision error: f357 is concave to f188, since p23(v76) is 0.008612 above f188 QH6115 qhull precision error: f381 is concave to f512, since p161(v13) is 0.05502 above f512 QH6115 qhull precision error: f386 is concave to f532, since p152(v82) is 0.01786 above f532 QH6115 qhull precision error: f436 is concave to f461, since p173(v92) is 0.007229 above f461 QH6115 qhull precision error: f436 is concave to f591, since p109(v11) is 0.04018 above f591 QH6115 qhull precision error: f488 is concave to f487, since p180(v32) is 0.01013 above f487 QH6115 qhull precision error: f539 is concave to f264, since p90(v113) is 0.01548 above f264 QH6115 qhull precision error: f549 is concave to f592, since p81(v95) is 0.0117 above f592 QH6115 qhull precision error: f562 is concave to f460, since p21(v117) is 0.007454 above f460 QH6115 qhull precision error: f563 is concave to f595, since p91(v49) is 0.03273 above f595 QH6115 qhull precision error: f569 is concave to f329, since p62(v119) is 0.007692 above f329 QH6113 qhull precision error: f577 is flipped (interior point is outside) QH6113 qhull precision error: f598 is flipped (interior point is outside) QH6115 qhull precision error: f603 is concave to f605, since p79(v52) is 0.01194 above f605 Convex hull of 200 points in 3-d: Number of vertices: 128 Number of facets: 252 Statistics for: rbox 200 s | qhull Q0 s R0.014 Gav Po Number of points processed: 128 Number of hyperplanes created: 610 Number of distance tests for qhull: 4539 CPU seconds to compute hull (after input): 0 precision problems (corrected unless 'Q0' or an error) 101 coplanar half ridges in output 25 concave half ridges in output 2 flipped facets 112 coplanar horizon facets for new vertices 72 coplanar points during partitioning echo ==the preceding should report flipped and concave facets== >/dev/null echo END eg/q_eg >/dev/null eg/q_egtest eg/q_egtest: Temporarily add "$PWD/bin" to $PATH for access to qconvex,etc. ============================== ========= eg/q_egtest ======== == Create geomview tests ===== ============================== rbox d D3 | qconvex s Gnrv Tc Tv >eg/eg.t01.spheres.3 Convex hull of 6 points in 3-d: Number of vertices: 6 Number of facets: 8 Statistics for: rbox d D3 | qconvex s Gnrv Tc Tv Number of points processed: 6 Number of hyperplanes created: 11 Number of distance tests for qhull: 10 Number of distance tests for merging: 59 Number of distance tests for checking: 54 Number of merged facets: 1 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 48 distance computations. rbox d D2 | qconvex s Gnv Tc Tv >eg/eg.t02.spheres.2 Convex hull of 4 points in 2-d: Number of vertices: 4 Number of facets: 4 Statistics for: rbox d D2 | qconvex s Gnv Tc Tv Number of points processed: 4 Number of hyperplanes created: 5 Number of distance tests for qhull: 3 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below 1.3e-15 of all facets. Will make 16 distance computations. rbox d D3 | qconvex s Gnrp Tc Tv >eg/eg.t03.points.3 Convex hull of 6 points in 3-d: Number of vertices: 6 Number of facets: 8 Statistics for: rbox d D3 | qconvex s Gnrp Tc Tv Number of points processed: 6 Number of hyperplanes created: 11 Number of distance tests for qhull: 10 Number of distance tests for merging: 59 Number of distance tests for checking: 54 Number of merged facets: 1 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 48 distance computations. rbox d D2 | qconvex s Gnp Tc Tv >eg/eg.t04.points.2 Convex hull of 4 points in 2-d: Number of vertices: 4 Number of facets: 4 Statistics for: rbox d D2 | qconvex s Gnp Tc Tv Number of points processed: 4 Number of hyperplanes created: 5 Number of distance tests for qhull: 3 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below 1.3e-15 of all facets. Will make 16 distance computations. rbox c D4 | qconvex s C0.05 GnpcD3 Pd3:0.5 Tc Tv >eg/eg.t05.centrum.points.4-3 Convex hull of 16 points in 4-d: Number of vertices: 16 Number of facets: 8 Number of 'good' facets: 1 Number of 'good' non-simplicial facets: 1 Statistics for: rbox c D4 | qconvex s C0.05 GnpcD3 Pd3:0.5 Tc Tv Number of points processed: 16 Number of hyperplanes created: 25 Number of distance tests for qhull: 167 Number of distance tests for merging: 565 Number of distance tests for checking: 532 Number of merged facets: 36 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 16 distance computations. rbox d D3 | qconvex s Gnrc Tc Tv >eg/eg.t06.centrums.3.precise Convex hull of 6 points in 3-d: Number of vertices: 6 Number of facets: 8 Statistics for: rbox d D3 | qconvex s Gnrc Tc Tv Number of points processed: 6 Number of hyperplanes created: 11 Number of distance tests for qhull: 10 Number of distance tests for merging: 59 Number of distance tests for checking: 54 Number of merged facets: 1 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 48 distance computations. rbox d D3 | qconvex s C0.05 Gnrc Tc Tv >eg/eg.t07.centrums.3 Convex hull of 6 points in 3-d: Number of vertices: 6 Number of facets: 8 Statistics for: rbox d D3 | qconvex s C0.05 Gnrc Tc Tv Number of points processed: 6 Number of hyperplanes created: 11 Number of distance tests for qhull: 10 Number of distance tests for merging: 93 Number of distance tests for checking: 130 Number of merged facets: 1 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 48 distance computations. rbox d D2 | qconvex s C0.05 Gc Tc Tv >eg/eg.t08.centrums.2 Convex hull of 4 points in 2-d: Number of vertices: 4 Number of facets: 4 Statistics for: rbox d D2 | qconvex s C0.05 Gc Tc Tv Number of points processed: 4 Number of hyperplanes created: 5 Number of distance tests for qhull: 3 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 16 distance computations. rbox d D3 | qconvex s Gnha Tc Tv >eg/eg.t09.intersect.3 Convex hull of 6 points in 3-d: Number of vertices: 6 Number of facets: 8 Statistics for: rbox d D3 | qconvex s Gnha Tc Tv Number of points processed: 6 Number of hyperplanes created: 11 Number of distance tests for qhull: 10 Number of distance tests for merging: 59 Number of distance tests for checking: 54 Number of merged facets: 1 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 48 distance computations. rbox d D3 | qconvex s GaD0 Pd0 Tc Tv >eg/eg.t10.faces.3-2 Convex hull of 6 points in 3-d: Number of vertices: 6 Number of facets: 8 Number of 'good' facets: 4 Statistics for: rbox d D3 | qconvex s GaD0 Pd0 Tc Tv Number of points processed: 6 Number of hyperplanes created: 11 Number of distance tests for qhull: 10 Number of distance tests for merging: 59 Number of distance tests for checking: 54 Number of merged facets: 1 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 24 distance computations. rbox d D3 | qconvex s GnrpD0 Pd0 Tc Tv >eg/eg.t11.points.3-2 Convex hull of 6 points in 3-d: Number of vertices: 6 Number of facets: 8 Number of 'good' facets: 4 Statistics for: rbox d D3 | qconvex s GnrpD0 Pd0 Tc Tv Number of points processed: 6 Number of hyperplanes created: 11 Number of distance tests for qhull: 10 Number of distance tests for merging: 59 Number of distance tests for checking: 54 Number of merged facets: 1 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 24 distance computations. rbox d D3 | qconvex s C0.05 GnrcD0 Pd0 Tc Tv >eg/eg.t12.centrums.3-2 Convex hull of 6 points in 3-d: Number of vertices: 6 Number of facets: 8 Number of 'good' facets: 4 Statistics for: rbox d D3 | qconvex s C0.05 GnrcD0 Pd0 Tc Tv Number of points processed: 6 Number of hyperplanes created: 11 Number of distance tests for qhull: 10 Number of distance tests for merging: 93 Number of distance tests for checking: 130 Number of merged facets: 1 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 24 distance computations. rbox d D3 | qconvex s GnhaD0 Pd0 Tc Tv >eg/eg.t13.intersect.3-2 Convex hull of 6 points in 3-d: Number of vertices: 6 Number of facets: 8 Number of 'good' facets: 4 Statistics for: rbox d D3 | qconvex s GnhaD0 Pd0 Tc Tv Number of points processed: 6 Number of hyperplanes created: 11 Number of distance tests for qhull: 10 Number of distance tests for merging: 59 Number of distance tests for checking: 54 Number of merged facets: 1 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 24 distance computations. rbox d D3 | qconvex s GnrvD0 Pd0 Tc Tv >eg/eg.t14.spheres.3-2 Convex hull of 6 points in 3-d: Number of vertices: 6 Number of facets: 8 Number of 'good' facets: 4 Statistics for: rbox d D3 | qconvex s GnrvD0 Pd0 Tc Tv Number of points processed: 6 Number of hyperplanes created: 11 Number of distance tests for qhull: 10 Number of distance tests for merging: 59 Number of distance tests for checking: 54 Number of merged facets: 1 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 24 distance computations. rbox c D4 | qconvex s GvD0 Pd0:0.5 Tc Tv >eg/eg.t15.spheres.4-3 Convex hull of 16 points in 4-d: Number of vertices: 16 Number of facets: 8 Number of 'good' facets: 1 Number of 'good' non-simplicial facets: 1 Statistics for: rbox c D4 | qconvex s GvD0 Pd0:0.5 Tc Tv Number of points processed: 16 Number of hyperplanes created: 25 Number of distance tests for qhull: 167 Number of distance tests for merging: 510 Number of distance tests for checking: 412 Number of merged facets: 36 CPU seconds to compute hull (after input): 0.001 Output completed. Verifying that all points are below outer planes of all facets. Will make 16 distance computations. rbox c D4 | qhull s Q0 C0 GpD0 Pd0:0.5 Tc Tv >eg/eg.t16.points.4-3 Convex hull of 16 points in 4-d: Number of vertices: 16 Number of facets: 8 Number of 'good' facets: 1 Number of 'good' non-simplicial facets: 1 Statistics for: rbox c D4 | qhull s Q0 C0 GpD0 Pd0:0.5 Tc Tv Number of points processed: 16 Number of hyperplanes created: 61 Number of distance tests for qhull: 162 Number of distance tests for merging: 1272 Number of distance tests for checking: 244 Number of merged facets: 36 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 16 distance computations. rbox c D4 | qconvex s GahD0 Pd0:0.5 Tc Tv >eg/eg.t17.intersect.4-3 Convex hull of 16 points in 4-d: Number of vertices: 16 Number of facets: 8 Number of 'good' facets: 1 Number of 'good' non-simplicial facets: 1 Statistics for: rbox c D4 | qconvex s GahD0 Pd0:0.5 Tc Tv Number of points processed: 16 Number of hyperplanes created: 25 Number of distance tests for qhull: 167 Number of distance tests for merging: 510 Number of distance tests for checking: 412 Number of merged facets: 36 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 16 distance computations. rbox 100 s | qconvex s C-0.05 Qc Gicvprh Tc Tv >eg/eg.t18.imprecise.3 Convex hull of 100 points in 3-d: Number of vertices: 18 Number of coplanar points: 82 Number of facets: 16 Number of non-simplicial facets: 12 Statistics for: rbox 100 s | qconvex s C-0.05 Qc Gicvprh Tc Tv Number of points processed: 18 Number of hyperplanes created: 60 Number of distance tests for qhull: 3110 Number of distance tests for merging: 784 Number of distance tests for checking: 1502 Number of merged facets: 29 CPU seconds to compute hull (after input): 0.001 Maximum distance of point above facet: 0.092 (0.6x) Maximum distance of vertex below facet: -0.14 (0.9x) Output completed. Verifying that all points are below outer planes of all facets. Will make 1600 distance computations. rbox 30 s D4 | qconvex s GhD0 Pd0d1d2D3 Tc >eg/eg.t19.intersect.precise.4-3 Convex hull of 30 points in 4-d: Number of vertices: 30 Number of facets: 138 Number of 'good' facets: 9 Statistics for: rbox 30 s D4 | qconvex s GhD0 Pd0d1d2D3 Tc Number of points processed: 30 Number of hyperplanes created: 340 Number of distance tests for qhull: 649 CPU seconds to compute hull (after input): 0 rbox 100 s P1,1,1 | qconvex s QG-0 Pgp Tc G >eg/eg.t20.notvisible Convex hull of 100 points in 3-d: Number of vertices: 100 Number of facets: 196 Number of 'good' facets: 125 Statistics for: rbox 100 s P1,1,1 | qconvex s QG-0 Pgp Tc G Number of points processed: 100 Number of hyperplanes created: 502 Number of distance tests for qhull: 1630 CPU seconds to compute hull (after input): 0.001 rbox 100 s | qconvex s QV-10 Pgp Tc G >eg/eg.t21.notvertex Convex hull of 100 points in 3-d: Number of vertices: 100 Number of facets: 196 Number of 'good' facets: 191 Statistics for: rbox 100 s | qconvex s QV-10 Pgp Tc G Number of points processed: 100 Number of hyperplanes created: 494 Number of distance tests for qhull: 1640 CPU seconds to compute hull (after input): 0.002 rbox 100 r D2 P1,1 | qhull s Pd0:0.7 PD0:0.8 QgG0 G Tv >eg/eg.t22.split Convex hull of 100 points in 2-d: Number of vertices: 42 Number of facets: 42 Number of 'good' facets: 3 Statistics for: rbox 100 r D2 P1,1 | qhull s Pd0:0.7 PD0:0.8 QgG0 G Tv Number of points processed: 42 Number of hyperplanes created: 176 Number of distance tests for qhull: 1099 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below 2.6e-15 of all good facets. Will make 303 distance computations. rbox 100 D2 c G1.0 | qvoronoi s A-0.95 Gna Tv >eg/eg.t23.voronoi.imprecise Voronoi diagram by the convex hull of 104 points in 3-d: Number of Voronoi regions: 16 Total number of nearly incident points: 88 Number of Voronoi vertices: 11 Number of non-simplicial Voronoi vertices: 8 Statistics for: rbox 100 D2 c G1.0 | qvoronoi s A-0.95 Gna Tv Number of points processed: 16 Number of hyperplanes created: 48 Number of facets in hull: 12 Number of distance tests for qhull: 2378 Number of distance tests for merging: 614 Number of distance tests for checking: 920 Number of merged facets: 23 CPU seconds to compute hull (after input): 0 Maximum distance of point above facet: 0.046 Maximum distance of vertex below facet: -0.1 (0.1x) Output completed. Verifying that all points are below outer planes of all facets. Will make 1144 distance computations. rbox 30 s D4 | qconvex s Gh Pd0d1d2D3 Tc >eg/eg.t24.intersect.precise.4d Convex hull of 30 points in 4-d: Number of vertices: 30 Number of facets: 138 Number of 'good' facets: 9 Statistics for: rbox 30 s D4 | qconvex s Gh Pd0d1d2D3 Tc Number of points processed: 30 Number of hyperplanes created: 340 Number of distance tests for qhull: 649 CPU seconds to compute hull (after input): 0 echo ==the following generates an error== >/dev/null rbox 1000 D4 | qhull Q0 s Po R0.005 Ga Tc Tv >eg/eg.t25.neighbors.4d QH6107 qhull topology error: facets f394, f412 and f396 meet at a ridge with more than 2 neighbors. Can not continue due to no qh.PREmerge and no 'Qx' (MERGEexact) ERRONEOUS FACET: - f394 - flags: bottom simplicial newfacet - offset: 0 - vertices: p938(v40) p381(v18) p241(v7) p327(v3) - neighboring facets: f121 f396 f398 f395 ERRONEOUS OTHER FACET: - f412 - flags: bottom simplicial newfacet - offset: 0 - vertices: p938(v40) p241(v7) p837(v6) p327(v3) - neighboring facets: f121 f398 ERRONEOUS and NEIGHBORING FACETS to output While executing: rbox 1000 D4 | qhull Q0 s Po R0.005 Ga Tc Tv Options selected for Qhull 2020.2.r 2020/07/24: run-id 213546123 Q0-no-premerge summary Poutput-forced Random-perturb 0.005 Gall-points Tcheck-frequently Tverify _max-width 1 Error-roundoff 0.0025 Visible-distance 0.0025 U-max-coplanar 0.0025 Width-outside 0.005 _wide-facet 0.015 _maxoutside 0.025 Last point added to hull was p938. Convex hull of 1000 points in 4-d: Number of vertices: 38 Number of facets: 180 Statistics for: rbox 1000 D4 | qhull Q0 s Po R0.005 Ga Tc Tv Number of points processed: 39 Number of hyperplanes created: 394 Number of distance tests for qhull: 21752 precision problems (corrected unless 'Q0' or an error) 1 flipped facets 13 coplanar horizon facets for new vertices 103 coplanar points during partitioning 4 degenerate hyperplanes recomputed with gaussian elimination Precision problems were detected during construction of the convex hull. This occurs because convex hull algorithms assume that calculations are exact, but floating-point arithmetic has roundoff errors. To correct for precision problems, do not use 'Q0'. By default, Qhull selects 'C-0' or 'Qx' and merges non-convex facets. With option 'QJ', Qhull joggles the input to prevent precision problems. See "Imprecision in Qhull" (qh-impre.htm). If you use 'Q0', the output may include coplanar ridges, concave ridges, and flipped facets. In 4-d and higher, Qhull may produce a ridge with four neighbors or two facets with the same vertices. Qhull reports these events when they occur. It stops when a concave ridge, flipped facet, or duplicate facet occurs. If you need triangular output: - use option 'Qt' to triangulate the output - use option 'QJ' to joggle the input points and remove precision errors - use option 'Ft'. It triangulates non-simplicial facets with added points. If you must use 'Q0', try one or more of the following options. They can not guarantee an output. - use 'QbB' to scale the input to a cube. - use 'Po' to produce output and prevent partitioning for flipped facets - use 'V0' to set min. distance to visible facet as 0 instead of roundoff - use 'En' to specify a maximum roundoff error less than 0.0025. - options 'Qf', 'Qbb', and 'QR0' may also help To guarantee simplicial output: - use option 'Qt' to triangulate the output - use option 'QJ' to joggle the input points and remove precision errors - use option 'Ft' to triangulate the output by adding points - use exact arithmetic (see "Imprecision in Qhull", qh-impre.htm) echo ==the previous should generate an error== >/dev/null echo END eg/q_egtest >/dev/null bash -c eg/q_test eg/q_test: Temporarily add "$PWD/bin" to $PATH for access to qconvex,etc. Convex hull of 8 points in 3-d: Number of vertices: 8 Number of facets: 6 Number of non-simplicial facets: 6 Statistics for: | qhull s Tcv Number of points processed: 8 Number of hyperplanes created: 11 Number of distance tests for qhull: 34 Number of distance tests for merging: 96 Number of distance tests for checking: 100 Number of merged facets: 6 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 48 distance computations. Delaunay triangulation by the convex hull of 8 points in 4-d: Number of input sites: 8 Number of Delaunay regions: 10 Statistics for: | qhull s d Tcv Number of points processed: 8 Number of hyperplanes created: 28 Number of facets in hull: 18 Number of distance tests for qhull: 28 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below 1e-14 of all facets. Will make 80 distance computations. Delaunay triangulation by the convex hull of 8 points in 4-d: Number of input sites: 8 Number of Delaunay regions: 10 Statistics for: | qhull s d Tcv Number of points processed: 8 Number of hyperplanes created: 26 Number of facets in hull: 17 Number of distance tests for qhull: 28 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below 1e-14 of all facets. Will make 80 distance computations. Halfspace intersection by the convex hull of 8 points in 3-d: Number of halfspaces: 8 Number of non-redundant halfspaces: 8 Number of intersection points: 6 Number of non-simplicial intersection points: 6 Statistics for: | qhull H0 s Tcv Fp Number of points processed: 8 Number of hyperplanes created: 11 Number of distance tests for qhull: 34 Number of distance tests for merging: 96 Number of distance tests for checking: 100 Number of merged facets: 6 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 48 distance computations. ============================== ========= eg/q_test ========== == Check qhull programs ====== ============================== qhull => qhull_r 8.0.1 (2020.2.r 2020/07/24) qconvex => qhull 8.0.1 (2020.2 2020/07/24) qvoronoi => qhull 8.0.1 (2020.2 2020/07/24) qdelaunay => qhull 8.0.1 (2020.2 2020/07/24) qhalf => qhull 8.0.1 (2020.2 2020/07/24) -rwxr-xr-x 1 bbarber 197121 344064 Jul 24 21:06 /d/bash/local/qhull/bin/qconvex -rwxr-xr-x 1 bbarber 197121 344576 Jul 24 21:06 /d/bash/local/qhull/bin/qdelaunay -rwxr-xr-x 1 bbarber 197121 344576 Jul 24 21:06 /d/bash/local/qhull/bin/qhalf -rwxr-xr-x 1 bbarber 197121 339968 Jul 24 21:06 /d/bash/local/qhull/bin/qhull -rwxr-xr-x 1 bbarber 197121 343552 Jul 24 21:06 /d/bash/local/qhull/bin/qvoronoi -rwxr-xr-x 1 bbarber 197121 13312 Jul 24 21:06 /d/bash/local/qhull/bin/user_eg -rwxr-xr-x 1 bbarber 197121 320000 Jul 24 21:06 /d/bash/local/qhull/bin/user_eg2 -rwxr-xr-x 1 bbarber 197121 468480 Jul 24 21:06 /d/bash/local/qhull/bin/user_eg3 ============================== == check user_eg, user_eg2, and user_eg3 == errors if user_eg and user_eg2 not found ============================== user_eg ======== user_eg 'cube qhull options' 'Delaunay options' 'halfspace options' This is the output from user_eg_r.c. It shows how qhull() may be called from an application, via Qhull's shared, reentrant library. user_eg is not part of Qhull itself. If user_eg fails immediately, user_eg_r.c was incorrectly linked to Qhull's non-reentrant library, libqhull. Try -- user_eg 'T1' 'T1' 'T1' ======== compute convex hull of cube after rotating input input -1 -1 -1 1 -1 -1 -1 1 -1 1 1 -1 -1 -1 1 1 -1 1 -1 1 1 1 1 1 Convex hull of 8 points in 3-d: Number of vertices: 8 Number of facets: 6 Number of non-simplicial facets: 6 Statistics for: | qhull s Tcv Number of points processed: 8 Number of hyperplanes created: 11 Number of distance tests for qhull: 34 Number of distance tests for merging: 96 Number of distance tests for checking: 100 Number of merged facets: 6 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 48 distance computations. 8 vertices and 6 facets with normals: -0 -0 -1 0 -1 0 1 -0 -0 -1 -0 -0 0 1 -0 -0 -0 1 ======== compute 3-d Delaunay triangulation seed: 1595644037 input -0.801 -0.418 0.372 -0.854 -0.0286 -0.978 -0.329 -0.199 -0.343 0.668 -0.752 0.621 -0.0443 -0.981 -0.666 0.786 0.278 0.847 0.639 0.432 0.349 -0.495 -0.786 0.239 Delaunay triangulation by the convex hull of 8 points in 4-d: Number of input sites: 8 Number of Delaunay regions: 10 Statistics for: | qhull s d Tcv Number of points processed: 8 Number of hyperplanes created: 28 Number of facets in hull: 18 Number of distance tests for qhull: 28 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below 1e-14 of all facets. Will make 80 distance computations. 8 vertices and 18 facets with normals: 0.67 0.27 -0.6 0.35 0.51 0.23 -0.8 -0.2 -0.47 0.83 0.3 0.072 -0.52 0.81 0.13 -0.23 0.86 0.0043 -0.48 0.16 0.71 -0.35 -0.33 -0.51 0.38 -0.011 -0.2 0.9 -0.34 -0.07 0.44 0.83 -0.38 -0.45 0.29 0.75 0.011 -0.16 0.78 -0.6 0.27 -0.76 -0.02 -0.59 -0.38 -0.49 0.3 0.72 -0.64 -0.57 -0.38 -0.34 -0.51 -0.56 0.2 0.62 -0.75 -0.48 -0.3 -0.35 -0.0085 -0.17 0.65 -0.74 0.12 -0.29 0.58 -0.75 0.021 -0.19 0.75 -0.64 find 3-d Delaunay triangle or adjacent triangle closest to [0.5, 0.5, ...] -0.80 -0.42 0.37 -0.33 -0.20 -0.34 0.64 0.43 0.35 -0.85 -0.03 -0.98 ======== Compute a new triangulation as a separate instance of Qhull seed: 1595644038 input -0.801 -0.155 -0.117 0.0631 -0.963 -0.541 -0.235 -0.841 -0.984 0.538 0.0146 -0.34 -0.382 -0.912 -0.559 -0.155 -0.38 0.862 -0.594 0.566 -0.816 0.878 0.392 0.1 Delaunay triangulation by the convex hull of 8 points in 4-d: Number of input sites: 8 Number of Delaunay regions: 10 Statistics for: | qhull s d Tcv Number of points processed: 8 Number of hyperplanes created: 26 Number of facets in hull: 17 Number of distance tests for qhull: 28 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below 1e-14 of all facets. Will make 80 distance computations. 8 vertices and 17 facets with normals: -0.27 0.8 0.44 -0.33 -0.15 0.61 0.4 -0.67 -0.064 -0.63 0.081 -0.77 0.68 -0.61 0.3 -0.26 -0.19 0.77 0.19 -0.58 -0.72 -0.05 0.32 0.62 -0.23 -0.13 -0.76 -0.59 0.51 -0.33 0.37 0.7 0.063 0.23 0.34 0.91 0.82 -0.23 -0.53 0.074 0.55 0.27 -0.78 0.11 -0.19 -0.71 0.12 -0.67 -0.74 -0.13 0.32 0.58 -0.024 -0.74 0.42 0.53 -0.16 -0.5 -0.37 -0.77 -0.22 -0.18 -0.74 -0.61 -0.097 -0.32 -0.72 -0.61 ======== Free memory allocated by the new instance of Qhull, and redisplay the old results. 8 vertices and 18 facets with normals: 0.67 0.27 -0.6 0.35 0.51 0.23 -0.8 -0.2 -0.47 0.83 0.3 0.072 -0.52 0.81 0.13 -0.23 0.86 0.0043 -0.48 0.16 0.71 -0.35 -0.33 -0.51 0.38 -0.011 -0.2 0.9 -0.34 -0.07 0.44 0.83 -0.38 -0.45 0.29 0.75 0.011 -0.16 0.78 -0.6 0.27 -0.76 -0.02 -0.59 -0.38 -0.49 0.3 0.72 -0.64 -0.57 -0.38 -0.34 -0.51 -0.56 0.2 0.62 -0.75 -0.48 -0.3 -0.35 -0.0085 -0.17 0.65 -0.74 0.12 -0.29 0.58 -0.75 0.021 -0.19 0.75 -0.64 ======== compute halfspace intersection about the origin for a diamond input as halfspace coefficients + offsets -1 -1 -1 -1 1 -1 -1 -1 -1 1 -1 -1 1 1 -1 -1 -1 -1 1 -1 1 -1 1 -1 -1 1 1 -1 1 1 1 -1 Halfspace intersection by the convex hull of 8 points in 3-d: Number of halfspaces: 8 Number of non-redundant halfspaces: 8 Number of intersection points: 6 Number of non-simplicial intersection points: 6 Statistics for: | qhull H0 s Tcv Fp Number of points processed: 8 Number of hyperplanes created: 11 Number of distance tests for qhull: 34 Number of distance tests for merging: 96 Number of distance tests for checking: 100 Number of merged facets: 6 CPU seconds to compute hull (after input): 0 3 6 0 0 -1 0 -1 0 1 0 0 -1 0 0 0 1 0 0 0 1 Output completed. Verifying that all points are below outer planes of all facets. Will make 48 distance computations. 8 vertices and 6 facets with normals: -0 -0 -1 0 -1 0 1 -0 -0 -1 -0 -0 0 1 -0 -0 -0 1 user_eg 'QR1 p n Qt' 'v p' 'Fp' ======== user_eg 'cube qhull options' 'Delaunay options' 'halfspace options' This is the output from user_eg_r.c. It shows how qhull() may be called from an application, via Qhull's shared, reentrant library. user_eg is not part of Qhull itself. If user_eg fails immediately, user_eg_r.c was incorrectly linked to Qhull's non-reentrant library, libqhull. Try -- user_eg 'T1' 'T1' 'T1' ======== compute convex hull of cube after rotating input input -1 -1 -1 1 -1 -1 -1 1 -1 1 1 -1 -1 -1 1 1 -1 1 -1 1 1 1 1 1 Convex hull of 8 points in 3-d: Number of vertices: 8 Number of facets: 12 Number of triangulated facets: 6 Statistics for: | qhull s Tcv QR1 p n Qt QR1 Number of points processed: 8 Number of hyperplanes created: 12 Number of distance tests for qhull: 22 Number of distance tests for merging: 100 Number of distance tests for checking: 100 Number of merged facets: 6 CPU seconds to compute hull (after input): 0 3 8 0.9124763375291641 1.390833937612012 -0.4826674750136243 -0.5764091147442416 0.565375258822974 -1.532352227508615 -0.1847368907548403 1.250953879569599 1.183632828365285 -1.673622343028246 0.4254952007805605 0.1339480758702939 1.673622343028246 -0.4254952007805605 -0.1339480758702939 0.1847368907548403 -1.250953879569599 -1.183632828365285 0.5764091147442416 -0.565375258822974 1.532352227508615 -0.9124763375291641 -1.390833937612012 0.4826674750136243 4 12 -0.744442726136703 -0.4127293393945193 -0.5248423762474955 -1 -0.744442726136703 -0.4127293393945193 -0.5248423762474955 -1 0.380573002749541 -0.9081645691962865 0.1743596995716653 -1 0.380573002749541 -0.9081645691962865 0.1743596995716653 -1 -0.5486066141420022 -0.06994002902120684 0.8331501516894545 -1 -0.5486066141420022 -0.06994002902120684 0.8331501516894545 -1 0.5486066141420022 0.06994002902120672 -0.8331501516894545 -1 0.5486066141420022 0.06994002902120672 -0.8331501516894545 -1 0.7444427261367031 0.4127293393945192 0.5248423762474955 -1 0.7444427261367031 0.4127293393945192 0.5248423762474955 -1 -0.380573002749541 0.9081645691962864 -0.1743596995716652 -1 -0.380573002749541 0.9081645691962864 -0.1743596995716652 -1 Output completed. Verifying that all points are below outer planes of all facets. Will make 96 distance computations. 8 vertices and 12 facets with normals: -0.74 -0.41 -0.52 -0.74 -0.41 -0.52 0.38 -0.91 0.17 0.38 -0.91 0.17 -0.55 -0.07 0.83 -0.55 -0.07 0.83 0.55 0.07 -0.83 0.55 0.07 -0.83 0.74 0.41 0.52 0.74 0.41 0.52 -0.38 0.91 -0.17 -0.38 0.91 -0.17 ======== compute 3-d Delaunay triangulation seed: 1595644038 input -0.801 -0.155 -0.117 0.0631 -0.963 -0.541 -0.235 -0.841 -0.984 0.538 0.0146 -0.34 -0.382 -0.912 -0.559 -0.155 -0.38 0.862 -0.594 0.566 -0.816 0.878 0.392 0.1 Voronoi diagram by the convex hull of 8 points in 4-d: Number of Voronoi regions: 8 Number of Voronoi vertices: 10 Statistics for: | qhull s d Tcv v p Number of points processed: 8 Number of hyperplanes created: 26 Number of facets in hull: 17 Number of distance tests for qhull: 28 CPU seconds to compute hull (after input): 0 3 10 -0.4071479102294318 1.219133029325973 0.6665355448746564 -0.1108160944725886 0.456025758474877 0.296165826000959 -0.04172545836103403 -0.4089628768956435 0.05248152588212329 1.328063758340639 -1.183562100392564 0.5872409889009436 -0.1590699940723186 0.6580028523373366 0.1606354382946221 -0.1958933203456756 -0.1120634006329647 -0.6453966139916644 -0.1391996697363491 -0.532197185823705 0.08861056648935872 -0.1012641820194624 -0.3207618095382609 -0.2371505242478096 -0.1847968878329362 -0.150249705715356 -0.6079504566397304 -0.07956014265606015 -0.2591783977016859 -0.5894629573067639 Output completed. Verifying that all points are below 1e-14 of all facets. Will make 80 distance computations. 8 vertices and 17 facets with normals: -0.27 0.8 0.44 -0.33 -0.15 0.61 0.4 -0.67 -0.064 -0.63 0.081 -0.77 0.68 -0.61 0.3 -0.26 -0.19 0.77 0.19 -0.58 -0.72 -0.05 0.32 0.62 -0.23 -0.13 -0.76 -0.59 0.51 -0.33 0.37 0.7 0.063 0.23 0.34 0.91 0.82 -0.23 -0.53 0.074 0.55 0.27 -0.78 0.11 -0.19 -0.71 0.12 -0.67 -0.74 -0.13 0.32 0.58 -0.024 -0.74 0.42 0.53 -0.16 -0.5 -0.37 -0.77 -0.22 -0.18 -0.74 -0.61 -0.097 -0.32 -0.72 -0.61 find 3-d Delaunay triangle or adjacent triangle closest to [0.5, 0.5, ...] -0.59 0.57 -0.82 -0.15 -0.38 0.86 0.88 0.39 0.10 -0.80 -0.16 -0.12 ======== Compute a new triangulation as a separate instance of Qhull seed: 1595644039 input -0.801 0.108 -0.606 0.98 0.102 -0.103 -0.141 0.517 0.375 0.407 0.782 0.698 -0.72 -0.842 -0.452 0.905 0.963 0.878 0.173 0.7 0.0194 0.252 -0.431 -0.039 Voronoi diagram by the convex hull of 8 points in 4-d: Number of Voronoi regions: 8 Number of Voronoi vertices: 10 Statistics for: | qhull s d Tcv v p Number of points processed: 8 Number of hyperplanes created: 29 Number of facets in hull: 19 Number of distance tests for qhull: 34 CPU seconds to compute hull (after input): 0 3 10 0.6957254548402696 -0.5636294604869319 -2.507464110663786 0.2747984690652054 0.1906381162276007 -1.008814834585774 0.9719393512739847 -0.4886296283040745 1.285981228064616 0.9113330904344364 0.817705195127131 0.1350558690072676 0.4328681637125205 0.1330532247438454 0.3197206613620017 0.4651973598805769 0.1012147513913624 0.4233056008080553 0.466027516489028 0.1682136331316482 0.3670953858444743 -0.1814376757632739 0.1184692202639611 -0.2296672791600022 -0.5906767690426418 -0.2360311159460474 0.1939451211897689 -2.63695386199309 -5.462987868661916 10.22310605930232 Output completed. Verifying that all points are below 1.5e-14 of all facets. Will make 80 distance computations. 8 vertices and 19 facets with normals: 0.25 0.099 -0.83 0.49 0.26 -0.21 -0.93 -0.18 0.41 -0.79 0.41 0.2 0.22 0.59 -0.76 0.17 0.23 0.16 -0.86 -0.43 0.55 -0.28 0.73 -0.28 0.69 0.62 0.1 -0.38 -0.14 -0.51 0.85 0.0066 -0.49 0.87 -0.013 0.069 0.58 0.18 0.43 -0.67 0.57 0.12 0.52 -0.62 0.59 0.21 0.46 -0.63 -0.31 0.2 -0.39 -0.85 -0.5 0.86 0.013 0.053 -0.71 -0.28 0.23 -0.6 -0.22 -0.46 0.86 -0.042 -0.77 0.12 0.59 0.21 -0.7 0.62 0.3 0.15 -0.67 -0.036 0.73 0.17 ======== Free memory allocated by the new instance of Qhull, and redisplay the old results. 8 vertices and 17 facets with normals: -0.27 0.8 0.44 -0.33 -0.15 0.61 0.4 -0.67 -0.064 -0.63 0.081 -0.77 0.68 -0.61 0.3 -0.26 -0.19 0.77 0.19 -0.58 -0.72 -0.05 0.32 0.62 -0.23 -0.13 -0.76 -0.59 0.51 -0.33 0.37 0.7 0.063 0.23 0.34 0.91 0.82 -0.23 -0.53 0.074 0.55 0.27 -0.78 0.11 -0.19 -0.71 0.12 -0.67 -0.74 -0.13 0.32 0.58 -0.024 -0.74 0.42 0.53 -0.16 -0.5 -0.37 -0.77 -0.22 -0.18 -0.74 -0.61 -0.097 -0.32 -0.72 -0.61 ======== compute halfspace intersection about the origin for a diamond input as halfspace coefficients + offsets -1 -1 -1 -1 1 -1 -1 -1 -1 1 -1 -1 1 1 -1 -1 -1 -1 1 -1 1 -1 1 -1 -1 1 1 -1 1 1 1 -1 Halfspace intersection by the convex hull of 8 points in 3-d: Number of halfspaces: 8 Number of non-redundant halfspaces: 8 Number of intersection points: 6 Number of non-simplicial intersection points: 6 Statistics for: | qhull H0 s Tcv Fp Number of points processed: 8 Number of hyperplanes created: 11 Number of distance tests for qhull: 34 Number of distance tests for merging: 96 Number of distance tests for checking: 100 Number of merged facets: 6 CPU seconds to compute hull (after input): 0 3 6 0 0 -1 0 -1 0 1 0 0 -1 0 0 0 1 0 0 0 1 Output completed. Verifying that all points are below outer planes of all facets. Will make 48 distance computations. 8 vertices and 6 facets with normals: -0 -0 -1 0 -1 0 1 -0 -0 -1 -0 -0 0 1 -0 -0 -0 1 user_eg2 ======== user_eg2 'cube qhull options' 'Delaunay options' 'halfspace options' This is the output from user_eg2_r.c. It shows how qhull() may be called from an application, via Qhull's static, reentrant library. user_eg2 is not part of Qhull itself. If user_eg2 fails immediately, user_eg2_r.c was incorrectly linked to Qhull's non-reentrant library, libqhullstatic. Try -- user_eg2 'T1' 'T1' 'T1' ======== compute triangulated convex hull of cube after rotating input Output completed. Verifying that all points are below outer planes of all facets. Will make 96 distance computations. 8 vertices and 12 facets with normals: -0 -0 -1 -0 -0 -1 0 -1 0 0 -1 0 1 -0 -0 1 -0 -0 -1 -0 -0 -1 -0 -0 0 1 -0 0 1 -0 -0 -0 1 -0 -0 1 add points in a diamond 9 vertices and 14 facets 10 vertices and 16 facets 11 vertices and 16 facets 12 vertices and 16 facets 13 vertices and 14 facets 14 vertices and 12 facets 14 vertices and 12 facets with normals: 0.71 -0.71 -0 -0.71 -0.71 0 -0.71 0.71 -0 0.71 0.71 -0 -0.71 -0 -0.71 -0 0.71 -0.71 0 -0.71 -0.71 0.71 0 -0.71 -0 -0.71 0.71 -0.71 0 0.71 0.71 0 0.71 -0 0.71 0.71 Convex hull of 14 points in 3-d: Number of vertices: 14 Number of facets: 12 Number of non-simplicial facets: 12 Statistics for: user_eg2 cube example | qhull s Tcv Q11 Number of points processed: 14 Number of hyperplanes created: 23 Number of distance tests for qhull: 64 Number of distance tests for merging: 276 Number of distance tests for checking: 324 Number of merged facets: 18 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 168 distance computations. ======== compute 2-d Delaunay triangulation seed: 1595644038 8 vertices and 12 facets with normals: 0.82 0.37 0.43 0.82 0.26 0.52 0.77 0.21 0.6 0.37 -0.025 0.93 -0.96 -0.0085 -0.29 -0.66 0.42 -0.62 -0.77 0.28 -0.57 -0.43 -0.34 -0.83 -0.45 -0.61 -0.65 -0.54 -0.61 -0.57 -0.6 -0.59 -0.53 -0.72 -0.46 -0.53 Delaunay triangulation by the convex hull of 8 points in 3-d: Number of input sites: 8 Number of Delaunay regions: 8 Statistics for: user_eg2 Delaunay example | qhull s d Tcv Number of points processed: 8 Number of hyperplanes created: 23 Number of facets in hull: 12 Number of distance tests for qhull: 32 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below 5.2e-15 of all facets. Will make 64 distance computations. ======== add points to triangulation added point p8: -1 -0.7369 1.543 9 points, 0 extra points, 9 vertices, and 14 facets in total added point p9: 0.5112 -0.0827 0.2682 10 points, 0 extra points, 10 vertices, and 16 facets in total added point p10: 0.06553 -0.5621 0.3202 11 points, 0 extra points, 11 vertices, and 18 facets in total added point p11: -0.9059 0.3577 0.9486 12 points, 0 extra points, 12 vertices, and 20 facets in total added point p12: 0.3586 0.8694 0.8844 13 points, 0 extra points, 13 vertices, and 22 facets in total added point p13: -0.233 0.03883 0.0558 14 points, 0 extra points, 14 vertices, and 24 facets in total find Delaunay triangle or adjacent triangle closest to [0.5, 0.5, ...] 0.36 0.87 0.51 -0.08 -0.12 0.06 Delaunay triangulation by the convex hull of 14 points in 3-d: Number of input sites: 14 Number of Delaunay regions: 19 Statistics for: user_eg2 Delaunay example | qhull s d Tcv Number of points processed: 14 Number of hyperplanes created: 51 Number of facets in hull: 24 Number of distance tests for qhull: 69 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below 5.2e-15 of all facets. Will make 266 distance computations. ======== compute halfspace intersection about the origin for a diamond Halfspace intersection by the convex hull of 8 points in 3-d: Number of halfspaces: 8 Number of non-redundant halfspaces: 8 Number of intersection points: 6 Number of non-simplicial intersection points: 6 Statistics for: user_eg2 halfspace example | qhull H0 s Tcv Number of points processed: 8 Number of hyperplanes created: 11 Number of distance tests for qhull: 34 Number of distance tests for merging: 96 Number of distance tests for checking: 100 Number of merged facets: 6 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 48 distance computations. ======== add halfspaces for cube to intersection added offset -1 and normal 1.732 0 0 8 points, 1 extra points, 9 vertices, and 9 facets in total added offset -1 and normal -1.732 0 0 8 points, 2 extra points, 10 vertices, and 12 facets in total added offset -1 and normal 0 1.732 0 8 points, 3 extra points, 11 vertices, and 15 facets in total added offset -1 and normal 0 -1.732 0 8 points, 4 extra points, 12 vertices, and 18 facets in total added offset -1 and normal 0 0 1.732 8 points, 5 extra points, 13 vertices, and 21 facets in total added offset -1 and normal 0 0 -1.732 8 points, 6 extra points, 14 vertices, and 24 facets in total Halfspace intersection by the convex hull of 14 points in 3-d: Number of halfspaces: 14 Number of non-redundant halfspaces: 14 Number of intersection points: 24 Statistics for: user_eg2 halfspace example | qhull H0 s Tcv Number of points processed: 14 Number of hyperplanes created: 35 Number of distance tests for qhull: 58 Number of distance tests for merging: 248 Number of distance tests for checking: 256 Number of merged facets: 6 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 192 distance computations. user_eg2 'QR1 p' 'v p' 'Fp' ======== user_eg2 'cube qhull options' 'Delaunay options' 'halfspace options' This is the output from user_eg2_r.c. It shows how qhull() may be called from an application, via Qhull's static, reentrant library. user_eg2 is not part of Qhull itself. If user_eg2 fails immediately, user_eg2_r.c was incorrectly linked to Qhull's non-reentrant library, libqhullstatic. Try -- user_eg2 'T1' 'T1' 'T1' ======== compute triangulated convex hull of cube after rotating input Output completed. Verifying that all points are below outer planes of all facets. Will make 96 distance computations. 8 vertices and 12 facets with normals: -0.74 -0.41 -0.52 -0.74 -0.41 -0.52 0.38 -0.91 0.17 0.38 -0.91 0.17 -0.55 -0.07 0.83 -0.55 -0.07 0.83 0.55 0.07 -0.83 0.55 0.07 -0.83 0.74 0.41 0.52 0.74 0.41 0.52 -0.38 0.91 -0.17 -0.38 0.91 -0.17 add points in a diamond 9 vertices and 14 facets 10 vertices and 16 facets 11 vertices and 18 facets 12 vertices and 20 facets 13 vertices and 22 facets 14 vertices and 24 facets 14 vertices and 24 facets with normals: -0.67 0.63 -0.39 0.67 -0.63 0.39 -0.1 -0.71 0.7 -0.65 -0.65 -0.41 -0.62 -0.62 -0.49 0.63 -0.7 -0.34 0.65 -0.66 0.37 -0.65 0.66 -0.37 0.1 0.71 -0.7 -0.63 0.7 0.34 0.62 0.62 0.49 0.65 0.65 0.41 -0.7 -0.13 -0.7 -0.62 -0.49 -0.62 0.11 0.7 -0.71 0.68 0.29 -0.68 0.66 -0.34 -0.67 0.67 -0.3 -0.67 -0.66 0.34 0.67 -0.67 0.3 0.67 0.62 0.49 0.62 0.7 0.13 0.7 -0.11 -0.7 0.71 -0.68 -0.29 0.68 Convex hull of 14 points in 3-d: Number of vertices: 14 Number of facets: 24 Statistics for: user_eg2 cube example | qhull s Tcv Q11 QR1 p QR1 Number of points processed: 14 Number of hyperplanes created: 46 Number of distance tests for qhull: 68 Number of distance tests for merging: 284 Number of distance tests for checking: 244 Number of merged facets: 6 CPU seconds to compute hull (after input): 0 3 14 0.9124763375291641 1.390833937612012 -0.4826674750136243 -0.5764091147442416 0.565375258822974 -1.532352227508615 -0.1847368907548403 1.250953879569599 1.183632828365285 -1.673622343028246 0.4254952007805605 0.1339480758702939 1.673622343028246 -0.4254952007805605 -0.1339480758702939 0.1847368907548403 -1.250953879569599 -1.183632828365285 0.5764091147442416 -0.565375258822974 1.532352227508615 -0.9124763375291641 -1.390833937612012 0.4826674750136243 -2 0 0 2 0 0 0 -2 0 0 2 0 0 0 -2 0 0 2 Output completed. Verifying that all points are below outer planes of all facets. Will make 192 distance computations. ======== compute 2-d Delaunay triangulation seed: 1595644038 8 vertices and 12 facets with normals: 0.82 0.37 0.43 0.82 0.26 0.52 0.77 0.21 0.6 0.37 -0.025 0.93 -0.96 -0.0085 -0.29 -0.66 0.42 -0.62 -0.77 0.28 -0.57 -0.43 -0.34 -0.83 -0.45 -0.61 -0.65 -0.54 -0.61 -0.57 -0.6 -0.59 -0.53 -0.72 -0.46 -0.53 Voronoi diagram by the convex hull of 8 points in 3-d: Number of Voronoi regions: 8 Number of Voronoi vertices: 8 Statistics for: user_eg2 Delaunay example | qhull s d Tcv v p Number of points processed: 8 Number of hyperplanes created: 23 Number of facets in hull: 12 Number of distance tests for qhull: 32 CPU seconds to compute hull (after input): 0 2 8 -1.674054922003768 -0.01487922147866316 -0.5283040369357602 0.3408731556323899 -0.6811827832457983 0.2470406317137401 -0.2588235717416882 -0.2062901824864997 -0.3453635548914167 -0.473499856633778 -0.4723074028302096 -0.5334617665938058 -0.5632414635328725 -0.5546706688338812 -0.6792210384845423 -0.4332097342034502 Output completed. Verifying that all points are below 5.2e-15 of all facets. Will make 64 distance computations. ======== add points to triangulation added point p8: -1 -0.7369 1.543 9 points, 0 extra points, 9 vertices, and 14 facets in total added point p9: 0.5112 -0.0827 0.2682 10 points, 0 extra points, 10 vertices, and 16 facets in total added point p10: 0.06553 -0.5621 0.3202 11 points, 0 extra points, 11 vertices, and 18 facets in total added point p11: -0.9059 0.3577 0.9486 12 points, 0 extra points, 12 vertices, and 20 facets in total added point p12: 0.3586 0.8694 0.8844 13 points, 0 extra points, 13 vertices, and 22 facets in total added point p13: -0.233 0.03883 0.0558 14 points, 0 extra points, 14 vertices, and 24 facets in total find Delaunay triangle or adjacent triangle closest to [0.5, 0.5, ...] 0.36 0.87 0.51 -0.08 -0.12 0.06 Voronoi diagram by the convex hull of 14 points in 3-d: Number of Voronoi regions: 14 Number of Voronoi vertices: 19 Statistics for: user_eg2 Delaunay example | qhull s d Tcv v p Number of points processed: 14 Number of hyperplanes created: 51 Number of facets in hull: 24 Number of distance tests for qhull: 69 CPU seconds to compute hull (after input): 0 2 19 -0.3453635548914167 -0.473499856633778 -0.4723074028302096 -0.5334617665938058 -0.5632414635328725 -0.5546706688338812 -0.6792210384845423 -0.4332097342034502 -4.056602348809204 -0.06101009284882331 -0.6560206746168462 -0.6998668839041049 0.185140444577552 -0.06163295117232724 -0.2543391922542552 -0.5188303037952583 0.3503119507232316 -0.379975065066025 -2.028638855503524 -0.02174467382692347 -1.591570729265863 -0.04956406204488362 -0.6808639548265594 0.136484379373769 0.2852101525160285 0.3693477005974929 -0.129890132625773 -0.1642796734345424 -0.2761495329593209 -0.2597875866082675 -0.5599240949499432 0.2183890070294259 -0.3236308562463083 0.7169995339075901 -0.3180575110901469 0.7253864449960007 -0.3156556110857897 0.7236756129173678 Output completed. Verifying that all points are below 5.2e-15 of all facets. Will make 266 distance computations. ======== compute halfspace intersection about the origin for a diamond Halfspace intersection by the convex hull of 8 points in 3-d: Number of halfspaces: 8 Number of non-redundant halfspaces: 8 Number of intersection points: 6 Number of non-simplicial intersection points: 6 Statistics for: user_eg2 halfspace example | qhull H0 s Tcv Fp Number of points processed: 8 Number of hyperplanes created: 11 Number of distance tests for qhull: 34 Number of distance tests for merging: 96 Number of distance tests for checking: 100 Number of merged facets: 6 CPU seconds to compute hull (after input): 0.001 3 6 0 0 -1 0 -1 0 1 0 0 -1 0 0 0 1 0 0 0 1 Output completed. Verifying that all points are below outer planes of all facets. Will make 48 distance computations. ======== add halfspaces for cube to intersection added offset -1 and normal 1.732 0 0 8 points, 1 extra points, 9 vertices, and 9 facets in total added offset -1 and normal -1.732 0 0 8 points, 2 extra points, 10 vertices, and 12 facets in total added offset -1 and normal 0 1.732 0 8 points, 3 extra points, 11 vertices, and 15 facets in total added offset -1 and normal 0 -1.732 0 8 points, 4 extra points, 12 vertices, and 18 facets in total added offset -1 and normal 0 0 1.732 8 points, 5 extra points, 13 vertices, and 21 facets in total added offset -1 and normal 0 0 -1.732 8 points, 6 extra points, 14 vertices, and 24 facets in total Halfspace intersection by the convex hull of 14 points in 3-d: Number of halfspaces: 14 Number of non-redundant halfspaces: 14 Number of intersection points: 24 Statistics for: user_eg2 halfspace example | qhull H0 s Tcv Fp Number of points processed: 14 Number of hyperplanes created: 35 Number of distance tests for qhull: 58 Number of distance tests for merging: 248 Number of distance tests for checking: 256 Number of merged facets: 6 CPU seconds to compute hull (after input): 0.001 3 24 0.5773502691896257 0 -0.4226497308103742 0.5773502691896257 -0.4226497308103742 0 0.5773502691896257 0.4226497308103742 0 0.5773502691896257 0 0.4226497308103742 -0.5773502691896257 0 -0.4226497308103742 -0.5773502691896257 -0.4226497308103742 0 -0.5773502691896257 0 0.4226497308103742 -0.5773502691896257 0.4226497308103742 0 0 0.5773502691896257 -0.4226497308103742 0.4226497308103742 0.5773502691896257 0 -0.4226497308103742 0.5773502691896257 0 0 0.5773502691896257 0.4226497308103742 0 -0.5773502691896257 -0.4226497308103742 -0.4226497308103742 -0.5773502691896257 0 0 -0.5773502691896257 0.4226497308103742 0.4226497308103742 -0.5773502691896257 0 0 -0.4226497308103742 0.5773502691896257 0.4226497308103742 0 0.5773502691896257 0 0.4226497308103742 0.5773502691896257 -0.4226497308103742 0 0.5773502691896257 -0.4226497308103742 0 -0.5773502691896257 0 -0.4226497308103742 -0.5773502691896257 0 0.4226497308103742 -0.5773502691896257 0.4226497308103742 0 -0.5773502691896257 Output completed. Verifying that all points are below outer planes of all facets. Will make 192 distance computations. user_eg3 ======== user_eg3 commands... -- demonstrate calling rbox and qhull from C++. user_eg3 is statically linked to qhullcpp and reentrant qhull. If user_eg3 fails immediately, it is probably linked to the non-reentrant qhull library. Commands: eg-100 Run the example in qh-code.htm eg-convex 'rbox d | qconvex o' with std::vector and C++ classes eg-delaunay 'rbox y c | qdelaunay o' with std::vector and C++ classes eg-voronoi 'rbox y c | qvoronoi o' with std::vector and C++ classes eg-fifo 'rbox y c | qvoronoi FN Fi Fo' with QhullUser and qh_fprintf Rbox and Qhull commands: rbox "200 D4" ... Generate points from rbox qhull "d p" ... Run qhull with options and produce output qhull-cout "o" ... Run qhull with options and produce output to cout qhull "T1" ... Run qhull with level-1 trace to cerr qhull-cout "T1z" ... Run qhull with level-1 trace to cout facets Print qhull's facets when done For example user_eg3 rbox qhull user_eg3 rbox qhull T1 user_eg3 rbox qhull d user_eg3 rbox D2 10 2 "s r 5" qhull "s p" facets user_eg3 eg-convex user_eg3 rbox 10 eg-delaunay qhull "d o" user_eg3 rbox D5 c P2 qhull d eg-delaunay user_eg3 rbox "D5 c P2" qhull v eg-voronoi o user_eg3 rbox D2 10 qhull "v" eg-fifo p Fi Fo user_eg3 eg-100 - f24 - flags: bottom simplicial - normal: -0.721696 -0.658796 -0.212466 - offset: -0.549277 - vertices: p40(v10) p27(v7) p0(v1) - neighboring facets: f34 f47 f54 - f32 - flags: top simplicial - normal: 0.389612 -0.428663 0.815138 - offset: -0.449315 - vertices: p22(v12) p13(v6) p82(v2) - neighboring facets: f61 f72 f77 - f34 - flags: top simplicial - normal: -0.452613 -0.760661 0.465335 - offset: -0.62552 - vertices: p22(v12) p27(v7) p0(v1) - neighboring facets: f24 f80 f73 - f38 - flags: top simplicial - normal: 0.998285 0.058513 -0.00174787 - offset: -0.477764 - vertices: p90(v13) p48(v8) p82(v2) - neighboring facets: f100 f97 f57 - f46 - flags: bottom simplicial - normal: -0.406035 0.904011 0.133791 - offset: -0.547585 - vertices: p73(v15) p76(v9) p97(v5) - neighboring facets: f51 f87 f82 - f47 - flags: bottom simplicial - normal: -0.992416 -0.0122817 -0.122308 - offset: -0.469463 - vertices: p73(v15) p40(v10) p0(v1) - neighboring facets: f24 f81 f88 - f49 - flags: top simplicial - normal: -0.107843 0.991034 0.0788761 - offset: -0.50132 - vertices: p21(v16) p97(v5) p29(v3) - neighboring facets: f116 f66 f51 - f51 - flags: top simplicial - normal: -0.177935 0.975873 0.126537 - offset: -0.506339 - vertices: p21(v16) p76(v9) p97(v5) - neighboring facets: f46 f49 f67 - f52 - flags: top simplicial - normal: -0.378163 -0.891276 -0.250241 - offset: -0.526009 - vertices: p98(v17) p27(v7) p83(v4) - neighboring facets: f75 f53 f54 - f53 - flags: bottom simplicial - normal: -0.430163 -0.821913 -0.373389 - offset: -0.546784 - vertices: p98(v17) p40(v10) p83(v4) - neighboring facets: f108 f52 f54 - f54 - flags: top simplicial - normal: -0.548096 -0.791241 -0.271162 - offset: -0.537299 - vertices: p98(v17) p40(v10) p27(v7) - neighboring facets: f24 f52 f53 - f57 - flags: bottom simplicial - normal: 0.974428 0.137974 -0.177349 - offset: -0.521881 - vertices: p19(v18) p90(v13) p48(v8) - neighboring facets: f38 f60 f113 - f59 - flags: bottom simplicial - normal: 0.239508 -0.0103785 -0.970839 - offset: -0.517616 - vertices: p19(v18) p4(v14) p83(v4) - neighboring facets: f76 f110 f60 - f60 - flags: top simplicial - normal: 0.567061 -0.0365561 -0.822865 - offset: -0.572132 - vertices: p19(v18) p4(v14) p48(v8) - neighboring facets: f85 f57 f59 - f61 - flags: bottom simplicial - normal: 0.433241 -0.284128 0.855321 - offset: -0.426268 - vertices: p37(v19) p13(v6) p82(v2) - neighboring facets: f32 f69 f95 - f65 - flags: top simplicial - normal: -0.198254 0.211674 0.957021 - offset: -0.497913 - vertices: p67(v20) p12(v11) p76(v9) - neighboring facets: f79 f67 f68 - f66 - flags: top simplicial - normal: -0.155514 0.97946 0.128347 - offset: -0.504016 - vertices: p67(v20) p21(v16) p29(v3) - neighboring facets: f49 f71 f67 - f67 - flags: bottom simplicial - normal: -0.16055 0.978089 0.132539 - offset: -0.504235 - vertices: p67(v20) p21(v16) p76(v9) - neighboring facets: f51 f65 f66 - f68 - flags: top simplicial - normal: 0.598999 -0.0537935 0.798941 - offset: -0.457967 - vertices: p67(v20) p37(v19) p12(v11) - neighboring facets: f96 f65 f69 - f69 - flags: bottom simplicial - normal: 0.69477 -0.0317528 0.718531 - offset: -0.45153 - vertices: p67(v20) p37(v19) p82(v2) - neighboring facets: f61 f98 f68 - f71 - flags: bottom simplicial - normal: 0.877687 0.308225 0.366966 - offset: -0.494379 - vertices: p67(v20) p90(v13) p29(v3) - neighboring facets: f115 f66 f99 - f72 - flags: top simplicial - normal: 0.245263 -0.887198 0.390801 - offset: -0.480731 - vertices: p41(v21) p22(v12) p82(v2) - neighboring facets: f32 f74 f73 - f73 - flags: bottom simplicial - normal: 0.0168085 -0.963019 0.268908 - offset: -0.510609 - vertices: p41(v21) p22(v12) p27(v7) - neighboring facets: f34 f75 f72 - f74 - flags: bottom simplicial - normal: 0.227082 -0.964773 0.132845 - offset: -0.464868 - vertices: p41(v21) p4(v14) p82(v2) - neighboring facets: f84 f72 f76 - f75 - flags: bottom simplicial - normal: 0.0345717 -0.998303 0.0468616 - offset: -0.47919 - vertices: p41(v21) p27(v7) p83(v4) - neighboring facets: f52 f76 f73 - f76 - flags: top simplicial - normal: 0.137757 -0.987556 0.0758723 - offset: -0.471349 - vertices: p41(v21) p4(v14) p83(v4) - neighboring facets: f59 f75 f74 - f77 - flags: bottom simplicial - normal: -0.323398 -0.00535492 0.946248 - offset: -0.501516 - vertices: p15(v22) p22(v12) p13(v6) - neighboring facets: f32 f78 f80 - f78 - flags: top simplicial - normal: -0.20543 0.0915675 0.974379 - offset: -0.474687 - vertices: p15(v22) p12(v11) p13(v6) - neighboring facets: f94 f77 f79 - f79 - flags: bottom simplicial - normal: -0.218614 0.160888 0.962457 - offset: -0.484859 - vertices: p15(v22) p12(v11) p76(v9) - neighboring facets: f65 f82 f78 - f80 - flags: top simplicial - normal: -0.593167 -0.119334 0.796186 - offset: -0.544059 - vertices: p15(v22) p22(v12) p0(v1) - neighboring facets: f34 f81 f77 - f81 - flags: bottom simplicial - normal: -0.974282 0.088044 0.20742 - offset: -0.50771 - vertices: p15(v22) p73(v15) p0(v1) - neighboring facets: f47 f80 f82 - f82 - flags: top simplicial - normal: -0.826328 0.394399 0.402034 - offset: -0.559684 - vertices: p15(v22) p73(v15) p76(v9) - neighboring facets: f46 f79 f81 - f84 - flags: top simplicial - normal: 0.82988 -0.542609 -0.129903 - offset: -0.585213 - vertices: p57(v23) p4(v14) p82(v2) - neighboring facets: f74 f101 f85 - f85 - flags: bottom simplicial - normal: 0.906692 -0.29884 -0.297664 - offset: -0.57209 - vertices: p57(v23) p4(v14) p48(v8) - neighboring facets: f60 f102 f84 - f86 - flags: top simplicial - normal: -0.85363 0.243861 -0.460269 - offset: -0.522928 - vertices: p11(v24) p40(v10) p97(v5) - neighboring facets: f89 f87 f88 - f87 - flags: bottom simplicial - normal: -0.890339 0.291001 -0.350165 - offset: -0.531756 - vertices: p11(v24) p73(v15) p97(v5) - neighboring facets: f46 f86 f88 - f88 - flags: top simplicial - normal: -0.987894 0.0156004 -0.154345 - offset: -0.477251 - vertices: p11(v24) p73(v15) p40(v10) - neighboring facets: f47 f86 f87 - f89 - flags: bottom simplicial - normal: -0.492188 0.332666 -0.804416 - offset: -0.526118 - vertices: p25(v25) p40(v10) p97(v5) - neighboring facets: f86 f114 f109 - f94 - flags: bottom simplicial - normal: 0.368779 -0.208614 0.905805 - offset: -0.440207 - vertices: p7(v26) p12(v11) p13(v6) - neighboring facets: f78 f95 f96 - f95 - flags: top simplicial - normal: 0.417114 -0.259346 0.871066 - offset: -0.429768 - vertices: p7(v26) p37(v19) p13(v6) - neighboring facets: f61 f94 f96 - f96 - flags: bottom simplicial - normal: 0.469304 -0.162419 0.867971 - offset: -0.446808 - vertices: p7(v26) p37(v19) p12(v11) - neighboring facets: f68 f94 f95 - f97 - flags: top simplicial - normal: 0.911891 0.1675 0.374697 - offset: -0.446013 - vertices: p28(v27) p90(v13) p82(v2) - neighboring facets: f38 f98 f99 - f98 - flags: bottom simplicial - normal: 0.888791 0.148029 0.433749 - offset: -0.448933 - vertices: p28(v27) p67(v20) p82(v2) - neighboring facets: f69 f97 f99 - f99 - flags: top simplicial - normal: 0.903592 0.183305 0.387197 - offset: -0.447956 - vertices: p28(v27) p67(v20) p90(v13) - neighboring facets: f71 f97 f98 - f100 - flags: bottom simplicial - normal: 0.93763 -0.294784 -0.184262 - offset: -0.546054 - vertices: p42(v28) p48(v8) p82(v2) - neighboring facets: f38 f101 f102 - f101 - flags: top simplicial - normal: 0.933493 -0.306605 -0.185968 - offset: -0.547862 - vertices: p42(v28) p57(v23) p82(v2) - neighboring facets: f84 f100 f102 - f102 - flags: bottom simplicial - normal: 0.928146 -0.300441 -0.219729 - offset: -0.55469 - vertices: p42(v28) p57(v23) p48(v8) - neighboring facets: f85 f100 f101 - f108 - flags: top simplicial - normal: 0.00135876 0.0103445 -0.999946 - offset: -0.494086 - vertices: p5(v30) p40(v10) p83(v4) - neighboring facets: f53 f110 f109 - f109 - flags: top simplicial - normal: -0.106214 0.129184 -0.985916 - offset: -0.504323 - vertices: p5(v30) p25(v25) p40(v10) - neighboring facets: f89 f108 f111 - f110 - flags: bottom simplicial - normal: 0.125474 0.0262996 -0.991748 - offset: -0.496467 - vertices: p5(v30) p19(v18) p83(v4) - neighboring facets: f59 f108 f111 - f111 - flags: bottom simplicial - normal: 0.0358445 0.163534 -0.985886 - offset: -0.514407 - vertices: p5(v30) p25(v25) p19(v18) - neighboring facets: f112 f110 f109 - f112 - flags: top simplicial - normal: 0.0769357 0.958704 -0.273801 - offset: -0.543222 - vertices: p78(v31) p25(v25) p19(v18) - neighboring facets: f111 f113 f114 - f113 - flags: top simplicial - normal: 0.129005 0.982313 -0.135717 - offset: -0.512909 - vertices: p78(v31) p19(v18) p90(v13) - neighboring facets: f57 f115 f112 - f114 - flags: bottom simplicial - normal: -0.0450665 0.957786 -0.283929 - offset: -0.551711 - vertices: p78(v31) p25(v25) p97(v5) - neighboring facets: f89 f116 f112 - f115 - flags: top simplicial - normal: 0.102483 0.993113 -0.0567803 - offset: -0.497056 - vertices: p78(v31) p90(v13) p29(v3) - neighboring facets: f71 f116 f113 - f116 - flags: bottom simplicial - normal: -0.00662022 0.999903 -0.0122926 - offset: -0.49314 - vertices: p78(v31) p97(v5) p29(v3) - neighboring facets: f49 f115 f114 user_eg3 eg-convex A 3-d diamond (rbox d) 3 rbox "d" 6 0 0 -0.5 0 0 0.5 0 -0.5 0 0 0.5 0 -0.5 0 0 0.5 0 0 Input points and facetlist of its convex hull (qhull o) 3 6 8 12 0 0 -0.5 0 0 0.5 0 -0.5 0 0 0.5 0 -0.5 0 0 0.5 0 0 3 2 0 4 3 0 2 5 3 1 2 4 3 2 1 5 3 3 0 5 3 0 3 4 3 1 3 5 3 3 1 4 Input points and facetlist using std::vector and C++ classes 3 6 8 12 0 0 -0.5 0 0 0.5 0 -0.5 0 0 0.5 0 -0.5 0 0 0.5 0 0 3 2 0 4 3 0 2 5 3 1 2 4 3 2 1 5 3 3 0 5 3 0 3 4 3 1 3 5 3 3 1 4 Its outward pointing normals as vector plus offset (qhull n) 4 8 -0.5773502691896258 -0.5773502691896258 -0.5773502691896258 -0.2886751345948129 0.5773502691896258 -0.5773502691896258 -0.5773502691896258 -0.2886751345948129 -0.5773502691896258 -0.5773502691896258 0.5773502691896258 -0.2886751345948129 0.5773502691896258 -0.5773502691896258 0.5773502691896258 -0.2886751345948129 0.5773502691896258 0.5773502691896258 -0.5773502691896258 -0.2886751345948129 -0.5773502691896258 0.5773502691896258 -0.5773502691896258 -0.2886751345948129 0.5773502691896258 0.5773502691896258 0.5773502691896258 -0.2886751345948129 -0.5773502691896258 0.5773502691896258 0.5773502691896258 -0.2886751345948129 user_eg3 eg-delaunay A 2-d triangle in a square (rbox y c D2) 2 rbox "y c D2" 7 0.0795233 -0.451105 0.279706 0.0133225 -0.0888864 0.0861965 -0.5 -0.5 -0.5 0.5 0.5 -0.5 0.5 0.5 The 2-d input sites are lifted to a 3-d paraboloid. A Delaunay region is a facet of the paraboloid's convex hull. The Delaunay triangulation as input sites and Delaunay regions (qhull d o) 3 7 8 12 0.07952334739223432 -0.4511049142583319 0.209819606448483 0.2797056779076398 0.01332249167684696 0.07841275503825199 -0.08888640449278651 0.08619647248293871 0.01533062477215727 -0.5 -0.5 0.5 -0.5 0.5 0.5 0.5 -0.5 0.5 0.5 0.5 0.5 3 2 4 3 3 2 6 4 3 5 0 3 3 0 2 3 3 6 1 5 3 1 6 2 3 1 0 5 3 0 1 2 The same results using std::vector and C++ classes 3 7 8 12 0.0795233 -0.451105 0.20982 0.279706 0.0133225 0.0784128 -0.0888864 0.0861965 0.0153306 -0.5 -0.5 0.5 -0.5 0.5 0.5 0.5 -0.5 0.5 0.5 0.5 0.5 3 2 4 3 3 2 6 4 3 5 0 3 3 0 2 3 3 6 1 5 3 1 6 2 3 1 0 5 3 0 1 2 user_eg3 eg-voronoi A 2-d triangle in a square (rbox y c D2) 2 rbox "y c D2" 7 0.0795233 -0.451105 0.279706 0.0133225 -0.0888864 0.0861965 -0.5 -0.5 -0.5 0.5 0.5 -0.5 0.5 0.5 Its Voronoi diagram as vertices and regions (qhull v o) The Voronoi diagram is the dual of the Delaunay triangulation Voronoi vertices are Delaunay regions, and Voronoi regions are Delaunay input sites The Voronoi vertex at infinity is represented as '-10.101 -10.101' 2 9 7 1 -10.101 -10.101 -0.5894591914795221 -2.775557561562891e-17 0 0.5856274089010268 -1.387778780781446e-17 -2.967377898513707 -0.2290343684408742 -0.2527745420948135 0.9568726986640038 2.081668171172169e-17 0.1571419516493774 0.3619977084558904 0.3129256373384354 -0.2763523586794005 0.05307821633938364 -0.1643502208872393 4 8 4 3 7 4 8 6 5 7 5 8 4 1 2 6 4 4 1 0 3 3 2 0 1 4 7 3 0 5 4 6 2 0 5 The same results using std::vector and C++ classes Qhull::prepareVoronoi assigns facetT.visit_id and vertexT.neighbors The Voronoi regions are rotated by one Voronoi vertex (prepareVoronoi occurs twice) 2 9 7 1 -10.101 -10.101 -0.589459 -2.77556e-17 0 0.585627 -1.38778e-17 -2.96738 -0.229034 -0.252775 0.956873 2.08167e-17 0.157142 0.361998 0.312926 -0.276352 0.0530782 -0.16435 4 7 8 4 3 4 7 8 6 5 5 6 8 4 1 2 4 3 4 1 0 3 1 2 0 4 5 7 3 0 4 5 6 2 0 user_eg3 eg-fifo A 2-d triangle in a square (rbox y c D2) 2 rbox "y c D2" 7 0.0795233 -0.451105 0.279706 0.0133225 -0.0888864 0.0861965 -0.5 -0.5 -0.5 0.5 0.5 -0.5 0.5 0.5 Its Voronoi vertices (qhull v p) This is the first part of eg-voronoi, but without infinity 2 8 -0.5894591914795221 -2.775557561562891e-17 0 0.5856274089010268 -1.387778780781446e-17 -2.967377898513707 -0.2290343684408742 -0.2527745420948135 0.9568726986640038 2.081668171172169e-17 0.1571419516493774 0.3619977084558904 0.3129256373384354 -0.2763523586794005 0.05307821633938364 -0.1643502208872393 Its Voronoi regions (qhull v FN) This is the second part of eg-voronoi, with ids one less Regions are ordered by the corresponding input site. 7 4 7 3 2 6 4 7 5 4 6 5 7 3 0 1 5 4 3 0 -1 2 3 1 -1 0 4 6 2 -1 4 4 5 1 -1 4 The same results as 'qhull v p FN' using std::vector and C++ classes Qhull::prepareVoronoi assigns facet.visit_id and vertex.neighbors prepareVoronoi is also called by q.outputQhull("FN"), hence the rotated vertices 2 8 -0.589459 -2.77556e-17 0 0.585627 -1.38778e-17 -2.96738 -0.229034 -0.252775 0.956873 2.08167e-17 0.157142 0.361998 0.312926 -0.276352 0.0530782 -0.16435 7 4 6 7 3 2 4 6 7 5 4 5 5 7 3 0 1 4 2 3 0 -1 3 0 1 -1 4 4 6 2 -1 4 4 5 1 -1 Hyperplanes for bounded facets between Voronoi regions (qhull v Fi) Each hyperplane is the perpendicular bisector of 2 input sites. 10 5 0 1 0.3958261856523667 0.9183254492563615 0.1299172425168069 5 0 5 0.9933067158065388 -0.1155065726858348 -0.3427516509210134 5 0 2 -0.2990888272252211 0.954225273941663 0.1727022360246516 5 0 3 -0.9964596398753636 -0.08407250501478321 -0.2494748932535505 5 1 5 0.3943714145865591 -0.9189511343684148 -0.3773632397513814 5 1 2 -0.9810105005095815 0.1939546284313432 0.08394677360204827 5 1 6 0.4123709353479589 0.9110160326142727 -0.3945864897570009 5 2 6 0.8181972788475073 0.5749375730342683 -0.3366992011759034 5 2 3 -0.574189571650573 -0.8187223801800775 -0.3384613206611199 5 2 4 -0.7047972640762143 0.7094087795838752 -0.4154492254393445 Hyperplanes for unbounded rays of unbounded facets (qhull v Fo) Each ray goes through the midpoint of 2 input sites, oriented outwards 4 5 3 5 1 -5.624508437144599e-18 -2.812254218572297e-18 5 3 4 -3.10259629632159e-16 1 -1.551298148160795e-16 5 4 6 1 -0 -0 5 5 6 -4.55634179336919e-17 1 2.278170896684595e-17 The same result as 'qhull v Fi' using QhullUser and its custom qh_fprintf qh_fprintf captures the output from qh_eachvoronoi in io_r.c (qhull v Fi Fo Ta) 10 5 0 1 0.395826 0.918325 0.129917 5 0 5 0.993307 -0.115507 -0.342752 5 0 2 -0.299089 0.954225 0.172702 5 0 3 -0.99646 -0.0840725 -0.249475 5 1 5 0.394371 -0.918951 -0.377363 5 1 2 -0.981011 0.193955 0.0839468 5 1 6 0.412371 0.911016 -0.394586 5 2 6 0.818197 0.574938 -0.336699 5 2 3 -0.57419 -0.818722 -0.338461 5 2 4 -0.704797 0.709409 -0.415449 The same result as 'qhull v Fo' using QhullUser and its custom qh_fprintf 4 5 3 5 1 -5.62451e-18 -2.81225e-18 5 3 4 -3.1026e-16 1 -1.5513e-16 5 4 6 1 -0 -0 5 5 6 -4.55634e-17 1 2.27817e-17 Message codes captured by qh_fprintf in QhullUser.cpp (qhull v Fo Ta): 9231 9271 9272 9272 9273 9274 9271 9272 9272 9273 9274 9271 9272 9272 9273 9274 9271 9272 9272 9273 9274 user_eg3 rbox qhull Results of qhull Convex hull of 10 points in 2-d: Number of vertices: 4 Number of facets: 4 Statistics for: rbox "10 D2" | qhull Number of points processed: 4 Number of hyperplanes created: 5 Number of distance tests for qhull: 51 CPU seconds to compute hull (after input): 0 user_eg3 rbox qhull T1 Results of T1 [QH0013]qh_initqhull_globals: for rbox "10 D2" | qhull T1 qh_meminitbuffers: memory initialized with alignment 8 qh_maxmin: dim min max width nearzero min-point max-point 0 -4.28543191e-01 3.79031236e-01 8.07574428e-01 7.6125e-15 p1 p4 1 -4.97972782e-01 4.74582647e-01 9.72555429e-01 1.6458e-14 p0 p1 qh_maxmin: found the max and min points (by dim): p1 p4 p0 p1 [QH1002]qh_maxsimplex: selected point p0 for 3`th initial vertex, det=0.7462, targetdet=0.7854, mindet=0.007854 [QH1028]qh_createsimplex: created simplex qh_initialhull: qh.interior_point p-2: -0.02391 0.1182 [QH1027]qh_checkpolygon: check all facets from f1, qh.NEWtentative? 0 [QH1064]qh_checkconvex: check that facets are not-flipped and for qh.ZEROcentrum that simplicial vertices are below their neighbor (dist<0.0) qh_initialhull: simplex constructed [QH1042]qh_partitionall: partition all points into outside sets Trace level T0, IStracing 1, point TP-3, merge TM0, dist TW1.8e+308, qh.tracefacet_id -1, traceridge_id -1, tracevertex_id -1, last qh.RERUN 0, rbox "10 D2" | qhull T1 Options selected for Qhull 2020.2.r 2020/07/24: run-id 213562930 _pre-merge _zero-centrum _max-width 0.97 Error-roundoff 4.3e-16 _one-merge 2.1e-15 _near-inside 1.1e-14 Visible-distance 8.5e-16 U-max-coplanar 8.5e-16 Width-outside 1.7e-15 _wide-facet 5.1e-15 [QH1029]qh_furthestnext: made f3 next facet(dist 0.19) [QH1030]qh_initbuild: initial hull created and points partitioned [QH1037]qh_buildhull: start build hull [QH1049]qh_addpoint: add p8(v4) 0.19 above f3 to hull of 3 facets, 0 merges, 3 outside at 0 CPU secs. Previous p-1(v3) delta 0 CPU, 3 facets, 0 merges, 3 hyperplanes, 61 distplanes, 0 retries [QH1040]qh_findhorizon: find horizon for point p8 facet f3 [QH1041]qh_findhorizon: 2 horizon facets(good 2), 1 visible(good 1), 0 coplanar [QH1032]qh_makenewfacets: created 2 new facets f4..f5 from point p8 to horizon [QH1019]qh_matchnewfacets: match neighbors for new facets. [QH1043]qh_partitionvisible: partitioned 2 points from outsidesets, 0 points from coplanarsets, and 0 deleted vertices [QH1018]qh_deletevisible: delete 1 visible facets and 0 vertices [QH1039]qh_buildhull: completed the hull construction [QH1036]Qhull: algorithm completed [QH1027]qh_checkpolygon: check all facets from f1, qh.NEWtentative? 0 [QH1064]qh_checkconvex: check that facets are not-flipped and for qh.ZEROcentrum that simplicial vertices are below their neighbor (dist<0.0) Convex hull of 10 points in 2-d: Number of vertices: 4 Number of facets: 4 Statistics for: rbox "10 D2" | qhull T1 Number of points processed: 4 Number of hyperplanes created: 5 Number of distance tests for qhull: 51 CPU seconds to compute hull (after input): 0 user_eg3 rbox qhull d Results of d Delaunay triangulation by the convex hull of 10 points in 3-d: Number of input sites: 10 Number of Delaunay regions: 14 Statistics for: rbox "10 D2" | qhull d Number of points processed: 10 Number of hyperplanes created: 28 Number of facets in hull: 16 Number of distance tests for qhull: 47 CPU seconds to compute hull (after input): 0 user_eg3 rbox y c rbox y rbox c 3 rbox "y" "c" 12 -0.306292 0.149266 -0.289011 -0.409906 -0.282924 -0.0983473 0.0770774 0.440163 -0.185531 -0.212802 0.438723 -0.375664 -0.5 -0.5 -0.5 -0.5 -0.5 0.5 -0.5 0.5 -0.5 -0.5 0.5 0.5 0.5 -0.5 -0.5 0.5 -0.5 0.5 0.5 0.5 -0.5 0.5 0.5 0.5 user_eg3 rbox D2 10 2 "s r 5" qhull 's p' facets rbox D2 rbox 10 rbox 2 rbox s r 5 Results of s p Convex hull of 17 points in 2-d: Number of vertices: 7 Number of facets: 7 Statistics for: rbox "10 D2" "2 D2" "s r 5 D2" | qhull s p Number of points processed: 7 Number of hyperplanes created: 11 Number of distance tests for qhull: 78 CPU seconds to compute hull (after input): 0 2 7 -0.02222276248244826 -0.4979727817680433 -0.4285431913366012 0.4745826469497594 0.3790312361708201 0.3779794437605696 0.1545084971874737 0.4755282581475768 -0.4045084971874738 -0.2938926261462365 0.1545084971874736 -0.4755282581475768 0.5 -1.224646799147353e-16 Facets created by Qhull::runQhull() - f5 - flags: bottom simplicial - normal: 0.952413 0.304811 - offset: -0.476206 - vertices: p4(v4) p16(v2) - neighboring facets: f8 f11 - f6 - flags: bottom simplicial - normal: -0.999511 -0.0312605 - offset: -0.413498 - vertices: p14(v5) p1(v1) - neighboring facets: f10 f7 - f7 - flags: top simplicial - normal: -0.470938 -0.882167 - offset: -0.44976 - vertices: p14(v5) p0(v3) - neighboring facets: f9 f6 - f8 - flags: top simplicial - normal: 0.809017 -0.587785 - offset: -0.404508 - vertices: p15(v6) p16(v2) - neighboring facets: f5 f9 - f9 - flags: bottom simplicial - normal: 0.125986 -0.992032 - offset: -0.491205 - vertices: p15(v6) p0(v3) - neighboring facets: f7 f8 - f10 - flags: top simplicial - normal: -0.00162183 0.999999 - offset: -0.475277 - vertices: p12(v7) p1(v1) - neighboring facets: f6 f11 - f11 - flags: bottom simplicial - normal: 0.398486 0.917174 - offset: -0.497712 - vertices: p12(v7) p4(v4) - neighboring facets: f5 f10 user_eg3 rbox "10 D2" eg-convex rbox 10 D2 Input points and facetlist for convex hull of rbox "10 D2" via C++ classes 2 10 4 4 -0.0222228 -0.497973 -0.428543 0.474583 0.31054 0.240018 -0.0188396 0.363026 0.379031 0.377979 -0.299496 0.377661 0.347182 0.0836553 -0.0048582 0.348268 0.344312 -0.143731 0.309331 -0.077581 2 4 1 2 1 0 2 8 4 2 0 8 user_eg3 rbox '10 D2' qhull s eg-convex rbox 10 D2 Results of s Convex hull of 10 points in 2-d: Number of vertices: 4 Number of facets: 4 Statistics for: rbox "10 D2" | qhull s Number of points processed: 4 Number of hyperplanes created: 5 Number of distance tests for qhull: 51 CPU seconds to compute hull (after input): 0 Input points and facetlist for 'qhull s' via C++ classes 2 10 4 4 -0.0222228 -0.497973 -0.428543 0.474583 0.31054 0.240018 -0.0188396 0.363026 0.379031 0.377979 -0.299496 0.377661 0.347182 0.0836553 -0.0048582 0.348268 0.344312 -0.143731 0.309331 -0.077581 2 4 1 2 1 0 2 8 4 2 0 8 user_eg3 rbox 10 eg-delaunay qhull 'd o' rbox 10 Delaunay triangulation of 10 points as 4-d paraboloid via C++ classes 4 10 15 30 -0.374949 0.224726 -0.0378235 0.192519 0.300492 0.369454 0.421096 0.404114 0.364148 0.233952 0.0348979 0.188555 -0.470713 -0.281065 0.135495 0.318928 0.264275 -0.326571 0.317506 0.2773 0.318323 0.0506033 0.489822 0.343815 0.433436 -0.248039 0.203767 0.290911 -0.285595 -0.00222701 -0.42931 0.265876 -0.40759 -0.362593 -0.0978938 0.307186 -0.301385 -0.378685 0.434172 0.422741 4 5 2 1 6 4 5 4 2 6 4 2 4 7 6 4 4 0 5 2 4 0 5 2 1 4 0 4 9 3 4 4 0 9 5 4 0 9 5 1 4 4 8 7 6 4 4 8 9 3 4 8 0 7 3 4 0 8 4 3 4 4 8 2 7 4 8 0 2 7 4 8 0 4 2 Results of d o 4 10 15 30 -0.374949442106252 0.2247255418679914 -0.03782349642163468 0.1925192701852094 0.3004920247946792 0.3694544596313075 0.4210962191420572 0.4041140804824029 0.3641479121187217 0.2339522165562512 0.03489791698278666 0.1885552061417448 -0.4707134565997063 -0.2810653003687648 0.1354949890035158 0.3189277533404903 0.2642752088273644 -0.3265712199048802 0.3175057017407433 0.2773000183087906 0.3183227589524563 0.05060330969337679 0.4898217078203537 0.3438153792710754 0.4334355904100794 -0.2480392830893763 0.2037671452423252 0.2909109464698327 -0.2855954200826543 -0.002227006947833121 -0.4293096679535784 0.2658764945305452 -0.4075898489985521 -0.3625928418362446 -0.09789381697577781 0.3071862533596335 -0.3013850588364387 -0.3786854184034145 0.4341719447953365 0.4227408774485775 4 5 2 1 6 4 5 4 2 6 4 2 4 7 6 4 4 0 5 2 4 0 5 2 1 4 0 4 9 3 4 4 0 9 5 4 0 9 5 1 4 4 8 7 6 4 4 8 9 3 4 8 0 7 3 4 0 8 4 3 4 4 8 2 7 4 8 0 2 7 4 8 0 4 2 user_eg3 rbox D5 c P2 qhull d eg-delaunay rbox D5 rbox c rbox P2 Results of d Delaunay triangulation by the convex hull of 33 points in 6-d: Number of input sites: 33 Number of Delaunay regions: 2 Number of non-simplicial Delaunay regions: 2 Statistics for: rbox "c D5" "P2 D5" | qhull d Number of points processed: 33 Number of hyperplanes created: 87 Number of facets in hull: 11 Number of distance tests for qhull: 826 Number of distance tests for merging: 3868 Number of distance tests for checking: 363 Number of merged facets: 296 CPU seconds to compute hull (after input): 0.001 Vertices and Delaunay regions of paraboloid from 'qhull d' via C++ classes 6 33 2 6 -0.5 -0.5 -0.5 -0.5 -0.5 1.25 -0.5 -0.5 -0.5 -0.5 0.5 1.25 -0.5 -0.5 -0.5 0.5 -0.5 1.25 -0.5 -0.5 -0.5 0.5 0.5 1.25 -0.5 -0.5 0.5 -0.5 -0.5 1.25 -0.5 -0.5 0.5 -0.5 0.5 1.25 -0.5 -0.5 0.5 0.5 -0.5 1.25 -0.5 -0.5 0.5 0.5 0.5 1.25 -0.5 0.5 -0.5 -0.5 -0.5 1.25 -0.5 0.5 -0.5 -0.5 0.5 1.25 -0.5 0.5 -0.5 0.5 -0.5 1.25 -0.5 0.5 -0.5 0.5 0.5 1.25 -0.5 0.5 0.5 -0.5 -0.5 1.25 -0.5 0.5 0.5 -0.5 0.5 1.25 -0.5 0.5 0.5 0.5 -0.5 1.25 -0.5 0.5 0.5 0.5 0.5 1.25 0.5 -0.5 -0.5 -0.5 -0.5 1.25 0.5 -0.5 -0.5 -0.5 0.5 1.25 0.5 -0.5 -0.5 0.5 -0.5 1.25 0.5 -0.5 -0.5 0.5 0.5 1.25 0.5 -0.5 0.5 -0.5 -0.5 1.25 0.5 -0.5 0.5 -0.5 0.5 1.25 0.5 -0.5 0.5 0.5 -0.5 1.25 0.5 -0.5 0.5 0.5 0.5 1.25 0.5 0.5 -0.5 -0.5 -0.5 1.25 0.5 0.5 -0.5 -0.5 0.5 1.25 0.5 0.5 -0.5 0.5 -0.5 1.25 0.5 0.5 -0.5 0.5 0.5 1.25 0.5 0.5 0.5 -0.5 -0.5 1.25 0.5 0.5 0.5 -0.5 0.5 1.25 0.5 0.5 0.5 0.5 -0.5 1.25 0.5 0.5 0.5 0.5 0.5 1.25 2 0 0 0 0 4 32 17 18 3 20 5 6 24 9 10 12 19 21 22 7 25 26 11 28 13 14 23 27 29 30 15 31 16 1 2 4 8 0 17 17 18 20 24 19 21 22 25 26 28 23 27 29 30 31 16 32 user_eg3 rbox '10 D2' eg-voronoi rbox 10 D2 Voronoi vertices and regions for rbox "10 D2" via C++ classes 2 15 10 1 -10.101 -10.101 -0.129438 -0.0724741 0.0826769 -0.239764 0.129526 1.71603 0.174036 0.531752 0.185142 0.388255 -0.906594 -0.296296 -0.195481 -0.0711189 -0.140758 0.723386 -0.16763 0.208062 0.0586831 0.0663207 0.0880634 0.105408 0.476159 -0.0316837 3.09421 -0.0647219 0.541052 0.211562 5 7 1 2 0 6 4 8 3 0 6 3 14 5 11 4 9 4 3 8 6 14 5 4 3 0 13 4 9 7 6 8 5 14 11 10 12 13 7 11 5 4 9 7 1 10 4 13 0 2 12 4 12 2 1 10 user_eg3 rbox "D5 c P2" qhull v eg-voronoi o rbox D5 c P2 Results of v Voronoi diagram by the convex hull of 33 points in 6-d: Number of Voronoi regions: 33 Number of Voronoi vertices: 2 Number of non-simplicial Voronoi vertices: 2 Statistics for: rbox "D5 c P2" | qhull v Number of points processed: 33 Number of hyperplanes created: 87 Number of facets in hull: 11 Number of distance tests for qhull: 826 Number of distance tests for merging: 3868 Number of distance tests for checking: 363 Number of merged facets: 296 CPU seconds to compute hull (after input): 0.001 Voronoi vertices and regions for 'qhull v' via C++ classes 5 3 33 1 -10.101 -10.101 -10.101 -10.101 -10.101 0 0 0 0 0 0.916667 0 0 0 0 2 0 2 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 Results of o 5 3 33 1 -10.101 -10.101 -10.101 -10.101 -10.101 0 0 0 0 0 0.9166666666666667 0 0 0 0 2 0 2 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 user_eg3 rbox '10 D2' eg-fifo rbox 10 D2 Voronoi vertices for rbox "10 D2" via QhullUser and qh_fprintf 2 14 -0.129438 -0.0724741 0.0826769 -0.239764 0.129526 1.71603 0.174036 0.531752 0.185142 0.388255 -0.906594 -0.296296 -0.195481 -0.0711189 -0.140758 0.723386 -0.16763 0.208062 0.0586831 0.0663207 0.0880634 0.105408 0.476159 -0.0316837 3.09421 -0.0647219 0.541052 0.211562 10 5 6 0 1 -1 5 4 7 2 -1 5 3 13 4 10 4 8 3 2 7 6 13 4 3 2 -1 12 4 8 6 5 7 5 13 10 9 11 12 7 10 4 3 8 6 0 9 4 12 -1 1 11 4 11 1 0 9 Hyperplanes for bounded facets between Voronoi regions via QhullUser and qh_fprintf 19 5 0 5 -0.301881 0.953346 0.00878913 5 0 7 0.0205153 0.99979 0.0751143 5 0 9 0.619259 0.785187 0.137061 5 1 5 0.799595 -0.600539 0.546971 5 1 3 0.964872 -0.262721 0.325862 5 2 6 0.22816 -0.973624 0.0825353 5 2 4 0.444671 0.895694 -0.430084 5 2 7 -0.945841 0.32463 0.0490754 5 3 5 -0.998643 0.0520745 -0.178237 5 3 7 0.687752 -0.725945 0.26633 5 3 4 0.999294 0.037557 -0.193884 5 4 6 -0.107584 -0.994196 0.268542 5 4 7 -0.997018 -0.0771644 0.214549 5 5 7 0.995061 -0.0992661 0.187455 5 6 7 -0.799364 0.600847 0.00706064 5 6 9 -0.228542 -0.973534 0.077977 5 6 8 -0.0126184 -0.99992 -0.0256728 5 7 9 0.593695 -0.80469 0.0185277 5 8 9 -0.467479 0.884004 0.250603 Hyperplanes for unbounded facets between Voronoi regions via QhullUser and qh_fprintf 4 5 0 8 0.719063 0.694945 0.107173 5 0 1 -0.385496 0.92271 -0.076093 5 1 4 0.992921 -0.118775 0.0752121 5 4 8 -0.0664014 -0.997793 0.140881 Message codes captured by qh_fprintf in QhullUser.cpp (qhull v Fo Ta): 9231 9271 9272 9272 9273 9274 9271 9272 9272 9273 9274 9271 9272 9272 9273 9274 9271 9272 9272 9273 9274 user_eg3 rbox D2 10 qhull v eg-fifo p Fi Fo rbox D2 rbox 10 Results of v Voronoi diagram by the convex hull of 10 points in 3-d: Number of Voronoi regions: 10 Number of Voronoi vertices: 14 Statistics for: rbox "10 D2" | qhull v Number of points processed: 10 Number of hyperplanes created: 28 Number of facets in hull: 16 Number of distance tests for qhull: 47 CPU seconds to compute hull (after input): 0 Voronoi vertices for 'qhull v' via C++ classes 2 14 -0.129438 -0.0724741 0.0826769 -0.239764 0.129526 1.71603 0.174036 0.531752 0.185142 0.388255 -0.906594 -0.296296 -0.195481 -0.0711189 -0.140758 0.723386 -0.16763 0.208062 0.0586831 0.0663207 0.0880634 0.105408 0.476159 -0.0316837 3.09421 -0.0647219 0.541052 0.211562 10 5 6 0 1 -1 5 4 7 2 -1 5 3 13 4 10 4 8 3 2 7 6 13 4 3 2 -1 12 4 8 6 5 7 5 13 10 9 11 12 7 10 4 3 8 6 0 9 4 12 -1 1 11 4 11 1 0 9 Hyperplanes for bounded facets between Voronoi regions via QhullUser and qh_fprintf 19 5 0 5 -0.301881 0.953346 0.00878913 5 0 7 0.0205153 0.99979 0.0751143 5 0 9 0.619259 0.785187 0.137061 5 1 5 0.799595 -0.600539 0.546971 5 1 3 0.964872 -0.262721 0.325862 5 2 6 0.22816 -0.973624 0.0825353 5 2 4 0.444671 0.895694 -0.430084 5 2 7 -0.945841 0.32463 0.0490754 5 3 5 -0.998643 0.0520745 -0.178237 5 3 7 0.687752 -0.725945 0.26633 5 3 4 0.999294 0.037557 -0.193884 5 4 6 -0.107584 -0.994196 0.268542 5 4 7 -0.997018 -0.0771644 0.214549 5 5 7 0.995061 -0.0992661 0.187455 5 6 7 -0.799364 0.600847 0.00706064 5 6 9 -0.228542 -0.973534 0.077977 5 6 8 -0.0126184 -0.99992 -0.0256728 5 7 9 0.593695 -0.80469 0.0185277 5 8 9 -0.467479 0.884004 0.250603 Hyperplanes for unbounded facets between Voronoi regions via QhullUser and qh_fprintf 4 5 0 8 0.719063 0.694945 0.107173 5 0 1 -0.385496 0.92271 -0.076093 5 1 4 0.992921 -0.118775 0.0752121 5 4 8 -0.0664014 -0.997793 0.140881 Message codes captured by qh_fprintf in QhullUser.cpp (qhull v Fo Ta): 9231 9271 9272 9272 9273 9274 9271 9272 9272 9273 9274 9271 9272 9272 9273 9274 9271 9272 9272 9273 9274 Results of p 2 14 -0.1294381801544404 -0.07247409101984709 0.08267689532419764 -0.2397644955865706 0.1295260566906467 1.716033573116839 0.1740355150742391 0.5317519038435656 0.1851415205797576 0.3882545794457364 -0.9065939866848106 -0.2962957610652136 -0.1954805620516264 -0.07111892482963184 -0.1407581310832469 0.7233857048236081 -0.1676297826663961 0.2080621273999384 0.05868313821742954 0.06632066014880161 0.08806341399736983 0.1054080604689984 0.4761588899009251 -0.03168366595227294 3.094213357897476 -0.064721945677682 0.5410515627308723 0.211561543495592 Results of Fi 19 5 0 5 -0.301880639203215 0.9533457293522944 0.008789126238507639 5 0 7 0.02051532578114256 0.9997895385570373 0.0751143044524602 5 0 9 0.619259133056969 0.7851866823409139 0.1370614663104577 5 1 5 0.7995952824356682 -0.6005392446015695 0.5469710423089691 5 1 3 0.9648718030091262 -0.2627211520946076 0.3258622775065155 5 2 6 0.2281595097543264 -0.9736237661995856 0.0825352874566877 5 2 4 0.4446710312325422 0.895693962234081 -0.4300843534994401 5 2 7 -0.9458410914974846 0.324629988810102 0.04907537812572163 5 3 5 -0.9986432053419565 0.05207445078292225 -0.1782370644858235 5 3 7 0.6877523324625964 -0.7259454037269318 0.2663295190946446 5 3 4 0.99929448732669 0.03755699133966526 -0.1938837324602515 5 4 6 -0.1075842248297359 -0.9941959739245502 0.2685422477498993 5 4 7 -0.9970183790688238 -0.07716444646969949 0.2145489484590234 5 5 7 0.995060920624513 -0.09926612839179721 0.1874553677160639 5 6 7 -0.7993641842155071 0.6008468199079334 0.007060641163779156 5 6 9 -0.2285415587894344 -0.9735341575446109 0.07797696388863322 5 6 8 -0.01261839651625044 -0.9999203848653946 -0.02567278177543585 5 7 9 0.5936952885926361 -0.8046899429612046 0.01852766555277021 5 8 9 -0.4674785097727935 0.8840044360186254 0.2506025495170938 Results of Fo 4 5 0 8 0.7190625207842074 0.6949453872092838 0.1071733734620183 5 0 1 -0.3854955578888163 0.922709691532494 -0.07609298438083834 5 1 4 0.9929212365203528 -0.1187746524595787 0.0752121188850394 5 4 8 -0.06640144810487485 -0.9977929883946747 0.1408811441173877 set +v === check front ends and examples Fri, Jul 24, 2020 10:27:18 PM ================== qconvex - qconvex -- compute the convex hull http://www.qhull.org 2020.2 2020/07/24 input (stdin): first lines: dimension and number of points (or vice-versa). other lines: point coordinates, best if one point per line comments: start with a non-numeric character options: Qc - keep coplanar points with nearest facet Qi - keep interior points with nearest facet QJ - joggled input instead of merged facets Qt - triangulated output Qhull control options: Qa - allow input with fewer or more points than coordinates Qbk:n - scale coord k so that low bound is n QBk:n - scale coord k so that upper bound is n (QBk is 0.5) QbB - scale input to unit cube centered at the origin Qbk:0Bk:0 - remove k-th coordinate from input QJn - randomly joggle input in range [-n,n] QRn - random rotation (n=seed, n=0 time, n=-1 time/no rotate) Qs - search all points for the initial simplex Qhull extra options: QGn - good facet if visible from point n, -n for not visible QVn - good facet if it includes point n, -n if not Qw - allow option warnings Q12 - allow wide facets and wide dupridge Q14 - merge pinched vertices that create a dupridge T options: TFn - report summary when n or more facets created TI file - input file, may be enclosed in single quotes TO file - output file, may be enclosed in single quotes Ts - statistics Tv - verify result: structure, convexity, and in-circle test Tz - send all output to stdout Trace options: T4 - trace at level n, 4=all, 5=mem/gauss, -1= events Ta - annotate output with message codes TAn - stop qhull after adding n vertices TCn - stop qhull after building cone for point n TVn - stop qhull after adding point n, -n for before Tc - check frequently during execution Tf - flush each qh_fprintf for debugging segfaults TPn - turn on tracing when point n added to hull TMn - turn on tracing at merge n TWn - trace merge facets when width > n Precision options: Cn - radius of centrum (roundoff added). Merge facets if non-convex An - cosine of maximum angle. Merge facets if cosine > n or non-convex C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge Rn - randomly perturb computations by a factor of [1-n,1+n] Un - max distance below plane for a new, coplanar point Wn - min facet width for outside point (before roundoff) Output formats (may be combined; if none, produces a summary to stdout): f - facet dump G - Geomview output (see below) i - vertices incident to each facet m - Mathematica output (2-d and 3-d) n - normals with offsets o - OFF file format (dim, points and facets) p - point coordinates s - summary (stderr) More formats: Fa - area for each facet FA - compute total area and volume for option 's' Fc - count plus coplanar points for each facet use 'Qc' (default) for coplanar and 'Qi' for interior FC - centrum for each facet Fd - use cdd format for input (homogeneous with offset first) FD - use cdd format for numeric output (offset first) FF - facet dump without ridges Fi - inner plane for each facet FI - ID for each facet Fm - merge count for each facet (511 max) FM - Maple output (2-d and 3-d) Fn - count plus neighboring facets for each facet FN - count plus neighboring facets for each point Fo - outer plane (or max_outside) for each facet FO - options and precision constants FP - nearest vertex for each coplanar point FQ - command used for qconvex Fs - summary: #int (8), dimension, #points, tot vertices, tot facets, output: #vertices, #facets, #coplanars, #nonsimplicial #real (2), max outer plane, min vertex FS - sizes: #int (0) #real (2) tot area, tot volume Ft - triangulation with centrums for non-simplicial facets (OFF format) Fv - count plus vertices for each facet FV - average of vertices (a feasible point for 'H') Fx - extreme points (in order for 2-d) Geomview output (2-d, 3-d, and 4-d) Ga - all points as dots Gp - coplanar points and vertices as radii Gv - vertices as spheres Gc - centrums GDn - drop dimension n in 3-d and 4-d output Gh - hyperplane intersections Gi - inner planes only Gn - no planes Go - outer planes only Gr - ridges Print options: PAn - keep n largest facets by area Pdk:n - drop facet if normal[k] <= n (default 0.0) PDk:n - drop facet if normal[k] >= n PFn - keep facets whose area is at least n Pg - print good facets (needs 'QGn' or 'QVn') PG - print neighbors of good facets PMn - keep n facets with most merges Po - force output. If error, output neighborhood of facet Pp - do not report precision problems . - list of all options - - one line descriptions of all options -? - help with examples -V - version qconvex . Qhull 2020.2 2020/07/24 Except for 'F.' and 'PG', upper-case options take an argument. facet-dump Geomview incidences mathematica normals off-format points summary Farea FArea-total Fcoplanars FCentrums Fd-cdd-in FD-cdd-out FFacets-xridge Finner FIDs Fmerges FMaple Fneighbors FNeigh-vertex Fouter FOptions FPoint-near FQhull Fsummary FSize Ftriangles Fvertices FVertex-ave Fxtremes Gall-points Gcentrums GDrop-dim Ghyperplanes Ginner Gno-planes Gouter Gpoints Gridges Gvertices PArea-keep Pdrop-d0:0D0 PFacet-area-keep Pgood PGood-neighbors PMerge-keep Poutput-forced Pprecision-not Qallow-short QbBound-0:0.5 QbB-scale-box Qcoplanar QGood-point Qinterior QJoggle QRotate Qsearch-all Qtriangulate QVertex-good Qwarn-allow Q12-allow-wide Q14-merge-pinched TFacet-log TInput-file TOutput-file Tstatistics Tverify Tz-stdout T4-trace Tannotate TAdd-stop Tcheck-often TCone-stop Tflush TMerge-trace TPoint-trace TVertex-stop TWide-trace Angle-max Centrum-size Random-dist Ucoplanar-max Wide-outside qconvex -? # [mar'19] isatty does not work for Git for Windows qconvex -- compute the convex hull. Qhull 2020.2 2020/07/24 input (stdin): dimension, number of points, point coordinates comments start with a non-numeric character options (qconvex.htm): Qt - triangulated output QJ - joggled input instead of merged facets Tv - verify result: structure, convexity, and point inclusion . - concise list of all options - - one-line description of each option -? - this message -V - version output options (subset): s - summary of results (default) i - vertices incident to each facet n - normals with offsets p - vertex coordinates (if 'Qc', includes coplanar points) FA - report total area and volume FS - total area and volume Fx - extreme points (convex hull vertices) G - Geomview output (2-d, 3-d, and 4-d) m - Mathematica output (2-d and 3-d) o - OFF format (dim, n, points, facets) QVn - print facets that include point n, -n if not TI file - input file, may be enclosed in single quotes TO file - output file, may be enclosed in single quotes examples: rbox c D2 | qconvex s n rbox c D2 | qconvex i rbox c D2 | qconvex o rbox 1000 s | qconvex s Tv FA rbox c d D2 | qconvex s Qc Fx rbox y 1000 W0 | qconvex Qc s n rbox y 1000 W0 | qconvex s QJ rbox d G1 D12 | qconvex QR0 FA Pp rbox c D7 | qconvex FA TF1000 rbox c D3 | qconvex s n Qt Convex hull of 8 points in 3-d: Number of vertices: 8 Number of facets: 12 Number of triangulated facets: 6 Statistics for: rbox c D3 | qconvex s n Qt Number of points processed: 8 Number of hyperplanes created: 11 Number of distance tests for qhull: 34 Number of distance tests for merging: 90 Number of distance tests for checking: 48 Number of merged facets: 6 CPU seconds to compute hull (after input): 0 4 12 -0 -0 -1 -0.5 -0 -0 -1 -0.5 0 -1 0 -0.5 0 -1 0 -0.5 1 -0 -0 -0.5 1 -0 -0 -0.5 -1 -0 -0 -0.5 -1 -0 -0 -0.5 0 1 -0 -0.5 0 1 -0 -0.5 -0 -0 1 -0.5 -0 -0 1 -0.5 rbox c D2 | qconvex s i Convex hull of 4 points in 2-d: Number of vertices: 4 Number of facets: 4 Statistics for: rbox c D2 | qconvex s i Number of points processed: 4 Number of hyperplanes created: 6 Number of distance tests for qhull: 5 CPU seconds to compute hull (after input): 0 4 0 2 1 0 2 3 3 1 rbox c D2 | qconvex s n Convex hull of 4 points in 2-d: Number of vertices: 4 Number of facets: 4 Statistics for: rbox c D2 | qconvex s n Number of points processed: 4 Number of hyperplanes created: 6 Number of distance tests for qhull: 5 CPU seconds to compute hull (after input): 0 3 4 -0 -1 -0.5 -1 0 -0.5 1 -0 -0.5 0 1 -0.5 rbox c D2 | qconvex o 2 4 4 4 -0.5 -0.5 -0.5 0.5 0.5 -0.5 0.5 0.5 2 0 2 2 1 0 2 2 3 2 3 1 rbox 1000 s | qconvex s Tv FA Convex hull of 1000 points in 3-d: Number of vertices: 1000 Number of facets: 1996 Statistics for: rbox 1000 s | qconvex s Tv FA Number of points processed: 1000 Number of hyperplanes created: 5544 Number of distance tests for qhull: 25487 CPU seconds to compute hull (after input): 0.003 Total facet area: 3.1201951 Total volume: 0.51650274 qhull output completed. Verifying that 1000 points are below 2.1e-15 of the nearest facet. rbox c d D2 | qconvex s Qc Fx Convex hull of 8 points in 2-d: Number of vertices: 4 Number of coplanar points: 4 Number of facets: 4 Statistics for: rbox c d D2 | qconvex s Qc Fx Number of points processed: 4 Number of hyperplanes created: 6 Number of distance tests for qhull: 35 CPU seconds to compute hull (after input): 0 4 0 2 3 1 rbox y 1000 W0 | qconvex Qc s n Convex hull of 1004 points in 3-d: Number of vertices: 4 Number of coplanar points: 1000 Number of facets: 4 Statistics for: rbox y 1000 W0 | qconvex Qc s n Number of points processed: 4 Number of hyperplanes created: 4 Number of distance tests for qhull: 11000 CPU seconds to compute hull (after input): 0.001 4 4 0.2135848119563837 0.1168704340428168 0.9699086708284446 -0.09806074564261894 0.08553875579270347 -0.8316435307282575 -0.5486822022403076 -0.1234144150397865 -0.749541668500822 -0.02779445272382575 -0.6613733859014791 -0.2159556159595279 0.3120013537900506 0.9498158823230658 -0.02247097950761911 -0.02453689035981485 rbox y 1000 W0 | qconvex s QJ Convex hull of 1004 points in 3-d: Number of vertices: 51 Number of facets: 98 Statistics for: rbox y 1000 W0 | qconvex s QJ Number of points processed: 52 Number of hyperplanes created: 180 Number of distance tests for qhull: 6420 CPU seconds to compute hull (after input): 0 Input joggled by: 2.1e-11 rbox d G1 D12 | qconvex QR0 FA Convex hull of 24 points in 12-d: Number of vertices: 24 Number of facets: 4096 Statistics for: rbox d G1 D12 | qconvex QR0 FA QR1595644039 Number of points processed: 24 Number of hyperplanes created: 4107 Number of distance tests for qhull: 4215 Number of distance tests for merging: 121142 Number of distance tests for checking: 98304 Number of merged facets: 2036 CPU seconds to compute hull (after input): 0.024 Approximate facet area: 0.00035546337 Approximate volume: 8.5511197e-06 rbox c D6 | qconvex s FA TF500 At 22:27:19 & 0.003 CPU secs, qhull has created 543 facets and merged 289. The current hull contains 91 facets and 23 vertices. There are 41 outside points. Next is point p27(v24), 0.64 above f107. At 22:27:19 & 0.004 CPU secs, qhull has created 1061 facets and merged 737. The current hull contains 69 facets and 33 vertices. There are 31 outside points. Next is point p22(v34), 0.52 above f610. At 22:27:19 & 0.006 CPU secs, qhull has created 1567 facets and merged 1216. The current hull contains 37 facets and 48 vertices. There are 16 outside points. Next is point p9(v49), 0.45 above f1061. At 22:27:19 & 0.006 CPU secs, qhull has created 1819 facets and merged 1462. The current hull contains 12 facets and 64 vertices. Last point was p11 Convex hull of 64 points in 6-d: Number of vertices: 64 Number of facets: 12 Number of non-simplicial facets: 12 Statistics for: rbox c D6 | qconvex s FA TF500 Number of points processed: 64 Number of hyperplanes created: 358 Number of distance tests for qhull: 2515 Number of distance tests for merging: 14300 Number of distance tests for checking: 0 Number of merged facets: 1462 First post-merge with 'C3.5e-15' and 'A1.8e+308' At 22:27:19 & 0.006 CPU secs, qhull has created 1819 facets and merged 1462. The current hull contains 12 facets and 64 vertices. Last point was p11 Testing all coplanar points. computing area of each facet and volume of the convex hull Convex hull of 64 points in 6-d: Number of vertices: 64 Number of facets: 12 Number of non-simplicial facets: 12 Statistics for: rbox c D6 | qconvex s FA TF500 Number of points processed: 64 Number of hyperplanes created: 358 Number of distance tests for qhull: 2515 Number of distance tests for merging: 14420 Number of distance tests for checking: 768 Number of merged facets: 1462 CPU seconds to compute hull (after input): 0.006 Approximate facet area: 12 Approximate volume: 1 rbox c D7 | qconvex s FA TF1000 At 22:27:19 & 0.003 CPU secs, qhull has created 1048 facets and merged 469. The current hull contains 230 facets and 24 vertices. There are 104 outside points. Next is point p79(v25), 0.66 above f145. At 22:27:19 & 0.005 CPU secs, qhull has created 2146 facets and merged 1272. The current hull contains 273 facets and 31 vertices. There are 97 outside points. Next is point p120(v32), 0.54 above f437. At 22:27:19 & 0.008 CPU secs, qhull has created 3310 facets and merged 2244. The current hull contains 243 facets and 36 vertices. There are 92 outside points. Next is point p60(v37), 0.54 above f1338. At 22:27:19 & 0.01 CPU secs, qhull has created 4322 facets and merged 3099. The current hull contains 249 facets and 42 vertices. There are 86 outside points. Next is point p30(v43), 0.54 above f2005. At 22:27:19 & 0.013 CPU secs, qhull has created 5491 facets and merged 4196. The current hull contains 186 facets and 48 vertices. There are 80 outside points. Next is point p21(v49), 0.5 above f2995. At 22:27:19 & 0.015 CPU secs, qhull has created 6589 facets and merged 5175. The current hull contains 194 facets and 53 vertices. There are 75 outside points. Next is point p56(v54), 0.28 above f3731. At 22:27:19 & 0.018 CPU secs, qhull has created 7867 facets and merged 6337. The current hull contains 203 facets and 60 vertices. There are 68 outside points. Next is point p76(v61), 0.29 above f5879. At 22:27:19 & 0.021 CPU secs, qhull has created 8971 facets and merged 7362. The current hull contains 179 facets and 67 vertices. There are 61 outside points. Next is point p80(v68), 0.23 above f7175. At 22:27:19 & 0.024 CPU secs, qhull has created 9984 facets and merged 8352. The current hull contains 104 facets and 77 vertices. There are 51 outside points. Next is point p96(v78), 0.41 above f6748. At 22:27:19 & 0.028 CPU secs, qhull has created 10990 facets and merged 9326. The current hull contains 54 facets and 90 vertices. There are 38 outside points. Next is point p18(v91), 0.41 above f10178. At 22:27:19 & 0.03 CPU secs, qhull has created 11996 facets and merged 10295. The current hull contains 34 facets and 114 vertices. There are 14 outside points. Next is point p19(v115), 0.38 above f11792. At 22:27:19 & 0.032 CPU secs, qhull has created 12860 facets and merged 11072. The current hull contains 14 facets and 128 vertices. Last point was p77 Convex hull of 128 points in 7-d: Number of vertices: 128 Number of facets: 14 Number of non-simplicial facets: 14 Statistics for: rbox c D7 | qconvex s FA TF1000 Number of points processed: 128 Number of hyperplanes created: 1789 Number of distance tests for qhull: 10122 Number of distance tests for merging: 87203 Number of distance tests for checking: 0 Number of merged facets: 11072 First post-merge with 'C4.4e-15' and 'A1.8e+308' At 22:27:19 & 0.033 CPU secs, qhull has created 12860 facets and merged 11072. The current hull contains 14 facets and 128 vertices. Last point was p77 Testing all coplanar points. computing area of each facet and volume of the convex hull Convex hull of 128 points in 7-d: Number of vertices: 128 Number of facets: 14 Number of non-simplicial facets: 14 Statistics for: rbox c D7 | qconvex s FA TF1000 Number of points processed: 128 Number of hyperplanes created: 1789 Number of distance tests for qhull: 10122 Number of distance tests for merging: 87371 Number of distance tests for checking: 1792 Number of merged facets: 11072 CPU seconds to compute hull (after input): 0.033 Approximate facet area: 14 Approximate volume: 1 rbox d G1 D12 | qconvex QR0 FA Pp Convex hull of 24 points in 12-d: Number of vertices: 24 Number of facets: 4096 Statistics for: rbox d G1 D12 | qconvex QR0 FA Pp QR1595644039 Number of points processed: 24 Number of hyperplanes created: 4107 Number of distance tests for qhull: 4215 Number of distance tests for merging: 121142 Number of distance tests for checking: 98304 Number of merged facets: 2036 CPU seconds to compute hull (after input): 0.022 Approximate facet area: 0.00035546337 Approximate volume: 8.5511197e-06 rbox c P0 d D2 | qconvex p Fa Fc FP FI Fn FN FS Fv Fx 2 8 -0.5 -0.5 -0.5 0.5 0.5 -0.5 0.5 0.5 0 -0.5 0 0.5 -0.5 0 0.5 0 4 1 1 1 1 4 1 5 1 7 1 8 1 6 4 3 5 1 0.5 2 7 2 0.5 4 8 4 0.5 4 6 5 0.5 4 1 2 4 5 4 2 1 2 2 0 3 2 0 3 2 1 2 9 0 2 0 1 2 1 3 2 2 0 2 3 2 1 0 1 3 1 1 1 2 0 2 4 1 4 2 3 1 2 2 1 2 4 3 2 4 2 4 1 3 4 2 rbox c d D2 | qconvex s i QV0 Convex hull of 8 points in 2-d: Number of vertices: 4 Number of facets: 4 Number of 'good' facets: 2 Statistics for: rbox c d D2 | qconvex s i QV0 Number of points processed: 4 Number of hyperplanes created: 6 Number of distance tests for qhull: 35 CPU seconds to compute hull (after input): 0 2 0 2 1 0 rbox c | qconvex Q0 QH6029 qhull option error: option 'Q0' is not used with this program. It may be used with qhull. While executing: | qconvex Q0 Options selected for Qhull 2020.2 2020/07/24: run-id 213579737 _maxoutside 0 qvoronoi - qvoronoi -- compute the Voronoi diagram http://www.qhull.org 2020.2 2020/07/24 input (stdin): first lines: dimension and number of points (or vice-versa). other lines: point coordinates, best if one point per line comments: start with a non-numeric character options: Qu - compute furthest-site Voronoi diagram Qhull control options: Qa - allow input with fewer or more points than coordinates QRn - random rotation (n=seed, n=0 time, n=-1 time/no rotate) Qs - search all points for the initial simplex Qz - add point-at-infinity to Voronoi diagram Qhull extra options: QGn - Voronoi vertices if visible from point n, -n if not QVn - Voronoi vertices for input point n, -n if not Qw - allow option warnings Q12 - allow wide facets and wide dupridge Q14 - merge pinched vertices that create a dupridge T options: TFn - report summary when n or more facets created TI file - input file, may be enclosed in single quotes TO file - output file, may be enclosed in single quotes Ts - statistics Tv - verify result: structure, convexity, and in-circle test Tz - send all output to stdout Trace options: T4 - trace at level n, 4=all, 5=mem/gauss, -1= events Ta - annotate output with message codes TAn - stop qhull after adding n vertices TCn - stop qhull after building cone for point n TVn - stop qhull after adding point n, -n for before Tc - check frequently during execution Tf - flush each qh_fprintf for debugging segfaults TPn - turn on tracing when point n added to hull TMn - turn on tracing at merge n TWn - trace merge facets when width > n Precision options: Cn - radius of centrum (roundoff added). Merge facets if non-convex An - cosine of maximum angle. Merge facets if cosine > n or non-convex C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge Rn - randomly perturb computations by a factor of [1-n,1+n] Wn - min facet width for non-coincident point (before roundoff) Output formats (may be combined; if none, summary to stdout): p - Voronoi vertices s - summary to stderr f - facet dump i - Delaunay regions (use 'Pp' to avoid warning) o - OFF format (dim, Voronoi vertices, and Voronoi regions) More formats: Fc - count plus coincident points (by Voronoi vertex) Fd - use cdd format for input (homogeneous with offset first) FD - use cdd format for output (offset first) FF - facet dump without ridges Fi - separating hyperplanes for bounded Voronoi regions FI - ID for each Voronoi vertex Fm - merge count for each Voronoi vertex (511 max) Fn - count plus neighboring Voronoi vertices for each Voronoi vertex FN - count and Voronoi vertices for each Voronoi region Fo - separating hyperplanes for unbounded Voronoi regions FO - options and precision constants FP - nearest point and distance for each coincident point FQ - command used for qvoronoi Fs - summary: #int (8), dimension, #points, tot vertices, tot facets, for output: #Voronoi regions, #Voronoi vertices, #coincident points, #non-simplicial regions #real (2), max outer plane and min vertex Fv - Voronoi diagram as Voronoi vertices between adjacent input sites Fx - extreme points of Delaunay triangulation (on convex hull) Geomview output (2-d only) Ga - all points as dots Gp - coplanar points and vertices as radii Gv - vertices as spheres Gc - centrums GDn - drop dimension n in 3-d and 4-d output Gh - hyperplane intersections Gi - inner planes only Gn - no planes Go - outer planes only Gr - ridges Print options: PAn - keep n largest Voronoi vertices by 'area' Pdk:n - drop facet if normal[k] <= n (default 0.0) PDk:n - drop facet if normal[k] >= n PFn - keep Voronoi vertices whose 'area' is at least n Pg - print good Voronoi vertices (needs 'QGn' or 'QVn') PG - print neighbors of good Voronoi vertices PMn - keep n Voronoi vertices with most merges Po - force output. If error, output neighborhood of facet Pp - do not report precision problems . - list of all options - - one line descriptions of all options -? - help with examples -V - version qvoronoi . Qhull 2020.2 2020/07/24 Except for 'F.' and 'PG', upper-case options take an argument. facet-dump Geomview i-delaunay off-format p-vertices summary Fcoincident Fd-cdd-in FD-cdd-out FF-dump-xridge Fi-bounded FIDs Fmerges Fneighbors FNeigh-region Fo-unbounded FOptions FPoint-near FQvoronoi Fsummary Fvoronoi Fxtremes Gall-points Gcentrums GDrop-dim Ghyperplanes Ginner Gno-planes Gouter Gpoints Gridges Gvertices PArea-keep Pdrop-d0:0D0 PFacet-area-keep Pgood PGood-neighbors PMerge-keep Poutput-forced Pprecision-not Qallow-short QG-vertex-good QRotate Qsearch-all Qupper-voronoi QV-point-good Qwarn-allow Qzinfinite Q12-allow-wide Q14-merge-pinched TFacet-log TInput-file TOutput-file Tstatistics Tverify Tz-stdout T4-trace Tannotate TAdd-stop Tcheck-often TCone-stop Tflush TMerge-trace TPoint-trace TVertex-stop TWide-trace Angle-max Centrum-size Random-dist Wide-outside qvoronoi -? # [mar'19] isatty does not work for Git for Windows qvoronoi -- compute the Voronoi diagram. Qhull 2020.2 2020/07/24 input (stdin): dimension, number of points, point coordinates comments start with a non-numeric character options (qvoronoi.htm): Qu - compute furthest-site Voronoi diagram Tv - verify result: structure, convexity, and in-circle test . - concise list of all options - - one-line description of all options -? - this message -V - version output options (subset): Fi - separating hyperplanes for bounded regions, 'Fo' for unbounded FN - count and Voronoi vertices for each Voronoi region Fv - Voronoi diagram as Voronoi vertices between adjacent input sites G - Geomview output (2-d only) o - OFF file format (dim, Voronoi vertices, and Voronoi regions) p - Voronoi vertices QVn - Voronoi vertices for input point n, -n if not s - summary of results (default) TI file - input file, may be enclosed in single quotes TO file - output file, may be enclosed in single quotes examples: rbox c P0 D2 | qvoronoi s o rbox c P0 D2 | qvoronoi Fi rbox c P0 D2 | qvoronoi Fo rbox c P0 D2 | qvoronoi Fv rbox c P0 D2 | qvoronoi s Qu Fv rbox c P0 D2 | qvoronoi Qu Fo rbox c G1 d D2 | qvoronoi s p rbox c P0 D2 | qvoronoi s Fv QV0 rbox c P0 D2 | qvoronoi s o Voronoi diagram by the convex hull of 5 points in 3-d: Number of Voronoi regions: 5 Number of Voronoi vertices: 4 Statistics for: rbox c P0 D2 | qvoronoi s o Number of points processed: 5 Number of hyperplanes created: 6 Number of facets in hull: 5 Number of distance tests for qhull: 7 Number of distance tests for merging: 34 Number of distance tests for checking: 25 Number of merged facets: 1 CPU seconds to compute hull (after input): 0 2 5 5 1 -10.101 -10.101 0 -0.5 -0.5 0 0.5 0 0 0.5 4 4 2 1 3 3 2 0 1 3 4 0 2 3 3 0 1 3 4 0 3 rbox c P0 D2 | qvoronoi Fi Tv 4 5 0 3 0.7071067811865475 -0.7071067811865475 -0.3535533905932737 5 0 1 -0.7071067811865475 -0.7071067811865475 -0.3535533905932737 5 0 2 -0.7071067811865475 0.7071067811865475 -0.3535533905932737 5 0 4 0.7071067811865475 0.7071067811865475 -0.3535533905932737 Voronoi ridge statistics 4 bounded ridges 0 max. distance of midpoint to ridge 4 bounded ridges with ok normal 2.2e-16 ave. angle to ridge 2.2e-16 max. angle to ridge Output completed. Verifying that all points are below outer planes of all facets. Will make 20 distance computations. rbox c P0 D2 | qvoronoi Fo Tv 4 5 1 2 -1 0 -0.5 5 1 3 1 -0 -0 5 2 4 1 -0 -0 5 3 4 -1 0 0.5 Output completed. Verifying that all points are below outer planes of all facets. Will make 20 distance computations. rbox c P0 D2 | qvoronoi Fv 8 4 0 3 1 3 4 0 1 1 2 4 0 2 2 4 4 0 4 3 4 4 1 2 0 2 4 1 3 0 1 4 2 4 0 4 4 3 4 0 3 rbox c P0 D2 | qvoronoi s Qu Fv Furthest-site Voronoi vertices by the convex hull of 5 points in 3-d: Number of Voronoi regions: 5 Number of Voronoi vertices: 1 Number of non-simplicial Voronoi vertices: 1 Statistics for: rbox c P0 D2 | qvoronoi s Qu Fv Number of points processed: 5 Number of hyperplanes created: 6 Number of facets in hull: 5 Number of distance tests for qhull: 7 Number of distance tests for merging: 34 Number of distance tests for checking: 25 Number of merged facets: 1 CPU seconds to compute hull (after input): 0 4 4 1 2 0 1 4 1 3 0 1 4 2 4 0 1 4 3 4 0 1 rbox c P0 D2 | qvoronoi s Qu Qt Fv Furthest-site Voronoi vertices by the convex hull of 5 points in 3-d: Number of Voronoi regions: 5 Number of Voronoi vertices: 2 Number of triangulated facets: 1 Statistics for: rbox c P0 D2 | qvoronoi s Qu Qt Fv Number of points processed: 5 Number of hyperplanes created: 6 Number of facets in hull: 6 Number of distance tests for qhull: 7 Number of distance tests for merging: 34 Number of distance tests for checking: 25 Number of merged facets: 1 CPU seconds to compute hull (after input): 0 4 4 1 3 0 2 4 1 2 0 1 4 2 4 0 1 4 3 4 0 2 rbox c P0 D2 | qvoronoi Qu Fo 4 5 1 2 -0 1 0 5 1 3 1 -0 -0 5 2 4 1 -0 -0 5 3 4 -0 1 -0 rbox c G1 d D2 | qvoronoi s p Voronoi diagram by the convex hull of 8 points in 3-d: Number of Voronoi regions: 8 Number of Voronoi vertices: 9 Number of non-simplicial Voronoi vertices: 1 Statistics for: rbox c G1 d D2 | qvoronoi s p Number of points processed: 8 Number of hyperplanes created: 16 Number of facets in hull: 10 Number of distance tests for qhull: 41 Number of distance tests for merging: 108 Number of distance tests for checking: 72 Number of merged facets: 3 CPU seconds to compute hull (after input): 0 2 9 0 -1.75 -1.75 0 -0.5833333333333334 -0.5833333333333333 0 1.75 -0.5833333333333333 0.5833333333333334 1.75 0 0.5833333333333334 -0.5833333333333333 0.5833333333333334 0.5833333333333333 0 0 rbox c G1 d D2 | qvoronoi QJ p 2 10 -2.57276422388486e-11 1.749999999802917 -2.05463598231932e-11 -1.750000000331276 0.5833333333083517 -0.5833333333052267 1.862254794815499e-11 -7.815052443180038e-11 1.750000000002628 3.498100747664324e-11 0.5833333333132078 0.5833333333796981 -0.5833333332888888 0.5833333333317835 -7.592293460589872e-11 -7.815050692933323e-11 -1.750000000049026 2.293196879294717e-11 -0.5833333333977307 -0.5833333333229861 rbox c P-0.1 P+0.1 P+0.1 D2 | qvoronoi s Fc FP FQ Fn FN Voronoi diagram by the convex hull of 7 points in 3-d: Number of Voronoi regions: 6 Number of nearly incident points: 1 Number of Voronoi vertices: 4 Number of non-simplicial Voronoi vertices: 2 Statistics for: rbox c P-0.1 P+0.1 P+0.1 D2 | qvoronoi s Fc FP FQ Fn FN Number of points processed: 6 Number of hyperplanes created: 7 Number of facets in hull: 5 Number of distance tests for qhull: 31 Number of distance tests for merging: 54 Number of distance tests for checking: 36 Number of merged facets: 3 CPU seconds to compute hull (after input): 0 4 0 1 1 0 0 1 2 1 8 0 rbox c P-0.1 P+0.1 P+0.1 D2 | qvoronoi s Fc FP FQ Fn FN 4 3 -1 2 3 3 -1 2 3 4 -1 0 3 1 4 0 -1 2 1 7 3 3 2 0 1 1 3 3 1 2 3 0 -1 2 3 3 -1 0 3 1 -1 2 3 1 -1 3 rbox P0 c D2 | qvoronoi s Fv QV0 Voronoi diagram by the convex hull of 5 points in 3-d: Number of Voronoi regions: 5 Number of 'good' Voronoi vertices: 4 Statistics for: rbox P0 c D2 | qvoronoi s Fv QV0 Number of points processed: 5 Number of hyperplanes created: 6 Number of facets in hull: 5 Number of distance tests for qhull: 7 Number of distance tests for merging: 34 Number of distance tests for checking: 25 Number of merged facets: 1 CPU seconds to compute hull (after input): 0 4 4 0 3 1 3 4 0 1 1 2 4 0 2 2 4 4 0 4 3 4 qdelaunay - qdelaunay -- compute the Delaunay triangulation http://www.qhull.org 2020.2 2020/07/24 input (stdin): first lines: dimension and number of points (or vice-versa). other lines: point coordinates, best if one point per line comments: start with a non-numeric character options: QJ - joggled input instead of merged facets Qt - triangulated output Qu - compute furthest-site Delaunay triangulation Qhull control options: Qa - allow input with fewer or more points than coordinates QJn - randomly joggle input in range [-n,n] QRn - random rotation (n=seed, n=0 time, n=-1 time/no rotate) Qs - search all points for the initial simplex Qz - add point-at-infinity to Delaunay triangulation Qhull extra options: QGn - print Delaunay region if visible from point n, -n if not QVn - print Delaunay regions that include point n, -n if not Qw - allow option warnings Q12 - allow wide facets and wide dupridge Q14 - merge pinched vertices that create a dupridge T options: TFn - report summary when n or more facets created TI file - input file, may be enclosed in single quotes TO file - output file, may be enclosed in single quotes Ts - statistics Tv - verify result: structure, convexity, and in-circle test Tz - send all output to stdout Trace options: T4 - trace at level n, 4=all, 5=mem/gauss, -1= events Ta - annotate output with message codes TAn - stop qhull after adding n vertices TCn - stop qhull after building cone for point n TVn - stop qhull after adding point n, -n for before Tc - check frequently during execution Tf - flush each qh_fprintf for debugging segfaults TPn - turn on tracing when point n added to hull TMn - turn on tracing at merge n TWn - trace merge facets when width > n Precision options: Cn - radius of centrum (roundoff added). Merge facets if non-convex An - cosine of maximum angle. Merge facets if cosine > n or non-convex C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge Rn - randomly perturb computations by a factor of [1-n,1+n] Wn - min facet width for outside point (before roundoff) Output formats (may be combined; if none, produces a summary to stdout): f - facet dump G - Geomview output (see below) i - vertices incident to each Delaunay region m - Mathematica output (2-d only, lifted to a paraboloid) o - OFF format (dim, points, and facets as a paraboloid) p - point coordinates (lifted to a paraboloid) s - summary (stderr) More formats: Fa - area for each Delaunay region FA - compute total area for option 's' Fc - count plus coincident points for each Delaunay region Fd - use cdd format for input (homogeneous with offset first) FD - use cdd format for numeric output (offset first) FF - facet dump without ridges FI - ID of each Delaunay region Fm - merge count for each Delaunay region (511 max) FM - Maple output (2-d only, lifted to a paraboloid) Fn - count plus neighboring region for each Delaunay region FN - count plus neighboring region for each point FO - options and precision constants FP - nearest point and distance for each coincident point FQ - command used for qdelaunay Fs - summary: #int (8), dimension, #points, tot vertices, tot facets, output: #vertices, #Delaunay regions, #coincident points, #non-simplicial regions #real (2), max outer plane, min vertex FS - sizes: #int (0) #real (2), tot area, 0 Fv - count plus vertices for each Delaunay region Fx - extreme points of Delaunay triangulation (on convex hull) Geomview output (2-d and 3-d points lifted to a paraboloid) Ga - all points as dots Gp - coplanar points and vertices as radii Gv - vertices as spheres Gc - centrums GDn - drop dimension n in 3-d and 4-d output Gh - hyperplane intersections Gi - inner planes only Gn - no planes Go - outer planes only Gr - ridges Gt - transparent outer ridges to view 3-d Delaunay Print options: PAn - keep n largest Delaunay regions by area Pdk:n - drop facet if normal[k] <= n (default 0.0) PDk:n - drop facet if normal[k] >= n PFn - keep Delaunay regions whose area is at least n Pg - print good Delaunay regions (needs 'QGn' or 'QVn') PG - print neighbors of good regions (needs 'QGn' or 'QVn') PMn - keep n Delaunay regions with most merges Po - force output. If error, output neighborhood of facet Pp - do not report precision problems . - list of all options - - one line descriptions of all options -? - help with examples -V - version qdelaunay . Qhull 2020.2 2020/07/24 Except for 'F.' and 'PG', upper-case options take an argument. facet-dump Geomview incidences mathematica off-format points-lifted summary Farea FArea-total Fcoincident Fd-cdd-in FD-cdd-out FF-dump-xridge FIDs Fmerges FMaple Fneighbors FNeigh-vertex FOptions FPoint-near FQdelaun Fsummary FSize Fvertices Fxtremes Gall-points Gcentrums GDrop-dim Ghyperplanes Ginner Gno-planes Gouter Gpoints Gridges Gtransparent Gvertices PArea-keep Pdrop-d0:0D0 PFacet-area-keep Pgood PGood-neighbors PMerge-keep Poutput-forced Pprecision-not Qallow-short QGood-point QJoggle Qrotate Qsearch-all Qtriangulate QupperDelaunay QVertex-good Qwarn-allow Qzinfinite Q12-allow-wide Q14-merge-pinched TFacet-log TInput-file TOutput-file Tstatistics Tverify Tz-stdout T4-trace Tannotate TAdd-stop Tcheck-often TCone-stop Tflush TMerge-trace TPoint-trace TVertex-stop TWide-trace Angle-max Centrum-size Random-dist Wide-outside qdelaunay -? # [mar'19] isatty does not work for Git for Windows qdelaunay -- compute the Delaunay triangulation. Qhull 2020.2 2020/07/24 input (stdin): dimension, number of points, point coordinates comments start with a non-numeric character options (qdelaun.htm): Qu - furthest-site Delaunay triangulation Qt - triangulated output QJ - joggled input instead of merged facets Tv - verify result: structure, convexity, and in-circle test . - concise list of all options - - one-line description of each option -? - this message -V - version output options (subset): s - summary of results (default) i - vertices incident to each Delaunay region Fx - extreme points (vertices of the convex hull) G - Geomview output (2-d and 3-d points lifted to a paraboloid) m - Mathematica output (2-d inputs lifted to a paraboloid) o - OFF format (shows the points lifted to a paraboloid) QVn - print Delaunay regions that include point n, -n if not TI file - input file, may be enclosed in single quotes TO file - output file, may be enclosed in single quotes examples: rbox c P0 D2 | qdelaunay s o rbox c P0 D2 | qdelaunay i rbox c P0 D2 | qdelaunay Fv rbox c P0 D2 | qdelaunay s Qu Fv rbox c G1 d D2 | qdelaunay s i rbox c G1 d D2 | qdelaunay Qt rbox M3,4 z 100 D2 | qdelaunay s rbox M3,4 z 100 D2 | qdelaunay s Qt rbox c P0 D2 | qdelaunay s o Delaunay triangulation by the convex hull of 5 points in 3-d: Number of input sites: 5 Number of Delaunay regions: 4 Statistics for: rbox c P0 D2 | qdelaunay s o Number of points processed: 5 Number of hyperplanes created: 6 Number of facets in hull: 5 Number of distance tests for qhull: 7 Number of distance tests for merging: 34 Number of distance tests for checking: 25 Number of merged facets: 1 CPU seconds to compute hull (after input): 0 3 5 4 6 0 0 0 -0.5 -0.5 0.5 -0.5 0.5 0.5 0.5 -0.5 0.5 0.5 0.5 0.5 3 3 0 1 3 0 2 1 3 4 0 3 3 0 4 2 rbox c P0 D2 | qdelaunay i 4 3 0 1 0 2 1 4 0 3 0 4 2 rbox c P0 D2 | qdelaunay Fv 4 3 0 3 1 3 0 2 1 3 4 0 3 3 4 0 2 rbox c P0 D2 | qdelaunay s Qu Qt Fv Furthest-site Delaunay triangulation by the convex hull of 5 points in 3-d: Number of input sites: 5 Number of Delaunay regions: 2 Number of triangulated facets: 1 Statistics for: rbox c P0 D2 | qdelaunay s Qu Qt Fv Number of points processed: 5 Number of hyperplanes created: 6 Number of facets in hull: 6 Number of distance tests for qhull: 7 Number of distance tests for merging: 34 Number of distance tests for checking: 25 Number of merged facets: 1 CPU seconds to compute hull (after input): 0 2 3 4 2 1 3 4 3 1 rbox c G1 d D2 | qdelaunay s i Delaunay triangulation by the convex hull of 8 points in 3-d: Number of input sites: 8 Number of Delaunay regions: 9 Number of non-simplicial Delaunay regions: 1 Statistics for: rbox c G1 d D2 | qdelaunay s i Number of points processed: 8 Number of hyperplanes created: 16 Number of facets in hull: 10 Number of distance tests for qhull: 41 Number of distance tests for merging: 108 Number of distance tests for checking: 72 Number of merged facets: 3 CPU seconds to compute hull (after input): 0 9 2 4 0 6 1 0 4 6 0 5 3 1 6 5 1 3 7 2 7 4 2 5 7 3 4 7 5 6 rbox c G1 d D2 | qhull d Qbb Ft 2 9 12 14 -1 -1 -1 1 1 -1 1 1 0 -0.5 0 0.5 -0.5 0 0.5 0 0 0 3 2 4 0 3 6 1 0 3 4 6 0 3 5 3 1 3 6 5 1 3 3 7 2 3 7 4 2 3 5 7 3 3 8 5 6 3 8 6 4 3 8 7 5 3 8 4 7 rbox c G1 d D2 | qhull d Qbb QJ s Ft Delaunay triangulation by the convex hull of 8 points in 3-d: Number of input sites: 8 Number of Delaunay regions: 10 Statistics for: rbox c G1 d D2 | qhull d Qbb QJ s Ft Number of points processed: 8 Number of hyperplanes created: 19 Number of facets in hull: 12 Number of distance tests for qhull: 31 CPU seconds to compute hull (after input): 0 Input joggled by: 8.3e-11 2 8 10 15 -1.000000000061343 -0.999999999957446 -0.9999999999945448 0.9999999999532114 1.000000000029778 -0.9999999999701502 0.9999999999806051 1.000000000003233 -7.748592400792811e-11 -0.5000000000743411 2.849349704487493e-11 0.49999999991804 -0.5000000000721135 -1.37371989142159e-11 0.5000000000148132 7.166044474310069e-11 3 1 5 3 3 2 4 0 3 7 4 2 3 4 7 5 3 3 7 2 3 5 7 3 3 1 6 5 3 6 4 5 3 6 1 0 3 4 6 0 rbox M3,4 z 100 D2 | qdelaunay s Delaunay triangulation by the convex hull of 100 points in 3-d: Number of input sites: 100 Number of Delaunay regions: 81 Number of non-simplicial Delaunay regions: 81 Statistics for: rbox M3,4 z 100 D2 | qdelaunay s Number of points processed: 100 Number of hyperplanes created: 251 Number of facets in hull: 86 Number of distance tests for qhull: 1650 Number of distance tests for merging: 2765 Number of distance tests for checking: 1248 Number of merged facets: 155 CPU seconds to compute hull (after input): 0 rbox c P-0.1 P+0.1 P+0.1 D2 | qdelaunay s Fx Fa Fc FP FQ Fn FN Delaunay triangulation by the convex hull of 7 points in 3-d: Number of input sites: 6 Number of nearly incident points: 1 Number of Delaunay regions: 4 Number of non-simplicial Delaunay regions: 2 Statistics for: rbox c P-0.1 P+0.1 P+0.1 D2 | qdelaunay s Fx Fa Fc FP FQ Fn FN Number of points processed: 6 Number of hyperplanes created: 7 Number of facets in hull: 5 Number of distance tests for qhull: 31 Number of distance tests for merging: 54 Number of distance tests for checking: 35 Number of merged facets: 3 CPU seconds to compute hull (after input): 0 Approximate facet area: 1 4 4 3 6 5 4 0.2 0.2 0.3 0.3 4 0 1 1 0 0 1 2 1 8 0 rbox c P-0.1 P+0.1 P+0.1 D2 | qdelaunay s Fx Fa Fc FP FQ Fn FN 4 3 -1 2 3 3 -1 2 3 4 -1 0 3 1 4 0 -1 2 1 7 3 3 2 0 1 1 3 3 1 2 3 0 -1 2 3 3 -1 0 3 1 -1 2 3 1 -1 3 rbox P0 P0 c D2 | qdelaunay s FP QV0 Delaunay triangulation by the convex hull of 6 points in 3-d: Number of input sites: 5 Number of nearly incident points: 1 Number of 'good' Delaunay regions: 4 Statistics for: rbox P0 P0 c D2 | qdelaunay s FP QV0 Number of points processed: 5 Number of hyperplanes created: 6 Number of facets in hull: 5 Number of distance tests for qhull: 18 Number of distance tests for merging: 34 Number of distance tests for checking: 30 Number of merged facets: 1 CPU seconds to compute hull (after input): 0 1 0 1 2 0 qhalf - qhalf -- compute the intersection of halfspaces about a point http://www.qhull.org 2020.2 2020/07/24 input (stdin): optional interior point: dimension, 1, coordinates first lines: dimension+1 and number of halfspaces other lines: halfspace coefficients followed by offset comments: start with a non-numeric character options: Hn,n - specify coordinates of interior point Qc - keep coplanar halfspaces Qi - keep other redundant halfspaces QJ - joggled input instead of merged facets Qt - triangulated output Qhull control options: Qa - allow input with fewer or more points than coordinates Qbk:0Bk:0 - remove k-th coordinate from input QJn - randomly joggle input in range [-n,n] QRn - random rotation (n=seed, n=0 time, n=-1 time/no rotate) Qs - search all halfspaces for the initial simplex Qhull extra options: QGn - print intersection if visible to halfspace n, -n for not QVn - print intersections for halfspace n, -n if not Qw - allow option warnings Q12 - allow wide facets and wide dupridge Q14 - merge pinched vertices that create a dupridge T options: TFn - report summary when n or more facets created TI file - input file, may be enclosed in single quotes TO file - output file, may be enclosed in single quotes Ts - statistics Tv - verify result: structure, convexity, and in-circle test Tz - send all output to stdout Trace options: T4 - trace at level n, 4=all, 5=mem/gauss, -1= events Ta - annotate output with message codes TAn - stop qhull after adding n vertices TCn - stop qhull after building cone for point n TVn - stop qhull after adding point n, -n for before Tc - check frequently during execution Tf - flush each qh_fprintf for debugging segfaults TPn - turn on tracing when point n added to hull TMn - turn on tracing at merge n TWn - trace merge facets when width > n Precision options: Cn - radius of centrum (roundoff added). Merge facets if non-convex An - cosine of maximum angle. Merge facets if cosine > n or non-convex C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge Rn - randomly perturb computations by a factor of [1-n,1+n] Un - max distance below plane for a new, coplanar halfspace Wn - min facet width for outside halfspace (before roundoff) Output formats (may be combined; if none, produces a summary to stdout): f - facet dump G - Geomview output (dual convex hull) i - non-redundant halfspaces incident to each intersection m - Mathematica output (dual convex hull) o - OFF format (dual convex hull: dimension, points, and facets) p - vertex coordinates of dual convex hull (coplanars if 'Qc' or 'Qi') s - summary (stderr) More formats: Fc - count plus redundant halfspaces for each intersection - Qc (default) for coplanar and Qi for other redundant Fd - use cdd format for input (homogeneous with offset first) FF - facet dump without ridges FI - ID of each intersection Fm - merge count for each intersection (511 max) FM - Maple output (dual 2-d or 3-d convex hull) Fn - count plus neighboring intersections for each intersection FN - count plus intersections for each halfspace FO - options and precision constants Fp - dim, count, and intersection coordinates FP - nearest halfspace and distance for each redundant halfspace FQ - command used for qhalf Fs - summary: #int (8), dim, #halfspaces, #non-redundant, #intersections output: #non-redundant, #intersections, #coplanar halfspaces, #non-simplicial intersections #real (2), max outer plane, min vertex Fv - count plus non-redundant halfspaces for each intersection Fx - non-redundant halfspaces Geomview output (2-d, 3-d and 4-d; dual convex hull) Ga - all points (i.e., transformed halfspaces) as dots Gp - coplanar points and vertices as radii Gv - vertices (i.e., non-redundant halfspaces) as spheres Gc - centrums GDn - drop dimension n in 3-d and 4-d output Gh - hyperplane intersections Gi - inner planes (i.e., halfspace intersections) only Gn - no planes Go - outer planes only Gr - ridges Print options: PAn - keep n largest facets (i.e., intersections) by area Pdk:n- drop facet if normal[k] <= n (default 0.0) PDk:n- drop facet if normal[k] >= n PFn - keep facets whose area is at least n Pg - print good facets (needs 'QGn' or 'QVn') PG - print neighbors of good facets PMn - keep n facets with most merges Po - force output. If error, output neighborhood of facet Pp - do not report precision problems . - list of all options - - one line descriptions of all options -? - help with examples -V - version qhalf . Qhull 2020.2 2020/07/24 Except for 'F.' and 'PG', upper_case options take an argument. facet-dump Geomview H0,0-interior incidences mathematica off-format point-dual summary Fc-redundant Fd-cdd-in FF-dump-xridge FIDs Fmerges FMaple Fneighbors FN-intersect FOptions Fp-coordinates FP-nearest FQhalf Fsummary Fv-halfspace Fx-non-redundant Gall-points Gcentrums GDrop-dim Ghyperplanes Ginner Gno-planes Gouter Gpoints Gridges Gvertices PArea-keep Pdrop-d0:0D0 PFacet-area-keep Pgood PGood-neighbors PMerge-keep Poutput-forced Pprecision-not Qallow-short Qbk:0Bk:0-drop Qcoplanar QG-half-good Qi-redundant QJoggle QRotate Qsearch-all Qtriangulate QVertex-good Qwarn-allow Q12-allow-wide Q14-merge-pinched TFacet-log TInput-file TOutput-file Tstatistics Tverify Tz-stdout T4-trace Tannotate TAdd-stop Tcheck-often TCone-stop Tflush TMerge-trace TPoint-trace TVertex-stop TWide-trace Angle-max Centrum-size Random-dist Ucoplanar-max Wide-outside qhalf -? # [mar'19] isatty does not work for Git for Windows qhalf -- halfspace intersection about a point. Qhull 2020.2 2020/07/24 input (stdin): [dimension, 1, interior point] dimension+1, number of halfspaces, coefficients+offset comments start with a non-numeric character options (qhalf.htm): Hn,n - specify coordinates of interior point Qt - triangulated output QJ - joggled input instead of merged facets Tv - verify result: structure, convexity, and redundancy . - concise list of all options - - one-line description of each option -? - this message -V - version output options (subset): s - summary of results (default) Fp - intersection coordinates Fv - non-redundant halfspaces incident to each intersection Fx - non-redundant halfspaces G - Geomview output (dual convex hull) m - Mathematica output (dual convex hull) o - OFF file format (dual convex hull) QVn - print intersections for halfspace n, -n if not TI file - input file, may be enclosed in single quotes TO file - output file, may be enclosed in single quotes examples: rbox d | qconvex FQ n | qhalf s H0,0,0 Fp rbox c | qconvex FQ FV n | qhalf s i rbox c | qconvex FQ FV n | qhalf s o rbox d | qhull FQ n | qhalf s Qt H0,0,0 Fp Halfspace intersection by the convex hull of 8 points in 3-d: Number of halfspaces: 8 Number of non-redundant halfspaces: 8 Number of intersection points: 12 Number of triangulated facets: 6 Statistics for: rbox d | qhull FQ n | qhalf s Qt H0,0,0 Fp Number of points processed: 8 Number of hyperplanes created: 11 Number of distance tests for qhull: 32 Number of distance tests for merging: 101 Number of distance tests for checking: 48 Number of merged facets: 7 CPU seconds to compute hull (after input): 0 3 12 0 0 -0.5 0 0 -0.5 0 -0.5 0 0 -0.5 0 -0.5 0 0 -0.5 0 0 0.5 0 0 0.5 0 0 0 0.5 0 0 0.5 0 0 0 0.5 0 0 0.5 rbox c | qhull FQ FV n | qhalf s i Halfspace intersection by the convex hull of 6 points in 3-d: Number of halfspaces: 6 Number of non-redundant halfspaces: 6 Number of intersection points: 8 Statistics for: rbox c | qhull FQ FV n | qhalf s i Number of points processed: 6 Number of hyperplanes created: 11 Number of distance tests for qhull: 10 Number of distance tests for merging: 51 Number of distance tests for checking: 48 Number of merged facets: 1 CPU seconds to compute hull (after input): 0 8 1 0 3 0 1 2 5 1 3 1 5 2 4 0 2 0 4 3 5 4 2 4 5 3 rbox c | qhull FQ FV n | qhalf o 3 6 8 12 -0 -0 -2 0 -2 0 2 -0 -0 -2 -0 -0 0 2 -0 -0 -0 2 3 1 0 3 3 0 1 2 3 5 1 3 3 1 5 2 3 4 0 2 3 0 4 3 3 5 4 2 3 4 5 3 rbox d D2 | qhull FQ n | qhalf s H0 Fc FP Fn FN FQ Fv Fx Halfspace intersection by the convex hull of 4 points in 2-d: Number of halfspaces: 4 Number of non-redundant halfspaces: 4 Number of intersection points: 4 Statistics for: rbox d D2 | qhull FQ n | qhalf s H0 Fc FP Fn FN FQ Fv Fx Number of points processed: 4 Number of hyperplanes created: 6 Number of distance tests for qhull: 5 CPU seconds to compute hull (after input): 0 4 0 0 0 0 0 4 2 1 2 2 0 3 2 0 3 2 1 2 4 2 0 1 2 2 0 2 1 3 2 3 2 rbox d D2 | qhull FQ n | qhalf s H0 Fc FP Fn FN FQ Fv Fx 4 2 1 0 2 2 0 2 3 1 2 3 2 4 0 1 3 2 # qhull - printed at end qhull . Qhull 2020.2.r 2020/07/24 Except for 'F.' and 'PG', upper-case options take an argument. delaunay facet-dump Geomview H0,0-interior Halfspace incidences mathematica normals off-format points summary voronoi Farea FArea-total Fcoplanars FCentrums Fd-cdd-in FD-cdd-out FFacets-xridge Finner FIDs Fmerges FMaple Fneighbors FNeigh-vertex Fouter FOptions Fpoint-intersect FPoint-near FQhull Fsummary FSize Ftriangles Fvertices Fvoronoi FVertex-ave Fxtremes Gall-points Gcentrums GDrop-dim Ghyperplanes Ginner Gno-planes Gouter Gpoints Gridges Gtransparent Gvertices PArea-keep Pdrop-d0:0D0 PFacet-area-keep Pgood PGood-neighbors PMerge-keep Poutput-forced Pprecision-not Qallow-short QbBound-0:0.5 QbB-scale-box Qbb-scale-last Qbk:0Bk:0-drop Qcoplanar Qinterior QJoggle QRotate Qsearch-all Qtriangulate QupperDelaunay Qwarn-allow Qxact-merge Qzinfinite Qfurthest Qgood-only QGood-point Qmax-outside Qrandom Qvneighbors QVertex-good Q0-no-premerge Q1-angle-merge Q2-no-independ Q3-no-redundant Q4-no-old Q5-no-check-out Q6-no-concave Q7-depth-first Q8-no-near-in Q9-pick-furthest Q10-no-narrow Q11-trinormals Q12-allow-wide Q14-merge-pinched Q15-duplicates TFacet-log TInput-file TOutput-file Tstatistics Tverify Tz-stdout T4-trace Tannotate TAdd-stop Tcheck-often TCone-stop Tflush TMerge-trace TPoint-trace TRerun TVertex-stop TWide-trace Angle-max Centrum-size Error-round Random-dist Ucoplanar-max Visible-min Wide-outside qhull -? # [mar'19] isatty does not work for Git for Windows qhull -- compute convex hulls and related structures. Qhull 2020.2.r 2020/07/24 input (stdin): dimension, number of points, point coordinates comments start with a non-numeric character halfspace: use dim+1 and put offsets after coefficients options (qh-quick.htm): d - Delaunay triangulation by lifting points to a paraboloid d Qu - furthest-site Delaunay triangulation (upper convex hull) v - Voronoi diagram as the dual of the Delaunay triangulation v Qu - furthest-site Voronoi diagram H1,1 - Halfspace intersection about [1,1,0,...] via polar duality Qt - triangulated output QJ - joggled input instead of merged facets Tv - verify result: structure, convexity, and point inclusion . - concise list of all options - - one-line description of each option -? - this message -V - version Output options (subset): s - summary of results (default) i - vertices incident to each facet n - normals with offsets p - vertex coordinates (if 'Qc', includes coplanar points) if 'v', Voronoi vertices FA - report total area and volume Fp - halfspace intersections FS - total area and volume Fx - extreme points (convex hull vertices) G - Geomview output (2-d, 3-d and 4-d) m - Mathematica output (2-d and 3-d) o - OFF format (if 'v', outputs Voronoi regions) QVn - print facets that include point n, -n if not TI file - input file, may be enclosed in single quotes TO file - output file, may be enclosed in single quotes examples: rbox D4 | qhull Tv rbox 1000 s | qhull Tv s FA rbox 10 D2 | qhull d QJ s i TO result rbox 10 D2 | qhull v Qbb Qt p rbox 10 D2 | qhull d Qu QJ m rbox 10 D2 | qhull v Qu QJ o rbox c d D2 | qhull Qc s f Fx | more rbox c | qhull FV n | qhull H Fp rbox d D12 | qhull QR0 FA rbox c D7 | qhull FA TF1000 rbox y 1000 W0 | qhull Qc rbox c | qhull n rbox 1000 s | qhull Tv s FA Convex hull of 1000 points in 3-d: Number of vertices: 1000 Number of facets: 1996 Statistics for: rbox 1000 s | qhull Tv s FA Number of points processed: 1000 Number of hyperplanes created: 5544 Number of distance tests for qhull: 25487 CPU seconds to compute hull (after input): 0.003 Total facet area: 3.1201951 Total volume: 0.51650274 qhull output completed. Verifying that 1000 points are below 2.1e-15 of the nearest facet. rbox 10 D2 | qhull d QJ s i TO q_test.log.1 Delaunay triangulation by the convex hull of 10 points in 3-d: Number of input sites: 10 Number of Delaunay regions: 14 Statistics for: rbox 10 D2 | qhull d QJ s i TO q_test.log.1 Number of points processed: 10 Number of hyperplanes created: 28 Number of facets in hull: 16 Number of distance tests for qhull: 47 CPU seconds to compute hull (after input): 0 Input joggled by: 4e-11 cat q_test.log.1 14 9 7 0 8 9 0 3 4 1 3 7 4 7 2 4 0 5 1 7 5 0 5 3 1 3 5 7 6 7 9 6 2 7 8 6 9 6 8 4 2 6 4 rbox 10 D2 | qhull v Qbb Qt p 2 14 -0.1294381801544404 -0.07247409101984714 0.08267689532419747 -0.2397644955865706 0.1295260566906465 1.716033573116837 0.1740355150742391 0.5317519038435655 0.1851415205797575 0.3882545794457364 -0.9065939866848107 -0.2962957610652135 -0.1954805620516266 -0.07111892482963184 -0.1407581310832468 0.7233857048236082 -0.1676297826663962 0.2080621273999375 0.05868313821742954 0.06632066014880154 0.08806341399736994 0.1054080604689985 0.4761588899009253 -0.03168366595227294 3.094213357897477 -0.064721945677682 0.5410515627308725 0.2115615434955919 rbox 10 D2 | qhull d Qu QJ m { Polygon[{{ 0.37903124, 0.37797944, 0.29963416}, { -0.02222276, -0.49797278, 0.23792952}, { -0.42854319, 0.47458265, 0.49797278}}], Polygon[{{ 0.34431227, -0.14373122, 0.06080143}, { -0.02222276, -0.49797278, 0.23792952}, { 0.37903124, 0.37797944, 0.29963416}}]} rbox 10 D2 | qhull v Qu QJ o 2 3 10 1 -10.101 -10.101 -0.06934933488573394 0.05349366577046777 -0.3051278692468022 0.16149850548211 3 0 2 1 2 0 1 0 0 3 0 1 2 0 0 0 2 0 2 0 rbox c d D2 | qhull Qc s f Fx Convex hull of 8 points in 2-d: Number of vertices: 4 Number of coplanar points: 4 Number of facets: 4 Statistics for: rbox c d D2 | qhull Qc s f Fx Number of points processed: 4 Number of hyperplanes created: 6 Number of distance tests for qhull: 35 CPU seconds to compute hull (after input): 0 Vertices and facets: - p2(v2): 0.5 -0.5 - p0(v1): -0.5 -0.5 - p1(v3): -0.5 0.5 - p3(v4): 0.5 0.5 - f1 - flags: bottom simplicial - normal: -0 -1 - offset: -0.5 - coplanar set(furthest p4): p4: 0 -0.5 furthest distance= 0 - vertices: p2(v2) p0(v1) - neighboring facets: f2 f4 - f2 - flags: top simplicial - normal: -1 0 - offset: -0.5 - coplanar set(furthest p6): p6: -0.5 0 furthest distance= 0 - vertices: p1(v3) p0(v1) - neighboring facets: f1 f5 - f4 - flags: bottom simplicial - normal: 1 -0 - offset: -0.5 - coplanar set(furthest p7): p7: 0.5 0 furthest distance= 0 - vertices: p3(v4) p2(v2) - neighboring facets: f1 f5 - f5 - flags: top simplicial - normal: 0 1 - offset: -0.5 - coplanar set(furthest p5): p5: 0 0.5 furthest distance= 0 - vertices: p3(v4) p1(v3) - neighboring facets: f2 f4 4 0 2 3 1 rbox c | qhull FV n | qhull H Fp 3 8 -0.5 -0.5 -0.5 0.5 -0.5 -0.5 -0.5 -0.5 0.5 0.5 -0.5 0.5 0.5 0.5 -0.5 -0.5 0.5 -0.5 0.5 0.5 0.5 -0.5 0.5 0.5 rbox d D12 | qhull QR0 FA Convex hull of 24 points in 12-d: Number of vertices: 24 Number of facets: 4096 Statistics for: rbox d D12 | qhull QR0 FA QR1595644042 Number of points processed: 24 Number of hyperplanes created: 4107 Number of distance tests for qhull: 4215 Number of distance tests for merging: 121142 Number of distance tests for checking: 98304 Number of merged facets: 2036 CPU seconds to compute hull (after input): 0.023 Approximate facet area: 1.735661e-07 Approximate volume: 2.0876757e-09 rbox c D7 | qhull FA TF1000 At 22:27:22 & 0.003 CPU secs, qhull has created 1048 facets and merged 469. The current hull contains 230 facets and 24 vertices. There are 104 outside points. Next is point p79(v25), 0.66 above f145. At 22:27:22 & 0.005 CPU secs, qhull has created 2146 facets and merged 1272. The current hull contains 273 facets and 31 vertices. There are 97 outside points. Next is point p120(v32), 0.54 above f437. At 22:27:22 & 0.008 CPU secs, qhull has created 3310 facets and merged 2244. The current hull contains 243 facets and 36 vertices. There are 92 outside points. Next is point p60(v37), 0.54 above f1338. At 22:27:22 & 0.01 CPU secs, qhull has created 4322 facets and merged 3099. The current hull contains 249 facets and 42 vertices. There are 86 outside points. Next is point p30(v43), 0.54 above f2005. At 22:27:22 & 0.012 CPU secs, qhull has created 5491 facets and merged 4196. The current hull contains 186 facets and 48 vertices. There are 80 outside points. Next is point p21(v49), 0.5 above f2995. At 22:27:22 & 0.015 CPU secs, qhull has created 6589 facets and merged 5175. The current hull contains 194 facets and 53 vertices. There are 75 outside points. Next is point p56(v54), 0.28 above f3731. At 22:27:22 & 0.018 CPU secs, qhull has created 7867 facets and merged 6337. The current hull contains 203 facets and 60 vertices. There are 68 outside points. Next is point p76(v61), 0.29 above f5879. At 22:27:22 & 0.021 CPU secs, qhull has created 8971 facets and merged 7362. The current hull contains 179 facets and 67 vertices. There are 61 outside points. Next is point p80(v68), 0.23 above f7175. At 22:27:22 & 0.023 CPU secs, qhull has created 9984 facets and merged 8352. The current hull contains 104 facets and 77 vertices. There are 51 outside points. Next is point p96(v78), 0.41 above f6748. At 22:27:22 & 0.027 CPU secs, qhull has created 10990 facets and merged 9326. The current hull contains 54 facets and 90 vertices. There are 38 outside points. Next is point p18(v91), 0.41 above f10178. At 22:27:22 & 0.031 CPU secs, qhull has created 11996 facets and merged 10295. The current hull contains 34 facets and 114 vertices. There are 14 outside points. Next is point p19(v115), 0.38 above f11792. At 22:27:22 & 0.034 CPU secs, qhull has created 12860 facets and merged 11072. The current hull contains 14 facets and 128 vertices. Last point was p77 Convex hull of 128 points in 7-d: Number of vertices: 128 Number of facets: 14 Number of non-simplicial facets: 14 Statistics for: rbox c D7 | qhull FA TF1000 Number of points processed: 128 Number of hyperplanes created: 1789 Number of distance tests for qhull: 10122 Number of distance tests for merging: 87203 Number of distance tests for checking: 0 Number of merged facets: 11072 First post-merge with 'C4.4e-15' and 'A1.8e+308' At 22:27:22 & 0.034 CPU secs, qhull has created 12860 facets and merged 11072. The current hull contains 14 facets and 128 vertices. Last point was p77 Testing all coplanar points. computing area of each facet and volume of the convex hull Convex hull of 128 points in 7-d: Number of vertices: 128 Number of facets: 14 Number of non-simplicial facets: 14 Statistics for: rbox c D7 | qhull FA TF1000 Number of points processed: 128 Number of hyperplanes created: 1789 Number of distance tests for qhull: 10122 Number of distance tests for merging: 87371 Number of distance tests for checking: 1792 Number of merged facets: 11072 CPU seconds to compute hull (after input): 0.034 Approximate facet area: 14 Approximate volume: 1 rbox y 1000 W0 | qhull Qc Convex hull of 1004 points in 3-d: Number of vertices: 4 Number of coplanar points: 1000 Number of facets: 4 Statistics for: rbox y 1000 W0 | qhull Qc Number of points processed: 4 Number of hyperplanes created: 4 Number of distance tests for qhull: 11000 CPU seconds to compute hull (after input): 0.001 rbox c | qhull n 4 6 -0 -0 -1 -0.5 0 -1 0 -0.5 1 -0 -0 -0.5 -1 -0 -0 -0.5 0 1 -0 -0.5 -0 -0 1 -0.5 rbox c | qhull TA1 Early exit due to 'TAn', 'TVn', 'TCn', 'TRn', or precision error with 'QJn'. Convex hull of 8 points in 3-d: Number of vertices: 5 Number of facets: 6 Statistics for: rbox c | qhull TA1 Number of points processed: 5 Number of hyperplanes created: 8 Number of distance tests for qhull: 25 CPU seconds to compute hull (after input): 0 rbox 10 s | qhull C1e-5 T1P-1f [QH1008]qh_readpoints: read in 10 3-dimensional points [QH0013]qh_initqhull_globals: for rbox 10 s | qhull C1e-5 T1P-1f Trace level T1, IStracing 0, point TP-1, merge TM0, dist TW1.8e+308, qh.tracefacet_id -1, traceridge_id -1, tracevertex_id -1, last qh.RERUN 0, rbox 10 s | qhull C1e-5 T1P-1f Options selected for Qhull 2020.2.r 2020/07/24: run-id 213630158 Centrum-postmerge 1e-05 Trace-point -1 Tflush _pre-merge _max-width 0.88 Error-roundoff 6.7e-16 _one-merge 3e-05 _near-inside 0.00015 Visible-distance 1.3e-15 U-max-coplanar 1.3e-15 Width-outside 2.7e-15 _wide-facet 8e-15 [QH2112]qh_qhull: finished qh_buildhull and qh_postmerge, start tracing (TP-1) [QH1022]qh_check_maxout: check and update qh.min_vertex -6.7e-16 and qh.max_outside 1.1e-16 [QH1055]qh_check_maxout: determine actual maxoutside [QH1024]qh_check_maxout: p7(v6) is qh.min_vertex -6.7e-16 below facet f4. Point p2 for f4 is qh.max_outside 1.1e-16 above f4. 0 points are outside of not-good facets [QH1036]Qhull: algorithm completed [QH1027]qh_checkpolygon: check all facets from f4, qh.NEWtentative? 0 [QH1062]qh_checkconvex: check that facets are not-flipped and that their centrums are convex by qh.DISTround ('En', 'Rn') Convex hull of 10 points in 3-d: Number of vertices: 10 Number of facets: 16 Statistics for: rbox 10 s | qhull C1e-5 T1P-1f Number of points processed: 10 Number of hyperplanes created: 27 Number of distance tests for qhull: 51 CPU seconds to compute hull (after input): 0 [QH1006]qh_freeqhull: free global memory [QH1005]qh_freebuild: free memory from qh_inithull and qh_buildhull [QH1061]qh_freeqhull: clear qhT except for qh.qhmem and qh.qhstat set +v === check quality of Qhull for kelwyn Fri, Jul 24, 2020 10:27:22 PM rbox 1000 W0 | qhull QR2 QJ s Fs Tv Convex hull of 1000 points in 3-d: Number of vertices: 144 Number of facets: 284 Statistics for: rbox 1000 W0 | qhull QR2 QJ s Fs Tv QR2 Number of points processed: 171 Number of hyperplanes created: 1233 Number of distance tests for qhull: 33543 CPU seconds to compute hull (after input): 0.005 After 1 retries, input joggled by: 2.9e-11 10 3 1000 144 284 144 284 0 0 33 0 2 5.045982607091333e-11 -5.045982607091333e-11 Output completed. Verifying that all points are below 2.9e-15 of all facets. Will make 284000 distance computations. rbox 1000 W0 | qhull QR2 s Fs Tv Convex hull of 1000 points in 3-d: Number of vertices: 84 Number of facets: 98 Number of non-simplicial facets: 6 Statistics for: rbox 1000 W0 | qhull QR2 s Fs Tv QR2 Number of points processed: 97 Number of hyperplanes created: 299 Number of distance tests for qhull: 18050 Number of distance tests for merging: 3163 Number of distance tests for checking: 15481 Number of merged facets: 92 CPU seconds to compute hull (after input): 0.001 10 3 1000 84 98 84 98 0 6 13 0 2 1.942124858599573e-15 -1.241679291552168e-15 Output completed. Verifying that all points are below outer planes of all facets. Will make 98000 distance computations. rbox 1000 s | qhull C0.02 Qc Tv Convex hull of 1000 points in 3-d: Number of vertices: 110 Number of coplanar points: 890 Number of facets: 57 Number of non-simplicial facets: 57 Statistics for: rbox 1000 s | qhull C0.02 Qc Tv Number of points processed: 1000 Number of hyperplanes created: 5544 Number of distance tests for qhull: 81537 Number of distance tests for merging: 80708 Number of distance tests for checking: 8256 Number of merged facets: 1939 CPU seconds to compute hull (after input): 0.011 Maximum distance of vertex below facet: -0.079 (1.3x) Output completed. Verifying that all points are below outer planes of all facets. Will make 57000 distance computations. rbox 500 s D4 | qhull C0.01 Qc Tv Convex hull of 500 points in 4-d: Number of vertices: 462 Number of coplanar points: 38 Number of facets: 345 Number of non-simplicial facets: 332 Statistics for: rbox 500 s D4 | qhull C0.01 Qc Tv Number of points processed: 500 Number of hyperplanes created: 11283 Number of distance tests for qhull: 42789 Number of distance tests for merging: 217345 Number of distance tests for checking: 12552 Number of merged facets: 2821 CPU seconds to compute hull (after input): 0.019 Maximum distance of vertex below facet: -0.08 (2.0x) Output completed. Verifying that all points are below outer planes of all facets. Will make 172500 distance computations. rbox 1000 s | qhull C-0.02 Qc Tv Convex hull of 1000 points in 3-d: Number of vertices: 52 Number of coplanar points: 948 Number of facets: 47 Number of non-simplicial facets: 38 Statistics for: rbox 1000 s | qhull C-0.02 Qc Tv Number of points processed: 53 Number of hyperplanes created: 214 Number of distance tests for qhull: 47444 Number of distance tests for merging: 2943 Number of distance tests for checking: 19555 Number of merged facets: 107 CPU seconds to compute hull (after input): 0.002 Maximum distance of point above facet: 0.039 (0.7x) Maximum distance of vertex below facet: -0.057 (0.9x) Output completed. Verifying that all points are below outer planes of all facets. Will make 47000 distance computations. rbox 1000 s D4 | qhull C-0.01 Qc Tv Convex hull of 1000 points in 4-d: Number of vertices: 126 Number of coplanar points: 874 Number of facets: 206 Number of non-simplicial facets: 148 Statistics for: rbox 1000 s D4 | qhull C-0.01 Qc Tv Number of points processed: 126 Number of hyperplanes created: 1371 Number of distance tests for qhull: 414344 Number of distance tests for merging: 73447 Number of distance tests for checking: 124140 Number of merged facets: 1331 CPU seconds to compute hull (after input): 0.02 Maximum distance of point above facet: 0.068 (1.7x) Maximum distance of vertex below facet: -0.1 (2.6x) Output completed. Verifying that all points are below outer planes of all facets. Will make 206000 distance computations. rbox 200 s D5 | qhull C-0.01 Qx Qc Tv Convex hull of 200 points in 5-d: Number of vertices: 161 Number of coplanar points: 39 Number of facets: 416 Number of non-simplicial facets: 365 Statistics for: rbox 200 s D5 | qhull C-0.01 Qx Qc Tv Number of points processed: 161 Number of hyperplanes created: 4552 Number of distance tests for qhull: 229096 Number of distance tests for merging: 309308 Number of distance tests for checking: 54701 Number of merged facets: 6165 CPU seconds to compute hull (after input): 0.039 Maximum distance of point above facet: 0.059 (1.2x) Maximum distance of vertex below facet: -0.1 (2.1x) QH7076 qhull input warning: exact merge ('Qx'). Verify may report that a point is outside of a facet. See qh-optq.htm#Qx Output completed. Verifying that all points are below outer planes of all facets. Will make 83200 distance computations. rbox 100 s D6 | qhull C-0.001 Qx Qc Tv Convex hull of 100 points in 6-d: Number of vertices: 100 Number of facets: 4454 Number of non-simplicial facets: 809 Statistics for: rbox 100 s D6 | qhull C-0.001 Qx Qc Tv Number of points processed: 100 Number of hyperplanes created: 19805 Number of distance tests for qhull: 33228 Number of distance tests for merging: 330047 Number of distance tests for checking: 88758 Number of merged facets: 3862 CPU seconds to compute hull (after input): 0.057 Maximum distance of point above facet: 0.003 (0.5x) Maximum distance of vertex below facet: -0.014 (2.3x) QH7076 qhull input warning: exact merge ('Qx'). Verify may report that a point is outside of a facet. See qh-optq.htm#Qx Output completed. Verifying that all points are below outer planes of all facets. Will make 445400 distance computations. rbox 1000 W1e-4 | qhull C-1e-6 Qc Tv Convex hull of 1000 points in 3-d: Number of vertices: 145 Number of coplanar points: 87 Number of facets: 243 Number of non-simplicial facets: 29 Statistics for: rbox 1000 W1e-4 | qhull C-1e-6 Qc Tv Number of points processed: 185 Number of hyperplanes created: 940 Number of distance tests for qhull: 40788 Number of distance tests for merging: 7744 Number of distance tests for checking: 6136 Number of merged facets: 143 CPU seconds to compute hull (after input): 0.002 Maximum distance of point above facet: 8.3e-07 (0.3x) Maximum distance of vertex below facet: -3.9e-06 (1.3x) Output completed. Verifying that all points are below outer planes of all facets. Will make 243000 distance computations. rbox 1000 W5e-4 D4 | qhull C-1e-5 Qc Tv Convex hull of 1000 points in 4-d: Number of vertices: 291 Number of coplanar points: 645 Number of facets: 1273 Number of non-simplicial facets: 151 Statistics for: rbox 1000 W5e-4 D4 | qhull C-1e-5 Qc Tv Number of points processed: 365 Number of hyperplanes created: 6252 Number of distance tests for qhull: 173357 Number of distance tests for merging: 90805 Number of distance tests for checking: 56693 Number of merged facets: 1351 CPU seconds to compute hull (after input): 0.013 Maximum distance of point above facet: 0.00013 (3.3x) Maximum distance of vertex below facet: -0.00021 (5.4x) Output completed. Verifying that all points are below outer planes of all facets. Will make 1273000 distance computations. rbox 400 W1e-3 D5 | qhull C-1e-5 Qx Qc Tv Convex hull of 400 points in 5-d: Number of vertices: 306 Number of coplanar points: 33 Number of facets: 5557 Number of non-simplicial facets: 287 Statistics for: rbox 400 W1e-3 D5 | qhull C-1e-5 Qx Qc Tv Number of points processed: 338 Number of hyperplanes created: 24498 Number of distance tests for qhull: 262194 Number of distance tests for merging: 271065 Number of distance tests for checking: 90075 Number of merged facets: 1472 CPU seconds to compute hull (after input): 0.045 Maximum distance of point above facet: 5.5e-05 (1.1x) Maximum distance of vertex below facet: -0.0001 (2.1x) QH7076 qhull input warning: exact merge ('Qx'). Verify may report that a point is outside of a facet. See qh-optq.htm#Qx Output completed. Verifying that all points are below outer planes of all facets. Will make 2222800 distance computations. set +v === check input format etc. Fri, Jul 24, 2020 10:27:23 PM qhull <r.x qhull TIr.x Convex hull of 10 points in 3-d: Number of vertices: 10 Number of facets: 16 Statistics for: rbox 10 | qhull TIr.x Number of points processed: 10 Number of hyperplanes created: 26 Number of distance tests for qhull: 43 CPU seconds to compute hull (after input): 0 qhull p TI r.x TO x.x cat x.x 3 10 -0.374949442106252 0.2247255418679914 -0.03782349642163468 0.3004920247946792 0.3694544596313075 0.4210962191420572 0.3641479121187217 0.2339522165562512 0.03489791698278666 -0.4707134565997063 -0.2810653003687648 0.1354949890035158 0.2642752088273644 -0.3265712199048802 0.3175057017407433 0.3183227589524563 0.05060330969337679 0.4898217078203537 0.4334355904100794 -0.2480392830893763 0.2037671452423252 -0.2855954200826543 -0.002227006947833121 -0.4293096679535784 -0.4075898489985521 -0.3625928418362446 -0.09789381697577781 -0.3013850588364387 -0.3786854184034145 0.4341719447953365 set +v === check qhull output formats Fri, Jul 24, 2020 10:27:28 PM rbox 5 r s D2 | qhull Tcv Convex hull of 5 points in 2-d: Number of vertices: 5 Number of facets: 5 Statistics for: rbox 5 r s D2 | qhull Tcv Number of points processed: 5 Number of hyperplanes created: 8 Number of distance tests for qhull: 7 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below 1.3e-15 of all facets. Will make 25 distance computations. rbox 5 r s D2 | qhull s Convex hull of 5 points in 2-d: Number of vertices: 5 Number of facets: 5 Statistics for: rbox 5 r s D2 | qhull s Number of points processed: 5 Number of hyperplanes created: 8 Number of distance tests for qhull: 7 CPU seconds to compute hull (after input): 0 rbox 5 r s D2 | qhull s o Convex hull of 5 points in 2-d: Number of vertices: 5 Number of facets: 5 Statistics for: rbox 5 r s D2 | qhull s o Number of points processed: 5 Number of hyperplanes created: 8 Number of distance tests for qhull: 7 CPU seconds to compute hull (after input): 0 2 5 5 5 0.1545084971874737 0.4755282581475768 -0.4045084971874737 0.2938926261462366 -0.4045084971874738 -0.2938926261462365 0.1545084971874736 -0.4755282581475768 0.5 -1.224646799147353e-16 2 4 0 2 2 3 2 3 4 2 1 2 2 0 1 rbox 5 r s D2 | qhull f Vertices and facets: - p0(v3): 0.15 0.48 - p4(v2): 0.5 -1.2e-16 - p3(v4): 0.15 -0.48 - p2(v1): -0.4 -0.29 - p1(v5): -0.4 0.29 - f3 - flags: bottom simplicial - normal: 0.809 0.5878 - offset: -0.4045085 - vertices: p0(v3) p4(v2) - neighboring facets: f5 f7 - f4 - flags: bottom simplicial - normal: -0.309 -0.9511 - offset: -0.4045085 - vertices: p3(v4) p2(v1) - neighboring facets: f6 f5 - f5 - flags: top simplicial - normal: 0.809 -0.5878 - offset: -0.4045085 - vertices: p3(v4) p4(v2) - neighboring facets: f3 f4 - f6 - flags: top simplicial - normal: -1 9.444e-17 - offset: -0.4045085 - vertices: p1(v5) p2(v1) - neighboring facets: f4 f7 - f7 - flags: bottom simplicial - normal: -0.309 0.9511 - offset: -0.4045085 - vertices: p1(v5) p0(v3) - neighboring facets: f3 f6 rbox 5 r s D2 | qhull i 5 4 0 2 3 3 4 1 2 0 1 rbox 5 r s D2 | qhull m { Line[{{ 0.50000000, -0.00000000}, { 0.15450850, 0.47552826}}] ,Line[{{ -0.40450850, -0.29389263}, { 0.15450850, -0.47552826}}] ,Line[{{ 0.15450850, -0.47552826}, { 0.50000000, -0.00000000}}] ,Line[{{ -0.40450850, 0.29389263}, { -0.40450850, -0.29389263}}] ,Line[{{ 0.15450850, 0.47552826}, { -0.40450850, 0.29389263}}] } rbox 5 r s D2 | qhull FM PLOT(CURVES( [[ 0.50000000, -0.00000000], [ 0.15450850, 0.47552826]] ,[[ -0.40450850, -0.29389263], [ 0.15450850, -0.47552826]] ,[[ 0.15450850, -0.47552826], [ 0.50000000, -0.00000000]] ,[[ -0.40450850, 0.29389263], [ -0.40450850, -0.29389263]] ,[[ 0.15450850, 0.47552826], [ -0.40450850, 0.29389263]] )); rbox 5 r s D2 | qhull n 3 5 0.8090169943749476 0.587785252292473 -0.4045084971874737 -0.3090169943749476 -0.9510565162951536 -0.4045084971874738 0.8090169943749472 -0.5877852522924732 -0.4045084971874737 -1 9.444121133484361e-17 -0.4045084971874738 -0.3090169943749474 0.9510565162951536 -0.4045084971874738 rbox 5 r s D2 | qhull p 2 5 0.1545084971874737 0.4755282581475768 -0.4045084971874737 0.2938926261462366 -0.4045084971874738 -0.2938926261462365 0.1545084971874736 -0.4755282581475768 0.5 -1.224646799147353e-16 rbox 5 r s D2 | qhull o 2 5 5 5 0.1545084971874737 0.4755282581475768 -0.4045084971874737 0.2938926261462366 -0.4045084971874738 -0.2938926261462365 0.1545084971874736 -0.4755282581475768 0.5 -1.224646799147353e-16 2 4 0 2 2 3 2 3 4 2 1 2 2 0 1 rbox 5 r s D2 | qhull Ft 2 5 5 5 0.1545084971874737 0.4755282581475768 -0.4045084971874737 0.2938926261462366 -0.4045084971874738 -0.2938926261462365 0.1545084971874736 -0.4755282581475768 0.5 -1.224646799147353e-16 2 4 0 2 2 3 2 3 4 2 1 2 2 0 1 rbox 5 r s D2 | qhull Fx 5 4 0 1 2 3 rbox 5 r s D2 | qhull p n i p p 2 5 0.1545084971874737 0.4755282581475768 -0.4045084971874737 0.2938926261462366 -0.4045084971874738 -0.2938926261462365 0.1545084971874736 -0.4755282581475768 0.5 -1.224646799147353e-16 3 5 0.8090169943749476 0.587785252292473 -0.4045084971874737 -0.3090169943749476 -0.9510565162951536 -0.4045084971874738 0.8090169943749472 -0.5877852522924732 -0.4045084971874737 -1 9.444121133484361e-17 -0.4045084971874738 -0.3090169943749474 0.9510565162951536 -0.4045084971874738 5 4 0 2 3 3 4 1 2 0 1 rbox 10 D3 | qhull f Tcv Vertices and facets: - p0(v5): -0.022 -0.37 0.33 - p9(v3): 0.38 -0.47 -0.22 - p6(v1): -0.31 -0.011 -0.49 - p1(v4): -0.067 -0.16 0.46 - p7(v2): 0.39 0.045 0.12 - p3(v6): 0.31 0.084 -0.1 - p4(v7): 0.18 0.12 0.049 - p5(v8): -0.12 0.015 -0.14 - p2(v9): 0.028 0.042 0.058 - f5 - flags: top simplicial - normal: -0.4934 -0.8471 -0.1973 - offset: -0.2568231 - vertices: p0(v5) p9(v3) p6(v1) - neighboring facets: f9 f6 f7 - f6 - flags: bottom simplicial - normal: -0.9301 -0.3157 0.1877 - offset: -0.1977325 - vertices: p0(v5) p1(v4) p6(v1) - neighboring facets: f17 f5 f8 - f7 - flags: bottom simplicial - normal: 0.7008 -0.3956 0.5936 - offset: -0.323519 - vertices: p0(v5) p9(v3) p7(v2) - neighboring facets: f10 f8 f5 - f8 - flags: top simplicial - normal: 0.6544 -0.298 0.6949 - offset: -0.3219447 - vertices: p0(v5) p1(v4) p7(v2) - neighboring facets: f13 f7 f6 - f9 - flags: bottom simplicial - normal: 0.4866 0.2316 -0.8424 - offset: -0.2582907 - vertices: p3(v6) p9(v3) p6(v1) - neighboring facets: f5 f16 f10 - f10 - flags: top simplicial - normal: 0.943 0.1711 -0.2855 - offset: -0.3386013 - vertices: p3(v6) p9(v3) p7(v2) - neighboring facets: f7 f14 f9 - f13 - flags: bottom simplicial - normal: 0.08536 0.8035 0.5892 - offset: -0.1388354 - vertices: p4(v7) p1(v4) p7(v2) - neighboring facets: f8 f14 f20 - f14 - flags: top simplicial - normal: 0.3121 0.948 0.06295 - offset: -0.1707289 - vertices: p4(v7) p3(v6) p7(v2) - neighboring facets: f10 f13 f16 - f16 - flags: bottom simplicial - normal: -0.008104 0.9738 -0.2271 - offset: -0.1026508 - vertices: p4(v7) p3(v6) p6(v1) - neighboring facets: f9 f18 f14 - f17 - flags: top simplicial - normal: -0.6179 0.7381 0.2709 - offset: -0.04995414 - vertices: p5(v8) p1(v4) p6(v1) - neighboring facets: f6 f18 f21 - f18 - flags: bottom simplicial - normal: -0.3978 0.9064 0.1423 - offset: -0.04320607 - vertices: p5(v8) p4(v7) p6(v1) - neighboring facets: f16 f17 f22 - f20 - flags: top simplicial - normal: -0.4124 0.8514 0.3242 - offset: -0.04294297 - vertices: p2(v9) p4(v7) p1(v4) - neighboring facets: f13 f21 f22 - f21 - flags: bottom simplicial - normal: -0.5086 0.8133 0.2826 - offset: -0.03620543 - vertices: p2(v9) p5(v8) p1(v4) - neighboring facets: f17 f20 f22 - f22 - flags: top simplicial - normal: -0.432 0.8759 0.2148 - offset: -0.03703814 - vertices: p2(v9) p5(v8) p4(v7) - neighboring facets: f18 f20 f21 Output completed. Verifying that all points are below 2e-15 of all facets. Will make 140 distance computations. rbox 10 D3 | qhull i 14 0 9 6 1 0 6 9 0 7 0 1 7 9 3 6 3 9 7 1 4 7 4 3 7 3 4 6 5 1 6 4 5 6 2 4 1 5 2 1 2 5 4 rbox 10 D3 | qhull p 3 9 -0.0222149361131852 -0.366434993563625 0.3270621312102882 -0.06676722137887703 -0.1566931052661437 0.4589771055234383 0.02820502736438535 0.04189077954915421 0.05832764185809314 0.3126723396709863 0.08400649026409401 -0.1029227018383543 0.1781470954214661 0.1182274414396169 0.04860343742054274 -0.1220315663349177 0.01546165115708642 -0.1360330368727753 -0.3072535691850387 -0.01073880122111998 -0.4870359524963758 0.3867462923626847 0.04492879989084675 0.118335500935405 0.3789805913148268 -0.4732086509216658 -0.2177962499836425 rbox 10 D3 | qhull o 3 10 14 21 -0.0222149361131852 -0.366434993563625 0.3270621312102882 -0.06676722137887703 -0.1566931052661437 0.4589771055234383 0.02820502736438535 0.04189077954915421 0.05832764185809314 0.3126723396709863 0.08400649026409401 -0.1029227018383543 0.1781470954214661 0.1182274414396169 0.04860343742054274 -0.1220315663349177 0.01546165115708642 -0.1360330368727753 -0.3072535691850387 -0.01073880122111998 -0.4870359524963758 0.3867462923626847 0.04492879989084675 0.118335500935405 -0.1352406177997967 0.01093378431250691 -0.2358910583293913 0.3789805913148268 -0.4732086509216658 -0.2177962499836425 3 0 9 6 3 1 0 6 3 9 0 7 3 0 1 7 3 9 3 6 3 3 9 7 3 1 4 7 3 4 3 7 3 3 4 6 3 5 1 6 3 4 5 6 3 2 4 1 3 5 2 1 3 2 5 4 rbox 10 D3 | qhull Fx 9 0 1 2 3 4 5 6 7 9 rbox 27 M1,0,1 | qhull Qc Convex hull of 27 points in 3-d: Number of vertices: 8 Number of coplanar points: 18 Number of facets: 6 Number of non-simplicial facets: 6 Statistics for: rbox 27 M1,0,1 | qhull Qc Number of points processed: 8 Number of hyperplanes created: 11 Number of distance tests for qhull: 297 Number of distance tests for merging: 90 Number of distance tests for checking: 168 Number of merged facets: 6 CPU seconds to compute hull (after input): 0 rbox 50 D3 s | qhull C0.1 Qc Pd0d1d2 Pg s p Tcv Convex hull of 50 points in 3-d: Number of vertices: 17 Number of coplanar points: 33 Number of facets: 11 Number of 'good' facets: 1 Statistics for: rbox 50 D3 s | qhull C0.1 Qc Pd0d1d2 Pg s p Tcv Number of points processed: 50 Number of hyperplanes created: 236 Number of distance tests for qhull: 1191 Number of distance tests for merging: 3250 Number of distance tests for checking: 1146 Number of merged facets: 85 CPU seconds to compute hull (after input): 0.001 Maximum distance of vertex below facet: -0.24 (0.8x) 3 4 0.4995640899182717 0.005583735684776723 0.02011322848106416 0.3642936952899509 -0.2163723184172344 -0.2654677445467591 0.39379735093457 0.04855022442420501 -0.3042474685273066 0.397166795352245 -0.07497301400429786 -0.2943426300092109 Output completed. Verifying that all points are below outer planes of all facets. Will make 50 distance computations. rbox 10 D2 P0 P1e-15 | qhull d Qc FP s Tcv Delaunay triangulation by the convex hull of 12 points in 3-d: Number of input sites: 11 Number of nearly incident points: 1 Number of Delaunay regions: 16 Statistics for: rbox 10 D2 P0 P1e-15 | qhull d Qc FP s Tcv Number of points processed: 11 Number of hyperplanes created: 33 Number of facets in hull: 18 Number of distance tests for qhull: 107 CPU seconds to compute hull (after input): 0 1 0 1 12 1e-15 Output completed. Verifying that all points are below outer planes of all facets. Will make 192 distance computations. rbox 100 s | qhull C-0.003 Qc FP s Convex hull of 100 points in 3-d: Number of vertices: 90 Number of coplanar points: 10 Number of facets: 118 Number of non-simplicial facets: 46 Statistics for: rbox 100 s | qhull C-0.003 Qc FP s Number of points processed: 90 Number of hyperplanes created: 404 Number of distance tests for qhull: 1996 Number of distance tests for merging: 3783 Number of distance tests for checking: 1381 Number of merged facets: 105 CPU seconds to compute hull (after input): 0 Maximum distance of point above facet: 0.0057 (0.6x) Maximum distance of vertex below facet: -0.0087 (1.0x) 10 29 92 222 0.05221620842441997 49 2 292 0.03790045221711884 99 9 336 0.02993864679572162 54 84 340 0.06479664045626413 54 72 226 0.03827167959574595 96 6 368 0.02282529175708784 19 1 372 0.01048228658130246 69 26 409 0.04998878658421259 19 66 371 0.008281093788857875 19 45 371 0.04608027722786196 rbox 100 s D2 | qhull C0.1 i Fx Tcv 6 4 28 77 70 6 68 70 6 68 4 28 77 6 4 28 77 70 6 68 Output completed. Verifying that all points are below outer planes of all facets. Will make 600 distance computations. rbox 4 s D3 | qhull Qc Ghipv Tcv {appearance {+edge -evert linewidth 2} LIST # rbox 4 s D3 | qhull Qc Ghipv Tcv {appearance {-edge -normal normscale 0} { INST geom {define vsphere OFF 18 32 48 0 0 1 1 0 0 0 1 0 -1 0 0 0 -1 0 0 0 -1 0.707107 0 0.707107 0 -0.707107 0.707107 0.707107 -0.707107 0 -0.707107 0 0.707107 -0.707107 -0.707107 0 0 0.707107 0.707107 -0.707107 0.707107 0 0.707107 0.707107 0 0.707107 0 -0.707107 0 0.707107 -0.707107 -0.707107 0 -0.707107 0 -0.707107 -0.707107 3 0 6 11 3 0 7 6 3 0 9 7 3 0 11 9 3 1 6 8 3 1 8 14 3 1 13 6 3 1 14 13 3 2 11 13 3 2 12 11 3 2 13 15 3 2 15 12 3 3 9 12 3 3 10 9 3 3 12 16 3 3 16 10 3 4 7 10 3 4 8 7 3 4 10 17 3 4 17 8 3 5 14 17 3 5 15 14 3 5 16 15 3 5 17 16 3 6 13 11 3 7 8 6 3 9 10 7 3 11 12 9 3 14 8 17 3 15 13 14 3 16 12 15 3 17 10 16 } transforms { TLIST 0.009951 0 0 0 # v3 0 0.009951 0 0 0 0 0.009951 0 -0.04234 -0.2077 -0.4529 # p3 1 0.009951 0 0 0 # v2 0 0.009951 0 0 0 0 0.009951 0 0.004313 -0.4976 0.04904 # p2 1 0.009951 0 0 0 # v1 0 0.009951 0 0 0 0 0.009951 0 -0.4876 0.03313 -0.1055 # p0 1 0.009951 0 0 0 # v4 0 0.009951 0 0 0 0 0.009951 0 -0.3939 -0.1068 -0.2889 # p1 1 }}} { OFF 3 1 1 # f1 -0.04933 -0.2152 -0.4566 -0.002675 -0.5051 0.04532 -0.4946 0.02557 -0.1092 3 0 1 2 0.1808 0.1547 0.3302 1.0 } VECT 1 2 1 2 1 # intersect f1 f2 0.004313 -0.4976 0.04904 # projected p2 -0.4876 0.03313 -0.1055 # projected p0 0 0 0 1.0 VECT 1 2 1 2 1 # intersect f1 f3 -0.04234 -0.2077 -0.4529 # projected p3 -0.4876 0.03313 -0.1055 # projected p0 0 0 0 1.0 VECT 1 2 1 2 1 # intersect f1 f4 -0.04234 -0.2077 -0.4529 # projected p3 0.004313 -0.4976 0.04904 # projected p2 0 0 0 1.0 { OFF 3 1 1 # f2 0.01247 -0.4904 0.04773 -0.3857 -0.09961 -0.2902 -0.4795 0.04031 -0.1068 3 0 1 2 0.8726 0.828 0.4402 1.0 } VECT 1 2 1 2 1 # intersect f2 f3 -0.3939 -0.1068 -0.2889 # projected p1 -0.4876 0.03313 -0.1055 # projected p0 0 0 0 1.0 VECT 1 2 1 2 1 # intersect f2 f4 -0.3939 -0.1068 -0.2889 # projected p1 0.004313 -0.4976 0.04904 # projected p2 0 0 0 1.0 { OFF 3 1 1 # f3 -0.3931 -0.1153 -0.282 -0.04157 -0.2162 -0.446 -0.4869 0.02464 -0.09863 3 0 1 2 0.5351 0.1123 0.8138 1.0 } VECT 1 2 1 2 1 # intersect f3 f4 -0.3939 -0.1068 -0.2889 # projected p1 -0.04234 -0.2077 -0.4529 # projected p3 0 0 0 1.0 { OFF 3 1 1 # f4 -0.03767 -0.1989 -0.4482 -0.3892 -0.09803 -0.2843 0.008983 -0.4888 0.05366 3 0 1 2 0.7133 0.8999 0.7112 1.0 } } Output completed. Verifying that all points are below 2.1e-15 of all facets. Will make 16 distance computations. rbox 6 D4 | qhull f Tcv Vertices and facets: - p3(v5): 0.1 -0.13 -0.17 -0.42 - p0(v4): -0.33 -0.43 -0.46 0.15 - p2(v3): 0.11 0.4 -0.063 -0.18 - p1(v1): -0.35 -0.24 0.14 -0.18 - p4(v2): 0.14 -0.34 -0.084 0.087 - p5(v6): -0.25 -0.5 0.22 -0.033 - f4 - flags: bottom simplicial - normal: -0.6536 0.3379 -0.424 -0.5281 - offset: -0.1850304 - vertices: p3(v5) p0(v4) p2(v3) p1(v1) - neighboring facets: f6 f8 f10 f5 - f5 - flags: top simplicial - normal: 0.6142 0.09488 -0.7743 0.1197 - offset: -0.1313181 - vertices: p3(v5) p0(v4) p2(v3) p4(v2) - neighboring facets: f7 f9 f11 f4 - f6 - flags: top simplicial - normal: -0.4209 0.3853 0.2879 0.7691 - offset: 0.04819078 - vertices: p5(v6) p0(v4) p2(v3) p1(v1) - neighboring facets: f4 f8 f10 f7 - f7 - flags: bottom simplicial - normal: -0.1759 0.3066 0.2842 0.8912 - offset: 0.07466537 - vertices: p5(v6) p0(v4) p2(v3) p4(v2) - neighboring facets: f5 f9 f11 f6 - f8 - flags: bottom simplicial - normal: 0.2584 0.07433 0.814 -0.515 - offset: -0.09844114 - vertices: p5(v6) p3(v5) p2(v3) p1(v1) - neighboring facets: f4 f6 f10 f9 - f9 - flags: top simplicial - normal: 0.6576 -0.06072 0.7252 -0.195 - offset: -0.03612816 - vertices: p5(v6) p3(v5) p2(v3) p4(v2) - neighboring facets: f5 f7 f11 f8 - f10 - flags: top simplicial - normal: -0.3537 -0.6003 -0.2017 -0.6883 - offset: -0.3651888 - vertices: p5(v6) p3(v5) p0(v4) p1(v1) - neighboring facets: f4 f6 f8 f11 - f11 - flags: bottom simplicial - normal: 0.2962 -0.865 -0.2123 -0.3449 - offset: -0.3220787 - vertices: p5(v6) p3(v5) p0(v4) p4(v2) - neighboring facets: f5 f7 f9 f10 Output completed. Verifying that all points are below 3e-15 of all facets. Will make 48 distance computations. rbox 6 D4 | qhull i 8 0 3 2 1 3 0 2 4 5 0 2 1 0 5 2 4 3 5 2 1 5 3 2 4 5 3 0 1 3 5 0 4 rbox 6 D4 | qhull p 4 6 -0.3257826863096865 -0.4296101703584289 -0.4581337649916613 0.1458114577883961 -0.3468340047139991 -0.2391184267952278 0.1365988111464296 -0.1837860440684352 0.1079548672847029 0.397449696341017 -0.062960620096848 -0.1791453880063681 0.1034612661259819 -0.1265049433582509 -0.1685859450777862 -0.4239815160855479 0.1426585555473888 -0.3376619446442108 -0.08430490557505277 0.08744874697872318 -0.2489141260729303 -0.4997188728300099 0.224904344160952 -0.03269336003129686 rbox 6 D4 | qhull o 4 6 8 16 -0.3257826863096865 -0.4296101703584289 -0.4581337649916613 0.1458114577883961 -0.3468340047139991 -0.2391184267952278 0.1365988111464296 -0.1837860440684352 0.1079548672847029 0.397449696341017 -0.062960620096848 -0.1791453880063681 0.1034612661259819 -0.1265049433582509 -0.1685859450777862 -0.4239815160855479 0.1426585555473888 -0.3376619446442108 -0.08430490557505277 0.08744874697872318 -0.2489141260729303 -0.4997188728300099 0.224904344160952 -0.03269336003129686 4 0 3 2 1 4 3 0 2 4 4 5 0 2 1 4 0 5 2 4 4 3 5 2 1 4 5 3 2 4 4 5 3 0 1 4 3 5 0 4 rbox 1000 s D2 | qhull FA Tcv Convex hull of 1000 points in 2-d: Number of vertices: 1000 Number of facets: 1000 Statistics for: rbox 1000 s D2 | qhull FA Tcv Number of points processed: 1000 Number of hyperplanes created: 1997 Number of distance tests for qhull: 13977 CPU seconds to compute hull (after input): 0.044 Total facet area: 3.1415592 Total volume: 0.7853647 qhull output completed. Verifying that 1000 points are below 1.3e-15 of the nearest facet. rbox 1000 s | qhull FA Tcv Convex hull of 1000 points in 3-d: Number of vertices: 1000 Number of facets: 1996 Statistics for: rbox 1000 s | qhull FA Tcv Number of points processed: 1000 Number of hyperplanes created: 5544 Number of distance tests for qhull: 25487 CPU seconds to compute hull (after input): 0.034 Total facet area: 3.1201951 Total volume: 0.51650274 qhull output completed. Verifying that 1000 points are below 2.1e-15 of the nearest facet. rbox c D4 | qhull FA Tcv Convex hull of 16 points in 4-d: Number of vertices: 16 Number of facets: 8 Number of non-simplicial facets: 8 Statistics for: rbox c D4 | qhull FA Tcv Number of points processed: 16 Number of hyperplanes created: 25 Number of distance tests for qhull: 167 Number of distance tests for merging: 510 Number of distance tests for checking: 412 Number of merged facets: 36 CPU seconds to compute hull (after input): 0 Approximate facet area: 8 Approximate volume: 1 Output completed. Verifying that all points are below outer planes of all facets. Will make 128 distance computations. rbox c D5 | qhull FA Tcv Convex hull of 32 points in 5-d: Number of vertices: 32 Number of facets: 10 Number of non-simplicial facets: 10 Statistics for: rbox c D5 | qhull FA Tcv Number of points processed: 32 Number of hyperplanes created: 86 Number of distance tests for qhull: 721 Number of distance tests for merging: 2702 Number of distance tests for checking: 400 Number of merged facets: 210 CPU seconds to compute hull (after input): 0.002 Approximate facet area: 10 Approximate volume: 1 QH7076 qhull input warning: exact merge ('Qx'). Verify may report that a point is outside of a facet. See qh-optq.htm#Qx Output completed. Verifying that all points are below outer planes of all facets. Will make 320 distance computations. rbox c D5 | qhull FA Qt Tcv Convex hull of 32 points in 5-d: Number of vertices: 32 Number of facets: 316 Number of triangulated facets: 10 Statistics for: rbox c D5 | qhull FA Qt Tcv Number of points processed: 32 Number of hyperplanes created: 86 Number of distance tests for qhull: 721 Number of distance tests for merging: 2702 Number of distance tests for checking: 400 Number of merged facets: 210 CPU seconds to compute hull (after input): 0.004 Approximate facet area: 10 Approximate volume: 1 QH7076 qhull input warning: exact merge ('Qx'). Verify may report that a point is outside of a facet. See qh-optq.htm#Qx Output completed. Verifying that all points are below outer planes of all facets. Will make 10112 distance computations. rbox 10 D2 | qhull d FA Tcv Delaunay triangulation by the convex hull of 10 points in 3-d: Number of input sites: 10 Number of Delaunay regions: 14 Statistics for: rbox 10 D2 | qhull d FA Tcv Number of points processed: 10 Number of hyperplanes created: 28 Number of facets in hull: 16 Number of distance tests for qhull: 47 CPU seconds to compute hull (after input): 0 Total facet area: 0.46254269 Output completed. Verifying that all points are below 2.1e-15 of all facets. Will make 140 distance computations. rbox 10 D2 | qhull d Qu FA Tcv Furthest-site Delaunay triangulation by the convex hull of 10 points in 3-d: Number of input sites: 10 Number of Delaunay regions: 2 Statistics for: rbox 10 D2 | qhull d Qu FA Tcv Number of points processed: 10 Number of hyperplanes created: 28 Number of facets in hull: 16 Number of distance tests for qhull: 47 CPU seconds to compute hull (after input): 0 Total facet area: 0.46254269 Output completed. Verifying that all points are below 2.1e-15 of all facets. Will make 20 distance computations. rbox 10 D2 | qhull FA Tcv Convex hull of 10 points in 2-d: Number of vertices: 4 Number of facets: 4 Statistics for: rbox 10 D2 | qhull FA Tcv Number of points processed: 4 Number of hyperplanes created: 5 Number of distance tests for qhull: 51 CPU seconds to compute hull (after input): 0 Total facet area: 2.8999576 Total volume: 0.46254269 Output completed. Verifying that all points are below 1.3e-15 of all facets. Will make 40 distance computations. rbox 10 c D2 | qhull Fx Tcv 4 10 12 13 11 Output completed. Verifying that all points are below 1.3e-15 of all facets. Will make 56 distance computations. rbox 1000 s | qhull FS Tcv 0 2 3.120195135077461 0.516502736886338 qhull output completed. Verifying that 1000 points are below 2.1e-15 of the nearest facet. rbox 10 W0 D2 | qhull p Qc FcC Tcv 2 10 -0.3863076515368257 0.5 -0.05259535978789942 0.5 0.2626424396993987 0.5 0.3748708151978168 0.5 -0.01474997775140219 0.5 0.1582814042067914 0.5 -0.5 0.4508927962285399 -0.5 -0.003085198815060031 -0.3688616616361418 -0.5 -0.2798755283280048 0.5 5 0 0 0 0 5 2 4 5 9 1 2 5 0.003004576780837498 -8.023127287351645e-18 -0.5 0.2239037987067399 -0.4344308308180709 -0.25154259940753 -0.4431538257684129 0.4754463981142699 -0.005718418169504469 0.5 Output completed. Verifying that all points are below outer planes of all facets. Will make 50 distance computations. rbox 4 z h s D2 | qhull Fd s n FD Tcv Convex hull of 4 points in 2-d: Number of vertices: 4 Number of facets: 4 Statistics for: rbox 4 z h s D2 | qhull Fd s n FD Tcv Number of points processed: 4 Number of hyperplanes created: 5 Number of distance tests for qhull: 4 CPU seconds to compute hull (after input): 0 rbox 4 z h s D2 | qhull Fd s n FD Tcv begin 4 3 real 107643.7343385944 -0.2650304141580589 -0.964240052876465 797791.7732245289 -0.6912673062074456 0.7225991360143615 874890.2679778723 0.9916265954087946 0.1291382796771071 864878.4439653738 0.3984446264475182 0.9171923896626583 end Output completed. Verifying that all points are below 2.6e-09 of all facets. Will make 16 distance computations. rbox 6 s D3 | qhull C-0.1 Qc FF s FQ Fi n Fo FQ FI Fm Fn FN FO FO FQ Fs FS FV Fv Tcv Options selected for Qhull 2020.2.r 2020/07/24: run-id 213781421 Centrum-premerge- 0.1 Qcoplanar-keep FFacets-xridge summary FQhull Finner normals Fouter FQhull FIDs Fmerges Fneighbors FNeighbors-vertex FOptions FQhull Fsummary FSize FVertex-average Tcheck-frequently Tverify Fvertices _max-width 0.86 Error-roundoff 6.6e-16 _one-merge 0.3 _near-inside 1.5 Visible-distance 0.1 U-max-coplanar 0.1 Width-outside 0.2 _wide-facet 0.6 Convex hull of 6 points in 3-d: Number of vertices: 4 Number of coplanar points: 2 Number of facets: 4 Statistics for: rbox 6 s D3 | qhull C-0.1 Qc FF s FQ Fi n Fo FQ FI Fm Fn FN FO FO FQ Fs FS FV Fv Tcv Number of points processed: 4 Number of hyperplanes created: 4 Number of distance tests for qhull: 22 CPU seconds to compute hull (after input): 0 Total facet area: 0.82966766 Total volume: 0.010511079 Maximum distance of point above facet: 0.11 (0.4x) Vertices and facets: - p1(v3): -0.3 0.39 -0.092 - p5(v2): 0.4 -0.22 -0.2 - p4(v1): -0.46 -0.19 -0.018 - p2(v4): 0.25 0.28 -0.33 - f1 - flags: top simplicial isarea - area: 0.26 - normal: 0.2054 0.06987 0.9762 - offset: 0.125398 - center: -0.1205015151724569 -0.008790385787885074 -0.1024776532548504 - vertices: p1(v3) p5(v2) p4(v1) - neighboring facets: f2 f3 f4 - f2 - flags: bottom simplicial isarea - area: 0.23 - normal: -0.2032 -0.3001 -0.932 - offset: -0.1680571 - center: 0.06430144219370747 -0.04270356053094847 -0.1805812707066012 - maxoutside: 0.1132672 - coplanar set(furthest p3): p0: 0.07025 -0.4742 -0.142 p3: 0.2976 -0.2965 -0.2712 furthest distance= 0.11 - vertices: p2(v4) p5(v2) p4(v1) - neighboring facets: f1 f3 f4 - f3 - flags: top simplicial isarea - area: 0.18 - normal: -0.3912 -0.01238 -0.9202 - offset: -0.1989549 - center: -0.1715856748140029 0.1590825675964338 -0.1454013928109104 - vertices: p2(v4) p1(v3) p4(v1) - neighboring facets: f1 f2 f4 - f4 - flags: bottom simplicial isarea - area: 0.16 - normal: 0.4184 0.3424 0.8413 - offset: 0.07254957 - center: 0.116549362001881 0.1503252206347392 -0.2053893818610149 - vertices: p2(v4) p1(v3) p5(v2) - neighboring facets: f1 f2 f3 rbox 6 s D3 | qhull C-0.1 Qc FF s FQ Fi n Fo FQ FI Fm Fn FN FO FO FQ Fs FS FV Fv Tcv 4 4 0.205360378770873 0.06987429109559466 0.976188864039624 0.1253980026939646 -0.2031613339148238 -0.3001304507855299 -0.9320124381751694 -0.1680570625036091 -0.3911895500493898 -0.01238286325891905 -0.9202268202077502 -0.1989548866041478 0.4183781509471984 0.3424157187037644 0.8412557271095321 0.07254956874669725 4 4 0.205360378770873 0.06987429109559466 0.976188864039624 0.125398002693964 -0.2031613339148238 -0.3001304507855299 -0.9320124381751694 -0.1680570625036098 -0.3911895500493898 -0.01238286325891905 -0.9202268202077502 -0.1989548866041485 0.4183781509471984 0.3424157187037644 0.8412557271095321 0.0725495687466966 4 4 0.205360378770873 0.06987429109559466 0.976188864039624 0.1253980026939626 -0.2031613339148238 -0.3001304507855299 -0.9320124381751694 -0.2813242952138535 -0.3911895500493898 -0.01238286325891905 -0.9202268202077502 -0.1989548866041498 0.4183781509471984 0.3424157187037644 0.8412557271095321 0.07254956874669528 rbox 6 s D3 | qhull C-0.1 Qc FF s FQ Fi n Fo FQ FI Fm Fn FN FO FO FQ Fs FS FV Fv Tcv 4 1 2 3 4 4 0 0 0 0 4 3 1 2 3 3 0 2 3 3 0 1 3 3 0 1 2 6 1 1 3 3 0 2 3 3 1 2 1 1 3 2 0 1 3 3 0 1 Options selected for Qhull 2020.2.r 2020/07/24: run-id 213781421 Centrum-premerge- 0.1 Qcoplanar-keep FFacets-xridge summary FQhull Finner normals Fouter FQhull FIDs Fmerges Fneighbors FNeighbors-vertex FOptions FQhull Fsummary FSize FVertex-average Tcheck-frequently Tverify Fvertices _max-width 0.86 Error-roundoff 6.6e-16 _one-merge 0.3 _near-inside 1.5 Visible-distance 0.1 U-max-coplanar 0.1 Width-outside 0.2 _wide-facet 0.6 rbox 6 s D3 | qhull C-0.1 Qc FF s FQ Fi n Fo FQ FI Fm Fn FN FO FO FQ Fs FS FV Fv Tcv 10 3 6 4 4 4 4 2 0 0 0 2 0.1132672327102437 -1.315898280434284e-15 0 2 0.8296676646636063 0.01051107893821417 3 1 -0.02780909644771785 0.06447846047808484 -0.1584624246583442 4 3 1 5 4 3 2 5 4 3 2 1 4 3 2 1 5 Output completed. Verifying that all points are below outer planes of all facets. Will make 24 distance computations. rbox P0.5,0.5 P0.5,0.5 W0 5 D2 | qhull d FN Qc 7 5 3 1 0 -4 -8 1 1 5 -10 2 -3 -4 -8 4 2 -3 0 1 3 -4 0 -3 3 -10 -8 3 4 -10 2 1 3 rbox 10 D3 | qhull Fa PA5 5 0.2844546842397038 0.1170134053930415 0.1758021655943633 0.07490600482805046 0.2087585943133527 rbox 10 D3 | qhull Fa PF0.4 QH7055 qhull warning: no facets printed 0 set +v === test Qt Fri, Jul 24, 2020 10:27:31 PM rbox c | qhull Qt s o Tcv Convex hull of 8 points in 3-d: Number of vertices: 8 Number of facets: 12 Number of triangulated facets: 6 Statistics for: rbox c | qhull Qt s o Tcv Number of points processed: 8 Number of hyperplanes created: 11 Number of distance tests for qhull: 34 Number of distance tests for merging: 96 Number of distance tests for checking: 100 Number of merged facets: 6 CPU seconds to compute hull (after input): 0 3 8 12 18 -0.5 -0.5 -0.5 -0.5 -0.5 0.5 -0.5 0.5 -0.5 -0.5 0.5 0.5 0.5 -0.5 -0.5 0.5 -0.5 0.5 0.5 0.5 -0.5 0.5 0.5 0.5 3 6 2 0 3 4 6 0 3 5 4 0 3 1 5 0 3 5 6 4 3 6 5 7 3 2 3 0 3 3 1 0 3 6 3 2 3 3 6 7 3 3 5 1 3 5 3 7 Output completed. Verifying that all points are below outer planes of all facets. Will make 96 distance computations. rbox c | qhull Qt f i Vertices and facets: - p6(v6): 0.5 0.5 -0.5 neighbors: f17 f18 f25 f27 f33 f34 - p2(v3): -0.5 0.5 -0.5 neighbors: f17 f29 f33 - p0(v1): -0.5 -0.5 -0.5 neighbors: f17 f18 f21 f22 f29 f30 - p4(v2): 0.5 -0.5 -0.5 neighbors: f18 f21 f25 - p5(v7): 0.5 -0.5 0.5 neighbors: f21 f22 f25 f27 f37 f38 - p1(v4): -0.5 -0.5 0.5 neighbors: f22 f30 f37 - p7(v5): 0.5 0.5 0.5 neighbors: f27 f34 f38 - p3(v8): -0.5 0.5 0.5 neighbors: f29 f30 f33 f34 f37 f38 - f17 - flags: top simplicial tricoplanar keepcentrum - owner of normal & centrum is facet f17 - normal: -0 -0 -1 - offset: -0.5 - center: 0 0 -0.5 - vertices: p6(v6) p2(v3) p0(v1) - neighboring facets: f29 f18 f33 - f18 - flags: bottom simplicial tricoplanar - owner of normal & centrum is facet f17 - normal: -0 -0 -1 - offset: -0.5 - center: 0 0 -0.5 - vertices: p6(v6) p4(v2) p0(v1) - neighboring facets: f21 f17 f25 - f21 - flags: top simplicial tricoplanar keepcentrum - owner of normal & centrum is facet f21 - normal: 0 -1 0 - offset: -0.5 - center: 0 -0.5 0 - vertices: p5(v7) p4(v2) p0(v1) - neighboring facets: f18 f22 f25 - f22 - flags: bottom simplicial tricoplanar - owner of normal & centrum is facet f21 - normal: 0 -1 0 - offset: -0.5 - center: 0 -0.5 0 - vertices: p5(v7) p1(v4) p0(v1) - neighboring facets: f30 f21 f37 - f25 - flags: top simplicial tricoplanar keepcentrum - owner of normal & centrum is facet f25 - normal: 1 -0 -0 - offset: -0.5 - center: 0.5 0 0 - vertices: p5(v7) p6(v6) p4(v2) - neighboring facets: f18 f21 f27 - f27 - flags: bottom simplicial tricoplanar - owner of normal & centrum is facet f25 - normal: 1 -0 -0 - offset: -0.5 - center: 0.5 0 0 - vertices: p5(v7) p6(v6) p7(v5) - neighboring facets: f34 f38 f25 - f29 - flags: bottom simplicial tricoplanar keepcentrum - owner of normal & centrum is facet f29 - normal: -1 -0 -0 - offset: -0.5 - center: -0.5 0 0 - vertices: p3(v8) p2(v3) p0(v1) - neighboring facets: f17 f30 f33 - f30 - flags: top simplicial tricoplanar - owner of normal & centrum is facet f29 - normal: -1 -0 -0 - offset: -0.5 - center: -0.5 0 0 - vertices: p3(v8) p1(v4) p0(v1) - neighboring facets: f22 f29 f37 - f33 - flags: bottom simplicial tricoplanar keepcentrum - owner of normal & centrum is facet f33 - normal: 0 1 -0 - offset: -0.5 - center: 0 0.5 0 - vertices: p3(v8) p6(v6) p2(v3) - neighboring facets: f17 f29 f34 - f34 - flags: top simplicial tricoplanar - owner of normal & centrum is facet f33 - normal: 0 1 -0 - offset: -0.5 - center: 0 0.5 0 - vertices: p3(v8) p6(v6) p7(v5) - neighboring facets: f27 f38 f33 - f37 - flags: top simplicial tricoplanar keepcentrum - owner of normal & centrum is facet f37 - normal: -0 -0 1 - offset: -0.5 - center: 0 0 0.5 - vertices: p3(v8) p5(v7) p1(v4) - neighboring facets: f22 f30 f38 - f38 - flags: bottom simplicial tricoplanar - owner of normal & centrum is facet f37 - normal: -0 -0 1 - offset: -0.5 - center: 0 0 0.5 - vertices: p3(v8) p5(v7) p7(v5) - neighboring facets: f27 f34 f37 12 6 2 0 4 6 0 5 4 0 1 5 0 5 6 4 6 5 7 2 3 0 3 1 0 6 3 2 3 6 7 3 5 1 5 3 7 rbox c | qhull Qt m FM n { Polygon[{{ 0.50000000, 0.50000000, -0.50000000}, { -0.50000000, 0.50000000, -0.50000000}, { -0.50000000, -0.50000000, -0.50000000}}], Polygon[{{ 0.50000000, -0.50000000, -0.50000000}, { 0.50000000, 0.50000000, -0.50000000}, { -0.50000000, -0.50000000, -0.50000000}}], Polygon[{{ 0.50000000, -0.50000000, 0.50000000}, { 0.50000000, -0.50000000, -0.50000000}, { -0.50000000, -0.50000000, -0.50000000}}], Polygon[{{ -0.50000000, -0.50000000, 0.50000000}, { 0.50000000, -0.50000000, 0.50000000}, { -0.50000000, -0.50000000, -0.50000000}}], Polygon[{{ 0.50000000, -0.50000000, 0.50000000}, { 0.50000000, 0.50000000, -0.50000000}, { 0.50000000, -0.50000000, -0.50000000}}], Polygon[{{ 0.50000000, 0.50000000, -0.50000000}, { 0.50000000, -0.50000000, 0.50000000}, { 0.50000000, 0.50000000, 0.50000000}}], Polygon[{{ -0.50000000, 0.50000000, -0.50000000}, { -0.50000000, 0.50000000, 0.50000000}, { -0.50000000, -0.50000000, -0.50000000}}], Polygon[{{ -0.50000000, 0.50000000, 0.50000000}, { -0.50000000, -0.50000000, 0.50000000}, { -0.50000000, -0.50000000, -0.50000000}}], Polygon[{{ 0.50000000, 0.50000000, -0.50000000}, { -0.50000000, 0.50000000, 0.50000000}, { -0.50000000, 0.50000000, -0.50000000}}], Polygon[{{ -0.50000000, 0.50000000, 0.50000000}, { 0.50000000, 0.50000000, -0.50000000}, { 0.50000000, 0.50000000, 0.50000000}}], Polygon[{{ -0.50000000, 0.50000000, 0.50000000}, { 0.50000000, -0.50000000, 0.50000000}, { -0.50000000, -0.50000000, 0.50000000}}], Polygon[{{ 0.50000000, -0.50000000, 0.50000000}, { -0.50000000, 0.50000000, 0.50000000}, { 0.50000000, 0.50000000, 0.50000000}}]} PLOT3D(POLYGONS( [[ 0.50000000, 0.50000000, -0.50000000], [ -0.50000000, 0.50000000, -0.50000000], [ -0.50000000, -0.50000000, -0.50000000]], [[ 0.50000000, -0.50000000, -0.50000000], [ 0.50000000, 0.50000000, -0.50000000], [ -0.50000000, -0.50000000, -0.50000000]], [[ 0.50000000, -0.50000000, 0.50000000], [ 0.50000000, -0.50000000, -0.50000000], [ -0.50000000, -0.50000000, -0.50000000]], [[ -0.50000000, -0.50000000, 0.50000000], [ 0.50000000, -0.50000000, 0.50000000], [ -0.50000000, -0.50000000, -0.50000000]], [[ 0.50000000, -0.50000000, 0.50000000], [ 0.50000000, 0.50000000, -0.50000000], [ 0.50000000, -0.50000000, -0.50000000]], [[ 0.50000000, 0.50000000, -0.50000000], [ 0.50000000, -0.50000000, 0.50000000], [ 0.50000000, 0.50000000, 0.50000000]], [[ -0.50000000, 0.50000000, -0.50000000], [ -0.50000000, 0.50000000, 0.50000000], [ -0.50000000, -0.50000000, -0.50000000]], [[ -0.50000000, 0.50000000, 0.50000000], [ -0.50000000, -0.50000000, 0.50000000], [ -0.50000000, -0.50000000, -0.50000000]], [[ 0.50000000, 0.50000000, -0.50000000], [ -0.50000000, 0.50000000, 0.50000000], [ -0.50000000, 0.50000000, -0.50000000]], [[ -0.50000000, 0.50000000, 0.50000000], [ 0.50000000, 0.50000000, -0.50000000], [ 0.50000000, 0.50000000, 0.50000000]], [[ -0.50000000, 0.50000000, 0.50000000], [ 0.50000000, -0.50000000, 0.50000000], [ -0.50000000, -0.50000000, 0.50000000]], [[ 0.50000000, -0.50000000, 0.50000000], [ -0.50000000, 0.50000000, 0.50000000], [ 0.50000000, 0.50000000, 0.50000000]])); 4 12 -0 -0 -1 -0.5 -0 -0 -1 -0.5 0 -1 0 -0.5 0 -1 0 -0.5 1 -0 -0 -0.5 1 -0 -0 -0.5 -1 -0 -0 -0.5 -1 -0 -0 -0.5 0 1 -0 -0.5 0 1 -0 -0.5 -0 -0 1 -0.5 -0 -0 1 -0.5 rbox c | qhull Qt p o 3 8 -0.5 -0.5 -0.5 -0.5 -0.5 0.5 -0.5 0.5 -0.5 -0.5 0.5 0.5 0.5 -0.5 -0.5 0.5 -0.5 0.5 0.5 0.5 -0.5 0.5 0.5 0.5 3 8 12 18 -0.5 -0.5 -0.5 -0.5 -0.5 0.5 -0.5 0.5 -0.5 -0.5 0.5 0.5 0.5 -0.5 -0.5 0.5 -0.5 0.5 0.5 0.5 -0.5 0.5 0.5 0.5 3 6 2 0 3 4 6 0 3 5 4 0 3 1 5 0 3 5 6 4 3 6 5 7 3 2 3 0 3 3 1 0 3 6 3 2 3 3 6 7 3 3 5 1 3 5 3 7 rbox c | qhull Qt Fx 8 0 1 2 3 4 5 6 7 rbox c | qhull Qt FA s Fa Convex hull of 8 points in 3-d: Number of vertices: 8 Number of facets: 12 Number of triangulated facets: 6 Statistics for: rbox c | qhull Qt FA s Fa Number of points processed: 8 Number of hyperplanes created: 11 Number of distance tests for qhull: 34 Number of distance tests for merging: 90 Number of distance tests for checking: 48 Number of merged facets: 6 CPU seconds to compute hull (after input): 0 Approximate facet area: 6 Approximate volume: 1 12 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 rbox 6 r s c G0.1 D2 | qhull Qt d FA Tcv Delaunay triangulation by the convex hull of 10 points in 3-d: Number of input sites: 10 Number of Delaunay regions: 12 Number of triangulated facets: 3 Statistics for: rbox 6 r s c G0.1 D2 | qhull Qt d FA Tcv Number of points processed: 10 Number of hyperplanes created: 19 Number of facets in hull: 16 Number of distance tests for qhull: 48 Number of distance tests for merging: 170 Number of distance tests for checking: 164 Number of merged facets: 7 CPU seconds to compute hull (after input): 0 Approximate facet area: 0.64951905 Output completed. Verifying that all points are below outer planes of all facets. Will make 120 distance computations. rbox 6 r s c G0.1 D2 | qhull d FA Tcv Delaunay triangulation by the convex hull of 10 points in 3-d: Number of input sites: 10 Number of Delaunay regions: 9 Number of non-simplicial Delaunay regions: 3 Statistics for: rbox 6 r s c G0.1 D2 | qhull d FA Tcv Number of points processed: 10 Number of hyperplanes created: 19 Number of facets in hull: 10 Number of distance tests for qhull: 48 Number of distance tests for merging: 170 Number of distance tests for checking: 164 Number of merged facets: 7 CPU seconds to compute hull (after input): 0 Approximate facet area: 0.64951905 Output completed. Verifying that all points are below outer planes of all facets. Will make 90 distance computations. rbox 6 r s c G0.1 D2 | qhull Qt v p Tcv 2 12 -0.3359969878447703 -0.1939879513790814 -0.3359969878447704 0.1939879513790817 -0.2875 0 0.3359969878447702 -0.1939879513790819 0.3359969878447707 0.1939879513790815 0.2875 0 -2.220446049250313e-16 -0.3453321730569308 -2.220446049250313e-16 -0.3453321730569308 1.110223024625157e-16 0.3453321730569308 1.110223024625157e-16 0.3453321730569308 0 0 0 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 120 distance computations. rbox c | qhull Qt C-0.1 Qc FF s FQ Fi n Fo FQ FI Fm Fn FN FO FO FQ Fs FS FV Fv Tcv Options selected for Qhull 2020.2.r 2020/07/24: run-id 213798228 Qtriangulate Centrum-premerge- 0.1 Qcoplanar-keep FFacets-xridge summary FQhull Finner normals Fouter FQhull FIDs Fmerges Fneighbors FNeighbors-vertex FOptions FQhull Fsummary FSize FVertex-average Tcheck-frequently Tverify Fvertices _max-width 1 Error-roundoff 6.9e-16 _one-merge 0.3 _near-inside 1.5 Visible-distance 0.1 U-max-coplanar 0.1 Width-outside 0.2 _wide-facet 0.6 Convex hull of 8 points in 3-d: Number of vertices: 8 Number of facets: 12 Number of triangulated facets: 6 Statistics for: rbox c | qhull Qt C-0.1 Qc FF s FQ Fi n Fo FQ FI Fm Fn FN FO FO FQ Fs FS FV Fv Tcv Number of points processed: 8 Number of hyperplanes created: 11 Number of distance tests for qhull: 34 Number of distance tests for merging: 102 Number of distance tests for checking: 126 Number of merged facets: 6 CPU seconds to compute hull (after input): 0 Approximate facet area: 6 Approximate volume: 1 Vertices and facets: - p6(v6): 0.5 0.5 -0.5 neighbors: f17 f18 f25 f27 f33 f34 - p2(v3): -0.5 0.5 -0.5 neighbors: f17 f29 f33 - p0(v1): -0.5 -0.5 -0.5 neighbors: f17 f18 f21 f22 f29 f30 - p4(v2): 0.5 -0.5 -0.5 neighbors: f18 f21 f25 - p5(v7): 0.5 -0.5 0.5 neighbors: f21 f22 f25 f27 f37 f38 - p1(v4): -0.5 -0.5 0.5 neighbors: f22 f30 f37 - p7(v5): 0.5 0.5 0.5 neighbors: f27 f34 f38 - p3(v8): -0.5 0.5 0.5 neighbors: f29 f30 f33 f34 f37 f38 - f17 - flags: top simplicial tricoplanar isarea keepcentrum - area: 0.5 - normal: -0 -0 -1 - offset: -0.5 - center: 0 0 -0.5 - vertices: p6(v6) p2(v3) p0(v1) - neighboring facets: f29 f18 f33 - f18 - flags: bottom simplicial tricoplanar isarea - area: 0.5 - normal: -0 -0 -1 - offset: -0.5 - center: 0 0 -0.5 - vertices: p6(v6) p4(v2) p0(v1) - neighboring facets: f21 f17 f25 - f21 - flags: top simplicial tricoplanar isarea keepcentrum - area: 0.5 - normal: 0 -1 0 - offset: -0.5 - center: 0 -0.5 0 - vertices: p5(v7) p4(v2) p0(v1) - neighboring facets: f18 f22 f25 - f22 - flags: bottom simplicial tricoplanar isarea - area: 0.5 - normal: 0 -1 0 - offset: -0.5 - center: 0 -0.5 0 - vertices: p5(v7) p1(v4) p0(v1) - neighboring facets: f30 f21 f37 - f25 - flags: top simplicial tricoplanar isarea keepcentrum - area: 0.5 - normal: 1 -0 -0 - offset: -0.5 - center: 0.5 0 0 - vertices: p5(v7) p6(v6) p4(v2) - neighboring facets: f18 f21 f27 - f27 - flags: bottom simplicial tricoplanar isarea - area: 0.5 - normal: 1 -0 -0 - offset: -0.5 - center: 0.5 0 0 - vertices: p5(v7) p6(v6) p7(v5) - neighboring facets: f34 f38 f25 - f29 - flags: bottom simplicial tricoplanar isarea keepcentrum - area: 0.5 - normal: -1 -0 -0 - offset: -0.5 - center: -0.5 0 0 - vertices: p3(v8) p2(v3) p0(v1) - neighboring facets: f17 f30 f33 - f30 - flags: top simplicial tricoplanar isarea - area: 0.5 - normal: -1 -0 -0 - offset: -0.5 - center: -0.5 0 0 - vertices: p3(v8) p1(v4) p0(v1) - neighboring facets: f22 f29 f37 - f33 - flags: bottom simplicial tricoplanar isarea keepcentrum - area: 0.5 - normal: 0 1 -0 - offset: -0.5 - center: 0 0.5 0 - vertices: p3(v8) p6(v6) p2(v3) - neighboring facets: f17 f29 f34 - f34 - flags: top simplicial tricoplanar isarea - area: 0.5 - normal: 0 1 -0 - offset: -0.5 - center: 0 0.5 0 - vertices: p3(v8) p6(v6) p7(v5) - neighboring facets: f27 f38 f33 - f37 - flags: top simplicial tricoplanar isarea keepcentrum - area: 0.5 - normal: -0 -0 1 - offset: -0.5 - center: 0 0 0.5 - vertices: p3(v8) p5(v7) p1(v4) - neighboring facets: f22 f30 f38 - f38 - flags: bottom simplicial tricoplanar isarea - area: 0.5 - normal: -0 -0 1 - offset: -0.5 - center: 0 0 0.5 - vertices: p3(v8) p5(v7) p7(v5) - neighboring facets: f27 f34 f37 rbox c | qhull Qt C-0.1 Qc FF s FQ Fi n Fo FQ FI Fm Fn FN FO FO FQ Fs FS FV Fv Tcv 4 12 -0 -0 -1 -0.4999999999999993 -0 -0 -1 -0.4999999999999993 0 -1 0 -0.4999999999999993 0 -1 0 -0.4999999999999993 1 -0 -0 -0.4999999999999993 1 -0 -0 -0.4999999999999993 -1 -0 -0 -0.4999999999999993 -1 -0 -0 -0.4999999999999993 0 1 -0 -0.4999999999999993 0 1 -0 -0.4999999999999993 -0 -0 1 -0.4999999999999993 -0 -0 1 -0.4999999999999993 4 12 -0 -0 -1 -0.5 -0 -0 -1 -0.5 0 -1 0 -0.5 0 -1 0 -0.5 1 -0 -0 -0.5 1 -0 -0 -0.5 -1 -0 -0 -0.5 -1 -0 -0 -0.5 0 1 -0 -0.5 0 1 -0 -0.5 -0 -0 1 -0.5 -0 -0 1 -0.5 4 12 -0 -0 -1 -0.5000000000000013 -0 -0 -1 -0.5000000000000013 0 -1 0 -0.5000000000000013 0 -1 0 -0.5000000000000013 1 -0 -0 -0.5000000000000013 1 -0 -0 -0.5000000000000013 -1 -0 -0 -0.5000000000000013 -1 -0 -0 -0.5000000000000013 0 1 -0 -0.5000000000000013 0 1 -0 -0.5000000000000013 -0 -0 1 -0.5000000000000013 -0 -0 1 -0.5000000000000013 rbox c | qhull Qt C-0.1 Qc FF s FQ Fi n Fo FQ FI Fm Fn FN FO FO FQ Fs FS FV Fv Tcv 12 17 18 21 22 25 27 29 30 33 34 37 38 12 0 0 0 0 0 0 0 0 0 0 0 0 12 3 6 1 8 3 2 0 4 3 1 3 4 3 7 2 10 3 1 2 5 3 9 11 4 3 0 7 8 3 3 6 10 3 0 6 9 3 5 11 8 3 3 7 11 3 5 9 10 8 6 7 3 2 1 0 6 3 10 3 7 3 8 0 6 6 11 9 8 6 7 10 3 4 1 2 6 11 5 4 2 3 10 6 9 5 4 1 0 8 3 11 5 9 Options selected for Qhull 2020.2.r 2020/07/24: run-id 213798228 Qtriangulate Centrum-premerge- 0.1 Qcoplanar-keep FFacets-xridge summary FQhull Finner normals Fouter FQhull FIDs Fmerges Fneighbors FNeighbors-vertex FOptions FQhull Fsummary FSize FVertex-average Tcheck-frequently Tverify Fvertices _max-width 1 Error-roundoff 6.9e-16 _one-merge 0.3 _near-inside 1.5 Visible-distance 0.1 U-max-coplanar 0.1 Width-outside 0.2 _wide-facet 0.6 rbox c | qhull Qt C-0.1 Qc FF s FQ Fi n Fo FQ FI Fm Fn FN FO FO FQ Fs FS FV Fv Tcv 10 3 8 8 12 8 12 0 0 0 6 2 1.387359992873471e-15 -6.936799964367356e-16 0 2 6 1 3 1 0 0 0 12 3 6 2 0 3 6 4 0 3 5 4 0 3 5 1 0 3 5 6 4 3 5 6 7 3 3 2 0 3 3 1 0 3 3 6 2 3 3 6 7 3 3 5 1 3 3 5 7 Output completed. Verifying that all points are below outer planes of all facets. Will make 96 distance computations. rbox 6 r s c G0.1 D2 P0.1,0.1 | qhull s FP d FO Qt Options selected for Qhull 2020.2.r 2020/07/24: run-id 213798228 summary FPoint-nearest delaunay Qtriangulate _pre-merge _zero-centrum Pgood Qcoplanar _max-width 1 Error-roundoff 6.9e-16 _one-merge 4.9e-15 _near-inside 2.4e-14 Visible-distance 1.4e-15 U-max-coplanar 1.4e-15 Width-outside 2.8e-15 _wide-facet 8.3e-15 Delaunay triangulation by the convex hull of 11 points in 3-d: Number of input sites: 10 Number of nearly incident points: 1 Number of Delaunay regions: 12 Number of triangulated facets: 3 Statistics for: rbox 6 r s c G0.1 D2 P0.1,0.1 | qhull s FP d FO Qt Number of points processed: 10 Number of hyperplanes created: 19 Number of facets in hull: 16 Number of distance tests for qhull: 79 Number of distance tests for merging: 153 Number of distance tests for checking: 100 Number of merged facets: 6 CPU seconds to compute hull (after input): 0 1 0 10 36 0 rbox 100 W0 | qhull Tv Q11 FO Options selected for Qhull 2020.2.r 2020/07/24: run-id 213798228 Tverify Q11-trinormals Qtriangulate _pre-merge _zero-centrum _max-width 1 Error-roundoff 6.9e-16 _one-merge 4.9e-15 _near-inside 2.4e-14 Visible-distance 1.4e-15 U-max-coplanar 1.4e-15 Width-outside 2.8e-15 _wide-facet 8.3e-15 Convex hull of 100 points in 3-d: Number of vertices: 45 Number of facets: 86 Number of triangulated facets: 33 Statistics for: rbox 100 W0 | qhull Tv Q11 FO Number of points processed: 52 Number of hyperplanes created: 171 Number of distance tests for qhull: 1575 Number of distance tests for merging: 1368 Number of distance tests for checking: 1131 Number of merged facets: 41 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 8600 distance computations. set +v === test unbounded intersection Fri, Jul 24, 2020 10:27:32 PM rbox c | qhull PD0:0.5 n | qhull H0 Fp Tcv 3 5 -0.5 -0.5 -0.5 -0.5 0.5 -0.5 -0.5 -0.5 0.5 -0.5 0.5 0.5 -10.101 -10.101 -10.101 Output completed. Verifying that all points are below outer planes of all facets. Will make 25 distance computations. rbox 1000 W1e-3 D3 | qhull PA8 Fa FS s n Tcv Convex hull of 1000 points in 3-d: Number of vertices: 156 Number of facets: 308 Number of 'good' facets: 8 Statistics for: rbox 1000 W1e-3 D3 | qhull PA8 Fa FS s n Tcv Number of points processed: 203 Number of hyperplanes created: 1043 Number of distance tests for qhull: 21452 CPU seconds to compute hull (after input): 0.005 Total facet area: 5.8817432 Total volume: 0.99685163 8 0.1446087232094601 0.1622198334884075 0.2057158590759608 0.1567143851824352 0.188985866819172 0.1580674614313252 0.1616733826473111 0.1767351337533958 0 2 5.881743214947513 0.9968516315221345 4 8 1.009144997325421e-05 0.9999999999463923 2.319049754624652e-06 -0.4999875785488853 -1.229609861584452e-05 8.587946880918045e-05 0.9999999962367613 -0.500004859549355 -1.383340239672454e-05 -0.9999999998842694 6.332306547224586e-06 -0.4999917156571327 1.802476239613105e-05 -1.901476191096464e-05 0.9999999996567733 -0.4999909156385879 0.9999999996788914 1.780140020603311e-05 -1.803683546259361e-05 -0.4999971349013697 3.470111681088057e-06 -3.668365732095583e-05 -0.9999999993211337 -0.4999893476858696 -1.633273154317779e-05 -0.9999999998072314 1.08985791646657e-05 -0.4999921708899001 -0.9999999997878146 -2.055073082985623e-05 -1.427680287303445e-06 -0.4999990322171605 Output completed. Verifying that all points are below outer planes of all facets. Will make 8000 distance computations. rbox 1000 W1e-3 D3 | qhull C-0.01 PM10 Fm n Tcv Qc 10 1 1 5 8 6 0 6 2 7 10 4 10 0.6345454980886096 0.2737427089707436 0.7227841587506171 -0.7458921924784656 -0.00253733560834815 0.666653414016696 0.7453635270845322 -0.6767722083805112 -0.003237401631533091 0.002761552371517554 -0.9999909464886048 -0.4969398742962436 -0.0004022623770974538 0.9999997831336711 0.0005214571799133833 -0.5000167453415887 -0.999601787347817 0.0214081839262726 0.01838359029211947 -0.4985486000821885 -0.4745617604911457 -0.2935495843214587 0.8298311738084099 -0.7523676152838523 -0.005480509661076107 -0.9999701072857251 0.005454223027194169 -0.4992904789191579 -0.9987007292177809 -0.05077399000218431 -0.004342280406757339 -0.5182179901342427 0.001196850675493193 0.0003334814784797861 0.9999992281689842 -0.4989807987213126 0.9999992961453315 0.00118637926097064 1.459763172590229e-05 -0.4998611663332402 Output completed. Verifying that all points are below outer planes of all facets. Will make 10000 distance computations. rbox 1000 W1e-3 D3 | qhull C-0.01 PA8 PG n Tcv Qc 4 12 0.6345454980886096 0.2737427089707436 0.7227841587506171 -0.7458921924784656 -0.00253733560834815 0.666653414016696 0.7453635270845322 -0.6767722083805112 -0.9785529186794025 -0.009694358843403266 -0.2057673558916428 -0.5832522471275383 0.8278306348810541 -0.3414688798813042 -0.4450791435520636 -0.7665474225756105 0.7383776593319754 -0.4655216164679661 0.4879426777814019 -0.7788991125303445 0.2008161614085187 -0.8823413491644904 0.4256132198037728 -0.6982307124493007 0.41932306725662 0.6721295192910486 -0.6102541065524131 -0.7755692997856908 -0.3210285130221472 0.4863414284958994 -0.8126578054478755 -0.7591490151594069 -0.4745617604911457 -0.2935495843214587 0.8298311738084099 -0.7523676152838523 -0.8238864443814345 -0.556605789918439 0.1067760337987315 -0.695666244857558 -0.5357402012449896 -0.5359428531021374 -0.6524934443952053 -0.811263040246498 0.6755431502353132 -0.2163920762108173 0.7048517017950092 -0.7475007704997935 Output completed. Verifying that all points are below outer planes of all facets. Will make 8000 distance computations. rbox 10 | qhull FO Tz TO q_test.log.1 cat q_test.log.1 Options selected for Qhull 2020.2.r 2020/07/24: run-id 213815035 Tz-stdout TOutput-file q_test.log.1 _pre-merge _zero-centrum _max-width 0.92 Error-roundoff 6.8e-16 _one-merge 4.8e-15 _near-inside 2.4e-14 Visible-distance 1.4e-15 U-max-coplanar 1.4e-15 Width-outside 2.7e-15 _wide-facet 8.2e-15 Convex hull of 10 points in 3-d: Number of vertices: 10 Number of facets: 16 Statistics for: rbox 10 | qhull FO Tz TO q_test.log.1 Number of points processed: 10 Number of hyperplanes created: 26 Number of distance tests for qhull: 43 CPU seconds to compute hull (after input): 0 set +v === check Delaunay/Voronoi Fri, Jul 24, 2020 10:27:33 PM rbox 10 D2 | qhull d Tcv Delaunay triangulation by the convex hull of 10 points in 3-d: Number of input sites: 10 Number of Delaunay regions: 14 Statistics for: rbox 10 D2 | qhull d Tcv Number of points processed: 10 Number of hyperplanes created: 28 Number of facets in hull: 16 Number of distance tests for qhull: 47 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below 2.1e-15 of all facets. Will make 140 distance computations. rbox 10 D2 | qhull d Qz Tcv Delaunay triangulation by the convex hull of 11 points in 3-d: Number of input sites and at-infinity: 11 Number of Delaunay regions: 14 Statistics for: rbox 10 D2 | qhull d Qz Tcv Number of points processed: 11 Number of hyperplanes created: 30 Number of facets in hull: 18 Number of distance tests for qhull: 55 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below 2.1e-15 of all facets. Will make 154 distance computations. rbox 10 D3 | qhull d Tcv Delaunay triangulation by the convex hull of 10 points in 4-d: Number of input sites: 10 Number of Delaunay regions: 18 Statistics for: rbox 10 D3 | qhull d Tcv Number of points processed: 10 Number of hyperplanes created: 43 Number of facets in hull: 27 Number of distance tests for qhull: 66 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below 2.9e-15 of all facets. Will make 180 distance computations. rbox c | qhull d Qz Ft Tcv 3 10 12 3 -0.5 -0.5 -0.5 -0.5 -0.5 0.5 -0.5 0.5 -0.5 -0.5 0.5 0.5 0.5 -0.5 -0.5 0.5 -0.5 0.5 0.5 0.5 -0.5 0.5 0.5 0.5 0 0 0 0 0 0 4 9 1 2 0 4 9 2 4 0 4 9 4 1 0 4 9 7 5 4 4 9 6 7 4 4 9 7 6 2 4 9 2 6 4 4 9 5 7 1 4 9 5 1 4 4 9 7 3 1 4 9 1 3 2 4 9 3 7 2 Output completed. Verifying that all points are below outer planes of all facets. Will make 9 distance computations. rbox 10 s D2 c | qhull d Tcv Delaunay triangulation by the convex hull of 14 points in 3-d: Number of input sites: 14 Number of Delaunay regions: 15 Number of non-simplicial Delaunay regions: 1 Statistics for: rbox 10 s D2 c | qhull d Tcv Number of points processed: 14 Number of hyperplanes created: 32 Number of facets in hull: 16 Number of distance tests for qhull: 115 Number of distance tests for merging: 296 Number of distance tests for checking: 272 Number of merged facets: 8 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 210 distance computations. rbox 10 s D2 | qhull d Tcv Qz Q8 Delaunay triangulation by the convex hull of 11 points in 3-d: Number of input sites and at-infinity: 11 Number of Delaunay regions: 1 Number of non-simplicial Delaunay regions: 1 Statistics for: rbox 10 s D2 | qhull d Tcv Qz Q8 Number of points processed: 11 Number of hyperplanes created: 19 Number of facets in hull: 11 Number of distance tests for qhull: 54 Number of distance tests for merging: 201 Number of distance tests for checking: 204 Number of merged facets: 7 CPU seconds to compute hull (after input): 0 QH7077 qhull input warning: no outer plane check ('Q5') or no processing of near-inside points ('Q8'). Verify may report that a point is outside of a facet. Output completed. Verifying that all points are below outer planes of all facets. Will make 11 distance computations. rbox 10 D2 | qhull d Tcv p 3 10 -0.02222276248244826 -0.4979727817680433 0.2484707425541546 -0.4285431913366012 0.4745826469497594 0.4088779556267987 0.3105396575392593 0.2400179190933871 0.1540434803905201 -0.01883958887200765 0.3630260628303755 0.13214285240299 0.3790312361708201 0.3779794437605696 0.2865331378987296 -0.2994955874043476 0.3776609263174803 0.2323253821416525 0.3471817493878135 0.08365533089605659 0.1275333814953112 -0.00485819764887746 0.3482682405489201 0.121314369459436 0.3443122672329771 -0.1437312230875075 0.1392096018573439 0.309330780347186 -0.07758103877080702 0.1017043492469565 Output completed. Verifying that all points are below 2.1e-15 of all facets. Will make 140 distance computations. rbox 10 D2 | qhull d Tcv i 14 9 7 0 8 9 0 3 4 1 3 7 4 7 2 4 0 5 1 7 5 0 5 3 1 3 5 7 6 7 9 6 2 7 8 6 9 6 8 4 2 6 4 Output completed. Verifying that all points are below 2.1e-15 of all facets. Will make 140 distance computations. rbox 10 D2 | qhull d Tcv o 3 10 14 21 -0.02222276248244826 -0.4979727817680433 0.2484707425541546 -0.4285431913366012 0.4745826469497594 0.4088779556267987 0.3105396575392593 0.2400179190933871 0.1540434803905201 -0.01883958887200765 0.3630260628303755 0.13214285240299 0.3790312361708201 0.3779794437605696 0.2865331378987296 -0.2994955874043476 0.3776609263174803 0.2323253821416525 0.3471817493878135 0.08365533089605659 0.1275333814953112 -0.00485819764887746 0.3482682405489201 0.121314369459436 0.3443122672329771 -0.1437312230875075 0.1392096018573439 0.309330780347186 -0.07758103877080702 0.1017043492469565 3 9 7 0 3 8 9 0 3 3 4 1 3 3 7 4 3 7 2 4 3 0 5 1 3 7 5 0 3 5 3 1 3 3 5 7 3 6 7 9 3 6 2 7 3 8 6 9 3 6 8 4 3 2 6 4 Output completed. Verifying that all points are below 2.1e-15 of all facets. Will make 140 distance computations. rbox 10 D2 | qhull v Tcv o 2 15 10 1 -10.101 -10.101 -0.1294381801544404 -0.07247409101984714 0.08267689532419747 -0.2397644955865706 0.1295260566906465 1.716033573116837 0.1740355150742391 0.5317519038435655 0.1851415205797575 0.3882545794457364 -0.9065939866848107 -0.2962957610652135 -0.1954805620516266 -0.07111892482963184 -0.1407581310832468 0.7233857048236082 -0.1676297826663962 0.2080621273999375 0.05868313821742954 0.06632066014880154 0.08806341399736994 0.1054080604689985 0.4761588899009253 -0.03168366595227294 3.094213357897477 -0.064721945677682 0.5410515627308725 0.2115615434955919 5 7 1 2 0 6 4 8 3 0 6 3 14 5 11 4 9 4 3 8 6 14 5 4 3 0 13 4 9 7 6 8 5 14 11 10 12 13 7 11 5 4 9 7 1 10 4 13 0 2 12 4 12 2 1 10 Output completed. Verifying that all points are below 2.1e-15 of all facets. Will make 140 distance computations. rbox 10 D2 | qhull v Tcv p 2 14 -0.1294381801544404 -0.07247409101984714 0.08267689532419747 -0.2397644955865706 0.1295260566906465 1.716033573116837 0.1740355150742391 0.5317519038435655 0.1851415205797575 0.3882545794457364 -0.9065939866848107 -0.2962957610652135 -0.1954805620516266 -0.07111892482963184 -0.1407581310832468 0.7233857048236082 -0.1676297826663962 0.2080621273999375 0.05868313821742954 0.06632066014880154 0.08806341399736994 0.1054080604689985 0.4761588899009253 -0.03168366595227294 3.094213357897477 -0.064721945677682 0.5410515627308725 0.2115615434955919 Output completed. Verifying that all points are below 2.1e-15 of all facets. Will make 140 distance computations. rbox 10 D2 | qhull v Tcv G {appearance {linewidth 3} LIST # rbox 10 D2 | qhull v Tcv G {appearance {+edge -face} OFF 15 10 1 # Voronoi centers and cells 0 0 0 # infinity not used # 1 f8 -0.1294381801544404 -0.07247409101984714 0 # 2 f11 0.08267689532419747 -0.2397644955865706 0 # 3 f12 0.1295260566906465 1.716033573116837 0 # 4 f14 0.1740355150742391 0.5317519038435655 0 # 5 f15 0.1851415205797575 0.3882545794457364 0 # 6 f19 -0.9065939866848107 -0.2962957610652135 0 # 7 f20 -0.1954805620516266 -0.07111892482963184 0 # 8 f21 -0.1407581310832468 0.7233857048236082 0 # 9 f22 -0.1676297826663962 0.2080621273999375 0 # 10 f23 0.05868313821742954 0.06632066014880154 0 # 11 f24 0.08806341399736994 0.1054080604689985 0 # 12 f25 0.4761588899009253 -0.03168366595227294 0 # 13 f26 3.094213357897477 -0.064721945677682 0 # 14 f27 0.5410515627308725 0.2115615434955919 0 4 7 1 2 6 # p0(v3) 3 8 3 6 # p1(v1) 3 14 5 11 # p2(v8) 4 9 4 3 8 # p3(v7) 5 14 5 4 3 13 # p4(v2) 4 9 7 6 8 # p5(v9) 5 14 11 10 12 13 # p6(v10) 7 11 5 4 9 7 1 10 # p7(v5) 3 13 2 12 # p8(v6) 4 12 2 1 10 # p9(v4) } } Output completed. Verifying that all points are below 2.1e-15 of all facets. Will make 140 distance computations. rbox 10 D2 | qhull v Tcv Fv 23 4 0 1 0 6 4 0 7 1 7 4 0 9 1 2 4 0 8 0 2 4 0 5 6 7 4 1 4 0 3 4 1 3 3 8 4 1 5 6 8 4 2 7 5 11 4 2 4 5 14 4 2 6 11 14 4 3 4 3 4 4 3 7 4 9 4 3 5 8 9 4 4 8 0 13 4 4 7 4 5 4 4 6 13 14 4 5 7 7 9 4 6 7 10 11 4 6 9 10 12 4 6 8 12 13 4 7 9 1 10 4 8 9 2 12 Output completed. Verifying that all points are below 2.1e-15 of all facets. Will make 140 distance computations. rbox 10 D2 | qhull v Tcv Fi 19 5 0 7 0.02051532578114336 0.9997895385570373 0.07511430445246037 5 0 9 0.619259133056969 0.7851866823409139 0.1370614663104577 5 0 5 -0.301880639203215 0.9533457293522944 0.008789126238507583 5 1 3 0.9648718030091262 -0.2627211520946079 0.3258622775065156 5 1 5 0.7995952824356682 -0.6005392446015695 0.5469710423089692 5 2 7 -0.9458410914974847 0.3246299888101017 0.04907537812572171 5 2 4 0.444671031232542 0.8956939622340812 -0.4300843534994401 5 2 6 0.2281595097543261 -0.9736237661995858 0.08253528745668784 5 3 4 0.9992944873266901 0.03755699133966539 -0.1938837324602516 5 3 7 0.6877523324625971 -0.7259454037269313 0.2663295190946441 5 3 5 -0.9986432053419565 0.05207445078292259 -0.1782370644858237 5 4 7 -0.9970183790688238 -0.07716444646969993 0.2145489484590235 5 4 6 -0.1075842248297359 -0.9941959739245502 0.2685422477498993 5 5 7 0.9950609206245129 -0.09926612839179765 0.187455367716064 5 6 7 -0.7993641842155074 0.6008468199079334 0.007060641163779212 5 6 9 -0.2285415587894342 -0.973534157544611 0.07797696388863314 5 6 8 -0.01261839651625044 -0.9999203848653946 -0.02567278177543585 5 7 9 0.5936952885926361 -0.8046899429612046 0.01852766555277016 5 8 9 -0.4674785097727932 0.8840044360186256 0.2506025495170936 Voronoi ridge statistics 19 bounded ridges 4.2e-17 ave. distance of midpoint to ridge 1.7e-16 max. distance of midpoint to ridge 19 bounded ridges with ok normal 5.8e-17 ave. angle to ridge 2.2e-16 max. angle to ridge Output completed. Verifying that all points are below 2.1e-15 of all facets. Will make 140 distance computations. rbox 10 D2 | qhull v Tcv Fo 4 5 0 1 -0.3854955578888161 0.922709691532494 -0.07609298438083822 5 0 8 0.719062520784207 0.6949453872092842 0.1071733734620186 5 1 4 0.9929212365203526 -0.1187746524595787 0.07521211888503937 5 4 8 -0.06640144810487483 -0.9977929883946747 0.1408811441173877 Output completed. Verifying that all points are below 2.1e-15 of all facets. Will make 140 distance computations. rbox 10 D2 | qhull v Qu o Fv Fi Fo Tcv 2 3 10 1 -10.101 -10.101 -0.06934933486244874 0.05349366577784781 -0.3051278694340224 0.161498505581022 3 0 2 1 2 0 1 0 0 3 0 1 2 0 0 0 2 0 2 0 5 4 0 8 0 2 4 0 4 1 2 4 0 1 0 1 4 1 4 0 1 4 4 8 0 2 1 5 0 4 0.4164624817835529 0.9091529031283372 -0.01975252543405325 4 5 0 8 0.7190625207842071 0.6949453872092841 0.1071733734620185 5 0 1 -0.3854955578888162 0.922709691532494 -0.07609298438083828 5 1 4 0.9929212365203528 -0.1187746524595786 0.07521211888503934 5 4 8 -0.06640144810487485 -0.9977929883946747 0.1408811441173877 Voronoi ridge statistics 1 bounded ridges 1.2e-16 ave. distance of midpoint to ridge 1.2e-16 max. distance of midpoint to ridge 1 bounded ridges with ok normal 0 max. angle to ridge Output completed. Verifying that all points are below 2.1e-15 of all facets. Will make 20 distance computations. rbox 10 D3 | qhull v Fv Tcv 32 6 0 1 0 17 15 3 7 0 9 0 7 12 11 2 6 0 6 0 7 18 17 5 0 7 0 2 3 6 0 2 2 3 15 11 5 0 8 7 18 12 7 0 5 11 12 18 17 15 5 1 7 0 5 3 6 1 2 3 5 0 15 5 1 5 15 0 17 6 2 3 1 4 13 9 6 2 9 1 2 11 9 7 2 7 1 2 3 5 4 6 2 4 4 5 0 13 7 2 5 9 11 15 0 13 7 3 9 0 6 10 9 1 5 3 7 0 4 1 5 3 6 0 8 6 7 3 4 0 8 14 13 4 6 3 8 6 8 14 10 6 3 5 9 10 14 13 5 4 7 0 5 4 5 4 6 0 16 8 5 4 8 8 16 14 6 4 5 13 0 16 14 6 5 9 9 11 12 10 7 5 8 10 12 18 16 14 6 5 6 0 17 18 16 5 6 9 0 6 7 7 6 8 6 7 18 16 8 5 7 9 0 1 2 6 8 9 6 7 12 10 Output completed. Verifying that all points are below 2.9e-15 of all facets. Will make 180 distance computations. rbox 10 D3 | qhull v Fi Tcv 13 6 0 2 0.1026012494065408 0.8309156055795224 -0.5468566905731632 0.2399036185798246 6 0 8 -0.1644981128676535 0.549224308046351 -0.8193247404503221 0.1220237399030437 6 0 5 -0.1640386761614813 0.6276090456203122 -0.7610507201092116 0.1709974344854015 6 2 3 0.8628264983391892 0.127742449234631 -0.4890933453107607 -0.1660057988150948 6 2 9 0.5146151495466437 -0.7556910962035636 -0.4050953159143434 -0.3000434746332832 6 2 7 0.9862472983740704 0.008356748990702902 0.1650649302430821 -0.2195655184060844 6 3 8 -0.9471370887617877 -0.1545163381156413 -0.2811690529684558 0.04372902199764667 6 3 5 -0.9850113492204077 -0.1553182373520528 -0.07502590921037623 0.09265233510028284 6 4 8 -0.7177135399298967 -0.245721536677967 -0.65154293873383 -0.02974683605231299 6 5 9 0.7110332662678562 -0.693517783370965 -0.116037831799318 -0.2706062861955821 6 5 8 -0.1310037283001485 -0.04490613421135446 -0.9903643078593113 -0.2004293237314498 6 6 8 0.563653077615962 0.07101685912338832 0.8229531054770393 0.4221671959133705 6 8 9 0.7278413449934529 -0.6852671087526033 0.02561183671604023 -0.2412830130907243 Voronoi ridge statistics 15 non-simplicial Voronoi vertices for all ridges 6.9e-17 ave. distance to ridge 1.9e-16 max. distance to ridge 13 bounded ridges 7.8e-17 ave. distance of midpoint to ridge 3e-16 max. distance of midpoint to ridge 13 bounded ridges with ok normal 8.5e-17 ave. angle to ridge 2.2e-16 max. angle to ridge Output completed. Verifying that all points are below 2.9e-15 of all facets. Will make 180 distance computations. rbox 10 D3 | qhull v Fo Tcv 19 6 0 1 -0.1769702595802885 0.8331351847724077 0.5239916899325134 0.004105600879712498 6 0 9 0.5856843296472444 -0.1558732679166009 -0.7954102025713885 -0.1264594278193164 6 0 6 -0.305501768024369 0.3812318858994052 -0.8725427891556765 -0.04822326899809234 6 0 7 0.6633910639781613 0.6672883530766242 -0.3385831509130507 0.06175731395259272 6 1 7 0.7533877382120365 0.334939238848763 -0.5658821628140998 0.06152842458597928 6 1 2 0.2077539373736714 0.4344067294949102 -0.8764297432625574 0.2556318087147513 6 1 5 -0.08886729274769822 0.2768317827550689 -0.9568002760954583 0.1656561460661369 6 2 4 0.8896724708236493 0.4529391082738924 -0.05769799697211265 -0.124969949041603 6 2 5 -0.6080629223625026 -0.1069684332549473 -0.7866493734408965 -0.05602222006342437 6 3 9 0.1157648604151236 -0.9728190902550374 -0.2005530222370839 -0.2615067759720444 6 3 7 0.3131056731324619 -0.1651787990807294 0.9352437125084113 -0.1060546443225209 6 3 6 -0.8429664438017094 -0.1288333013498811 -0.5223117412882753 -0.1470675860428305 6 3 4 -0.6546392846048742 0.1665291828386516 0.7373706247980789 0.1638426312062793 6 4 7 0.8997625993863546 -0.3161631359012113 0.3007792151107228 -0.2534488584590283 6 4 6 -0.6610636619910346 -0.1756381951302929 -0.7294834194184102 -0.1931488689248214 6 4 5 -0.8177140658972858 -0.2799433900977097 -0.5029666040348314 0.01966883326066583 6 5 6 -0.4656867325018191 -0.06587339986788447 -0.8824945112359766 -0.374728122564582 6 6 9 0.7885740013077054 -0.5314391513195501 0.309392102204163 -0.04784058563315544 6 7 9 -0.0125726543874506 -0.8388634914110149 -0.5441966291143082 -0.2018836580171401 Voronoi ridge statistics 14 non-simplicial Voronoi vertices for all ridges 4.3e-17 ave. distance to ridge 9.7e-17 max. distance to ridge Output completed. Verifying that all points are below 2.9e-15 of all facets. Will make 180 distance computations. rbox 10 D3 | qhull v Qu o Fv Fi Fo Tcv 3 10 10 1 -10.101 -10.101 -10.101 -0.04510412048603351 -0.1962229636993575 -0.06746145990413344 -0.2032838761823815 -0.3188041900902701 0.1251484339163768 0.1359785067833994 0.06954805978697726 -0.07249043373758879 -0.9550934192592715 0.3815223390696589 -0.9370156532984113 -0.01637948561987637 -0.8836250780525146 -0.03718065630611937 0.09499885792019704 -0.7038538868165176 -0.181396220925921 2.128743389186444 -4.06034590041635 -1.2162468947864 2.789531685277133 -5.393666229616701 -1.494034092231969 2.640156785601998 -4.796303906482405 -1.459799746992412 3 0 3 4 7 0 1 3 4 6 7 9 4 0 7 8 9 3 0 2 5 5 0 5 6 7 8 3 0 8 9 9 0 1 2 3 5 6 7 8 9 6 0 1 2 4 5 6 0 5 0 1 2 3 4 18 5 0 1 0 3 4 5 0 9 0 3 4 8 1 6 0 3 1 6 7 9 5 1 2 0 7 9 5 1 4 0 6 7 6 1 7 0 4 1 6 5 1 9 1 3 4 5 2 5 0 9 8 5 2 4 0 7 8 5 2 6 7 9 8 5 3 6 0 5 2 5 3 7 0 2 5 7 4 6 0 5 6 7 8 5 4 7 0 6 5 5 5 6 0 9 8 6 6 9 0 3 1 2 6 6 7 1 2 5 6 6 7 9 0 2 1 4 3 6 1 9 0.5123553720802024 -0.363812082853534 -0.7779027838170592 -0.100757404152973 6 2 6 -0.5221667006142685 -0.08192192666458321 -0.8488997200501196 -0.2535440955968309 6 6 7 0.752213645322669 0.06033708575303686 0.6561509489997043 0.09003235761431796 15 6 0 1 -0.1769702595802886 0.8331351847724078 0.5239916899325134 0.004105600879712498 6 0 9 0.5856843296472447 -0.1558732679166012 -0.7954102025713884 -0.1264594278193166 6 1 6 -0.2436653478720986 0.147883680687048 -0.9585184480399009 -0.04663519095132841 6 1 2 0.2077539373736637 0.4344067294949081 -0.8764297432625605 0.255631808714752 6 1 4 0.444220078847362 0.4986447037065236 -0.744326528490203 0.1737545932855555 6 1 7 0.7533877382120362 0.3349392388487629 -0.5658821628141001 0.06152842458597942 6 2 5 -0.6080629223625006 -0.1069684332549458 -0.7866493734408982 -0.05602222006342417 6 2 4 0.8896724708236509 0.4529391082738904 -0.0576979969721034 -0.1249699490416035 6 3 6 -0.8429664438017096 -0.1288333013498811 -0.5223117412882751 -0.1470675860428304 6 3 7 0.3131056731324613 -0.1651787990807291 0.9352437125084115 -0.1060546443225207 6 4 6 -0.6610636619910349 -0.1756381951302929 -0.7294834194184099 -0.1931488689248214 6 4 7 0.8997625993863546 -0.3161631359012115 0.3007792151107228 -0.2534488584590282 6 5 6 -0.4656867325018176 -0.06587339986788343 -0.8824945112359772 -0.374728122564582 6 6 9 0.7885740013077054 -0.5314391513195503 0.3093921022041629 -0.04784058563315553 6 7 9 -0.01257265438745033 -0.8388634914110151 -0.5441966291143079 -0.2018836580171402 Voronoi ridge statistics 9 non-simplicial Voronoi vertices for all ridges 1.5e-16 ave. distance to ridge 4.4e-16 max. distance to ridge 3 bounded ridges 6.4e-16 ave. distance of midpoint to ridge 1.7e-15 max. distance of midpoint to ridge 3 bounded ridges with ok normal 7.4e-17 ave. angle to ridge 2.2e-16 max. angle to ridge Output completed. Verifying that all points are below 2.9e-15 of all facets. Will make 90 distance computations. rbox 5 D2 | qhull v f FnN o Vertices and facets: - p3(v5): 0.43 -0.11 0.19 neighbors: f5 f6 f7 f8 - p2(v2): 0.47 -0.11 0.24 neighbors: f1 f5 f7 - p4(v1): -0.39 0.45 0.36 neighbors: f1 f3 f5 f6 - p0(v4): -0.34 0.23 0.17 neighbors: f3 f6 f8 - p1(v3): 0.32 -0.23 0.16 neighbors: f1 f3 f7 f8 - f5 - flags: top simplicial - normal: 0.437 0.773 -0.4599 - offset: -0.01170704 - center: 0.4751017705052502 0.8404705693422864 - vertices: p3(v5) p2(v2) p4(v1) - neighboring facets: f1 f6 f7 - f6 - flags: bottom simplicial - normal: 0.3235 0.6691 -0.669 - offset: 0.0657 - center: 0.24177356134713 0.5000766029034823 - vertices: p3(v5) p0(v4) p4(v1) - neighboring facets: f3 f5 f8 - f7 - flags: top simplicial - normal: 0.6288 -0.3317 -0.7033 - offset: -0.1682885 - center: 0.4470293595057619 -0.2357835939937328 - vertices: p3(v5) p1(v3) p2(v2) - neighboring facets: f1 f5 f8 - f8 - flags: top simplicial - normal: 0.1177 0.1841 -0.9758 - offset: 0.15929 - center: 0.06029550723695781 0.09433023738340306 - vertices: p3(v5) p0(v4) p1(v3) - neighboring facets: f3 f7 f6 4 3 -1 1 2 3 -3 0 3 3 -1 0 3 3 -3 2 1 5 3 3 -3 1 4 3 -3 -1 2 3 2 -1 0 4 3 1 0 2 4 1 -3 -1 0 2 5 5 1 -10.101 -10.101 0.4751017705052502 0.8404705693422864 0.24177356134713 0.5000766029034823 0.4470293595057619 -0.2357835939937328 0.06029550723695781 0.09433023738340306 3 2 4 0 3 3 4 0 3 1 3 0 4 3 4 2 1 3 1 2 0 set +v === check Halfspace and Qhull identity pipeline, showing the input Fri, Jul 24, 2020 10:27:34 PM === the Qhull pipeline recreates 100 4-D cospherical points with the same area and volume rbox 100 s D4 | qhull FA FV s n | head Convex hull of 100 points in 4-d: Number of vertices: 100 Number of facets: 584 Statistics for: rbox 100 s D4 | qhull FA FV s n Number of points processed: 100 Number of hyperplanes created: 1717 Number of distance tests for qhull: 4090 CPU seconds to compute hull (after input): 0.001 Total facet area: 1.7919449 Total volume: 0.18640279 4 1 -0.006240661006237819 -0.006198497499885543 -0.0019864189252863 0.03528712962677102 5 584 -0.4728063044129454 -0.06576180062326932 0.3296766529322419 -0.8145200357250598 -0.4001269961794449 0.9350657178932537 -0.116181174817606 -0.009048199757790566 0.3347718147035652 -0.3733488931324643 0.5670388949132408 -0.5323662756300656 -0.3876606744394214 0.4947446227302695 -0.4846392631626165 0.8393609616706702 -0.1089654738688994 -0.05104156673138016 0.530089105710936 -0.4115455431603698 0.6753770108964836 -0.1536990905729236 -0.0485198359900459 0.7196445707605155 -0.4414725485817289 0.20025580309926 0.08170320261530004 0.2334845247641378 0.9480016754748583 -0.4466269780920115 rbox 100 s D4 | qhull FQ FA FV n s | qhull s H Fp | head Convex hull of 100 points in 4-d: Number of vertices: 100 Number of facets: 584 Statistics for: rbox 100 s D4 | qhull FQ FA FV n s Number of points processed: 100 Number of hyperplanes created: 1717 Number of distance tests for qhull: 4090 CPU seconds to compute hull (after input): 0.001 Total facet area: 1.7919449 Total volume: 0.18640279 Halfspace intersection by the convex hull of 584 points in 4-d: Number of halfspaces: 584 Number of non-redundant halfspaces: 584 Number of intersection points: 100 Number of non-simplicial intersection points: 100 Statistics for: rbox 100 s D4 | qhull FQ FA FV n s | qhull s H Fp Number of points processed: 584 Number of hyperplanes created: 4013 Number of distance tests for qhull: 29717 Number of distance tests for merging: 76955 Number of distance tests for checking: 18265 Number of merged facets: 3444 CPU seconds to compute hull (after input): 0.012 Maximum distance of point above facet: 2.4e-14 (0.4x) Maximum distance of vertex below facet: -1.7e-14 (0.3x) 4 100 -0.1497820974007844 0.4220759056868791 -0.1730594919621551 0.1395265758865447 -0.1656824599698354 0.2695081565763442 0.2399815540443042 -0.3038478726528215 -0.1287028906527846 0.3274268489457611 0.1066154632455187 -0.3389105597705839 0.2152206390581626 0.2489384546335302 -0.342896351704003 0.1553441801811403 -0.3478218321497436 0.1609400522171699 0.2504669650899252 -0.2009591303498609 -0.2026608048181584 0.132737676060139 -0.4340855448243784 0.05365675464591807 -0.1243914612976075 -0.06208848857682957 -0.4348180038806073 -0.2039732517850684 0.318659177699236 0.2994118752602876 -0.2407753518255607 -0.02891517550426 rbox 100 s D4 | qhull FQ FA FV n s Tcv | qhull FQ s H Fp Tcv | qhull FA Tcv Convex hull of 100 points in 4-d: Number of vertices: 100 Number of facets: 584 Statistics for: rbox 100 s D4 | qhull FQ FA FV n s Tcv Number of points processed: 100 Number of hyperplanes created: 1717 Number of distance tests for qhull: 4090 CPU seconds to compute hull (after input): 0.007 Total facet area: 1.7919449 Total volume: 0.18640279 Output completed. Verifying that all points are below 2.8e-15 of all facets. Will make 58400 distance computations. Halfspace intersection by the convex hull of 584 points in 4-d: Number of halfspaces: 584 Number of non-redundant halfspaces: 584 Number of intersection points: 100 Number of non-simplicial intersection points: 100 Statistics for: rbox 100 s D4 | qhull FQ FA FV n s Tcv | qhull FQ s H Fp Tcv Number of points processed: 584 Number of hyperplanes created: 4013 Number of distance tests for qhull: 29717 Number of distance tests for merging: 77055 Number of distance tests for checking: 51837 Number of merged facets: 3444 CPU seconds to compute hull (after input): 0.363 Maximum distance of point above facet: 2.4e-14 (0.4x) Maximum distance of vertex below facet: -1.7e-14 (0.3x) Output completed. Verifying that all points are below outer planes of all facets. Will make 58400 distance computations. Convex hull of 100 points in 4-d: Number of vertices: 100 Number of facets: 584 Statistics for: rbox 100 s D4 | qhull FQ FA FV n s Tcv | qhull FQ s H Fp Tcv | qhull FA Tcv Number of points processed: 100 Number of hyperplanes created: 1717 Number of distance tests for qhull: 4090 CPU seconds to compute hull (after input): 0.006 Total facet area: 1.7919449 Total volume: 0.18640279 Output completed. Verifying that all points are below 2.8e-15 of all facets. Will make 58400 distance computations. echo === the Qhull pipeline recreates a 3-D tetrahedron === the Qhull pipeline recreates a 3-D tetrahedron rbox d D3 | qhull n FD rbox d D3 | qhull n FD begin 8 4 real 0.2886751345948129 0.5773502691896258 0.5773502691896258 0.5773502691896258 0.2886751345948129 -0.5773502691896258 0.5773502691896258 0.5773502691896258 0.2886751345948129 0.5773502691896258 0.5773502691896258 -0.5773502691896258 0.2886751345948129 -0.5773502691896258 0.5773502691896258 -0.5773502691896258 0.2886751345948129 -0.5773502691896258 -0.5773502691896258 0.5773502691896258 0.2886751345948129 0.5773502691896258 -0.5773502691896258 0.5773502691896258 0.2886751345948129 -0.5773502691896258 -0.5773502691896258 -0.5773502691896258 0.2886751345948129 0.5773502691896258 -0.5773502691896258 -0.5773502691896258 end rbox d D3 | qhull s n FD Tcv | qhull s Fd H0.1,0.1 Fp Tcv Convex hull of 6 points in 3-d: Number of vertices: 6 Number of facets: 8 Statistics for: rbox d D3 | qhull s n FD Tcv Number of points processed: 6 Number of hyperplanes created: 11 Number of distance tests for qhull: 10 Number of distance tests for merging: 59 Number of distance tests for checking: 54 Number of merged facets: 1 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 48 distance computations. Halfspace intersection by the convex hull of 8 points in 3-d: Number of halfspaces: 8 Number of non-redundant halfspaces: 8 Number of intersection points: 6 Number of non-simplicial intersection points: 6 Statistics for: rbox d D3 | qhull s n FD Tcv | qhull s Fd H0.1,0.1 Fp Tcv Number of points processed: 8 Number of hyperplanes created: 10 Number of distance tests for qhull: 30 Number of distance tests for merging: 95 Number of distance tests for checking: 100 Number of merged facets: 6 CPU seconds to compute hull (after input): 0 3 6 -1.387778780781446e-17 -1.387778780781446e-17 -0.5 -2.775557561562891e-17 0.5 0 -0.5 0 0 0.5 -2.775557561562891e-17 0 0 -0.5 0 -1.387778780781446e-17 1.387778780781446e-17 0.4999999999999999 Output completed. Verifying that all points are below outer planes of all facets. Will make 48 distance computations. echo === the Qhull pipeline recreates a regular 2-D pentagon === the Qhull pipeline recreates a regular 2-D pentagon rbox 5 r D2 | qhull FQ n rbox 5 r D2 | qhull FQ n 3 5 0.8090169943749476 0.587785252292473 -0.4045084971874737 -0.3090169943749476 -0.9510565162951536 -0.4045084971874738 0.8090169943749472 -0.5877852522924732 -0.4045084971874737 -1 9.444121133484361e-17 -0.4045084971874738 -0.3090169943749474 0.9510565162951536 -0.4045084971874738 rbox 5 r D2 | qhull s FQ n Tcv | qhull s H0 Fp Tcv Convex hull of 5 points in 2-d: Number of vertices: 5 Number of facets: 5 Statistics for: rbox 5 r D2 | qhull s FQ n Tcv Number of points processed: 5 Number of hyperplanes created: 8 Number of distance tests for qhull: 7 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below 1.3e-15 of all facets. Will make 25 distance computations. Halfspace intersection by the convex hull of 5 points in 2-d: Number of halfspaces: 5 Number of non-redundant halfspaces: 5 Number of intersection points: 5 Statistics for: rbox 5 r D2 | qhull s FQ n Tcv | qhull s H0 Fp Tcv Number of points processed: 5 Number of hyperplanes created: 7 Number of distance tests for qhull: 8 CPU seconds to compute hull (after input): 0 2 5 -0.4045084971874738 -0.2938926261462365 0.5 -1.528090898784888e-16 0.1545084971874736 -0.4755282581475768 -0.4045084971874737 0.2938926261462366 0.1545084971874737 0.4755282581475768 Output completed. Verifying that all points are below 6.4e-15 of all facets. Will make 25 distance computations. set +v === check qhull Fri, Jul 24, 2020 10:27:35 PM rbox 10 s D3 | qhull Tcv Convex hull of 10 points in 3-d: Number of vertices: 10 Number of facets: 16 Statistics for: rbox 10 s D3 | qhull Tcv Number of points processed: 10 Number of hyperplanes created: 29 Number of distance tests for qhull: 48 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below 2e-15 of all facets. Will make 160 distance computations. rbox 10 s D3 | qhull f Pd0:0.5 Pd2 Pg Tcv Vertices and facets: - p7(v8): 0.2 0.093 0.45 - p9(v5): 0.29 -0.16 0.38 - p3(v2): 0.48 -0.13 0.022 - p8(v10): 0.32 0.025 -0.38 - f16 - flags: bottom simplicial - normal: 0.858 0.1759 0.4826 - offset: -0.4016457 - vertices: p7(v8) p9(v5) p3(v2) - neighboring facets: f7 f27 f23 - f27 - flags: bottom simplicial - normal: 0.646 0.7625 0.03668 - offset: -0.2138755 - vertices: p8(v10) p7(v8) p3(v2) - neighboring facets: f16 f26 f28 Output completed. Verifying that all points are below 2e-15 of all facets. Will make 20 distance computations. rbox 10 s D3 | qhull f Tcv PD2:-0.5 Pg Vertices and facets: - p4(v7): 0.23 -0.32 -0.31 - p1(v4): -0.072 0.057 -0.49 - p6(v3): -0.13 -0.47 -0.09 - p0(v9): -0.37 -0.27 0.19 - p8(v10): 0.32 0.025 -0.38 - p5(v6): 0.028 0.16 -0.47 - f12 - flags: top simplicial - normal: -0.2354 -0.5691 -0.7879 - offset: -0.3715833 - vertices: p4(v7) p1(v4) p6(v3) - neighboring facets: f21 f11 f25 - f21 - flags: bottom simplicial - normal: -0.8148 -0.2922 -0.5006 - offset: -0.2881945 - vertices: p0(v9) p1(v4) p6(v3) - neighboring facets: f12 f19 f20 - f24 - flags: top simplicial - normal: 0.2636 -0.06941 -0.9621 - offset: -0.4497787 - vertices: p8(v10) p5(v6) p1(v4) - neighboring facets: f9 f25 f28 - f25 - flags: bottom simplicial - normal: 0.2402 -0.2624 -0.9346 - offset: -0.4268812 - vertices: p8(v10) p4(v7) p1(v4) - neighboring facets: f12 f24 f26 Output completed. Verifying that all points are below 2e-15 of all facets. Will make 40 distance computations. rbox 10 s D3 | qhull QR-1 Convex hull of 10 points in 3-d: Number of vertices: 10 Number of facets: 16 Statistics for: rbox 10 s D3 | qhull QR-1 QR-1595644055 Number of points processed: 10 Number of hyperplanes created: 29 Number of distance tests for qhull: 48 CPU seconds to compute hull (after input): 0 rbox 10 s D3 | qhull QR-40 Convex hull of 10 points in 3-d: Number of vertices: 10 Number of facets: 16 Statistics for: rbox 10 s D3 | qhull QR-40 QR-40 Number of points processed: 10 Number of hyperplanes created: 29 Number of distance tests for qhull: 48 CPU seconds to compute hull (after input): 0 rbox 1000 D3 | qhull Tcvs qhull 2020.2.r 2020/07/24 Statistics: rbox 1000 D3 | qhull Tcvs Convex hull of 1000 points in 3-d: Number of vertices: 73 Number of facets: 142 Statistics for: rbox 1000 D3 | qhull Tcvs Number of points processed: 81 Number of hyperplanes created: 367 Number of distance tests for qhull: 12879 CPU seconds to compute hull (after input): 0.001 qhull invoked by: rbox 1000 D3 | qhull Tcvs 2020.2.r 2020/07/24 with options: run-id 213848649 Tcheck-frequently Tverify Tstatistics _pre-merge _zero-centrum _max-width 1 Error-roundoff 6.9e-16 _one-merge 4.9e-15 _near-inside 2.4e-14 Visible-distance 1.4e-15 U-max-coplanar 1.4e-15 Width-outside 2.8e-15 _wide-facet 8.3e-15 precision constants: 0.5 max. abs. coordinate in the (transformed) input ('Qbd:n') 6.9e-16 max. roundoff error for distance computation ('En') 6.7e-16 max. roundoff error for angle computations 2.8e-15 min. distance for outside points ('Wn') 1.4e-15 min. distance for visible facets ('Vn') 1.4e-15 max. distance for coplanar facets ('Un') 8.3e-15 max. facet width for recomputing centrum and area 2.4e-14 max. distance for near-inside points 1.4e-15 radius of pre-merge centrum 4.9e-15 max. distance for merging two simplicial facets 2.2e-16 max. roundoff error for arithmetic operations 1.1e-308 min. denominator for division zero diagonal for Gauss: 8.88e-15 1.78e-14 2.66e-14 precision statistics 3.8e-17 ave. distance of a new vertex to a facet 1.7e-16 max. distance of a new vertex to a facet 1.4e-16 max. distance of an output vertex to a facet -1.7e-16 min. distance of an output vertex to a facet 0.0026 min. denominator in hyperplane computation summary information 73 number of vertices in output 142 number of facets in output 3 average number of neighbors per facet 3 maximum number of neighbors 3 average number of vertices per facet 3 maximum number of vertices 0.001 cpu seconds for qhull after input 82 vertices created altogether 367 facets created altogether 0 maximum merges for a facet (at most 511) 0.93 average cosine (angle) of facet normals for all ridges 1 maximum cosine of facet normals (flatest) across a ridge 0.21 minimum cosine of facet normals (sharpest) across a ridge build hull statistics 81 points processed 73 max. vertices at any one time 2.78 ave. visible facets per iteration 0.21 ave. visible facets without an horizon neighbor 2.78 ave. facets deleted per iteration 8 maximum 5.43 ave. visible vertices per iteration 11 maximum 4.38 ave. horizon facets per iteration 4.48 ave. new or merged facets per iteration 10 maximum (includes initial simplex) -0.77 average new facet balance 1.5 standard deviation 77 count 7 determinants for initial hull or voronoi vertices 503 distance tests for facet visibility 73 points checked for facets' outer planes 11.4 ave. distance tests per check 1668 max visit_id/2 3125 max vertex_visit/2 partitioning statistics (see previous for outer planes) 8 total vertices deleted 1 maximum vertices deleted per iteration 132 calls to findbest 2.53 ave. facets tested 6 max. facets tested 2048 calls to findbestnew 4.47 ave. facets tested 13 max. facets tested 36 calls due to qh_sharpnewfacets 927 calls to findhorizon 3.01 ave. facets tested 5 max. facets tested 0.00539 ave. clearly better 5 new bestfacets during qh_findbesthorizon 919 inside points 8 inside points that were coplanar with a facet -2.8e-17 difference in max_outside at final check 3747 distance tests for initial partition 3132 partitions of a point 8553 distance tests for partitioning 518 distance tests for checking flipped facets 1160 distance tests for statistics 16915 total number of distance tests 8 partitions of coplanar points or deleted vertices 76 distance tests for these partitions statistics for matching ridges 726 total lookups for matching ridges of new facets 0.583 average number of tests to match a ridge statistics for determining merges 1089 distance tests for checking simplicial convexity statistics for merging 1.7e-16 max distance of vertex or coplanar point above facet (w/roundoff) -6.9e-16 max distance of vertex below facet (or roundoff) memory usage statistics (in bytes) 21584 for facets and their normals, neighbor and vertex sets 2044 for vertices and their neighbor sets 31104 for input points, outside and coplanar sets, and qhT memory statistics: 1413 quick allocations 687 short allocations 69 long allocations 1445 short frees 68 long frees 25680 bytes of short memory in use 1472 bytes of short memory in freelists 103912 bytes of dropped short memory 1364 bytes of unused short memory (estimated) 10916 bytes of long memory allocated (max, except for input) 96 bytes of long memory in use (in 1 pieces) 131064 bytes of short memory buffers (minus links) 65536 bytes per short memory buffer (initially 131072 bytes) 100 calls to qh_setlarger 14 average copy size freelists(bytes->count): 16->1 24->13 32->0 48->11 88->7 size in bytes: merge 48 ridge 20 vertex 28 facet 88 normal 24 ridge vertices 16 facet vertices or neighbors 20 Output completed. Verifying that all points are below outer planes of all facets. Will make 142000 distance computations. # Test tracing 'Tn', combine stderr/stdout 'Tz', flush fprintf 'Tf' rbox 100 D3 | qhull T1 Tz Tf TA1 TO q_test.log.1 tail -n -10 q_test.log.1 Statistics for: rbox 100 D3 | qhull T1 Tz Tf TA1 TO q_test.log.1 Number of points processed: 5 Number of hyperplanes created: 8 Number of distance tests for qhull: 456 CPU seconds to compute hull (after input): 0.001 [QH1006]qh_freeqhull: free global memory [QH1005]qh_freebuild: free memory from qh_inithull and qh_buildhull [QH1061]qh_freeqhull: clear qhT except for qh.qhmem and qh.qhstat rm q_test.log.1 rbox 100 s D3 | qhull TcvA10 Early exit due to 'TAn', 'TVn', 'TCn', 'TRn', or precision error with 'QJn'. Convex hull of 100 points in 3-d: Number of vertices: 14 Number of facets: 24 Statistics for: rbox 100 s D3 | qhull TcvA10 Number of points processed: 14 Number of hyperplanes created: 48 Number of distance tests for qhull: 599 CPU seconds to compute hull (after input): 0 rbox 100 s D3 | qhull TcvV-2 Early exit due to 'TAn', 'TVn', 'TCn', 'TRn', or precision error with 'QJn'. Convex hull of 100 points in 3-d: Number of vertices: 78 Number of facets: 152 Statistics for: rbox 100 s D3 | qhull TcvV-2 Number of points processed: 78 Number of hyperplanes created: 390 Number of distance tests for qhull: 1488 CPU seconds to compute hull (after input): 0.001 rbox 100 s D3 | qhull TcvC2 Early exit due to 'TAn', 'TVn', 'TCn', 'TRn', or precision error with 'QJn'. Convex hull of 100 points in 3-d: Number of vertices: 79 Number of facets: 154 Statistics for: rbox 100 s D3 | qhull TcvC2 Number of points processed: 79 Number of hyperplanes created: 395 Number of distance tests for qhull: 1495 CPU seconds to compute hull (after input): 0.001 rbox 100 s D3 | qhull TcvV2 Early exit due to 'TAn', 'TVn', 'TCn', 'TRn', or precision error with 'QJn'. Convex hull of 100 points in 3-d: Number of vertices: 79 Number of facets: 154 Statistics for: rbox 100 s D3 | qhull TcvV2 Number of points processed: 79 Number of hyperplanes created: 395 Number of distance tests for qhull: 1495 CPU seconds to compute hull (after input): 0.001 rbox 100 s D3 | qhull T1cvV2P2 [QH1008]qh_readpoints: read in 100 3-dimensional points [QH0013]qh_initqhull_globals: for rbox 100 s D3 | qhull T1cvV2P2 Trace level T1, IStracing 0, point TP2, merge TM0, dist TW1.8e+308, qh.tracefacet_id -1, traceridge_id -1, tracevertex_id -1, last qh.RERUN 0, rbox 100 s D3 | qhull T1cvV2P2 Options selected for Qhull 2020.2.r 2020/07/24: run-id 213848649 Tcheck-frequently Tverify TV-stop-after-point 2 Trace-point 2 _pre-merge _zero-centrum _max-width 0.94 Error-roundoff 6.7e-16 _one-merge 4.7e-15 _near-inside 2.3e-14 Visible-distance 1.3e-15 U-max-coplanar 1.3e-15 Width-outside 2.7e-15 _wide-facet 8.1e-15 qh_findbest: point p2 starting at f7 isnewfacets? 1, unless 0 exit if > 2.7e-15, testhorizon? 1, noupper? 0, Last qh_addpoint p41, Last merge #0, max_outside 4e-17 qh_findbest: point p2 starting at f15 isnewfacets? 1, unless 0 exit if > 2.7e-15, testhorizon? 1, noupper? 0, Last qh_addpoint p52, Last merge #0, max_outside 1.1e-16 qh_findbest: point p2 starting at f37 isnewfacets? 1, unless 0 exit if > 2.7e-15, testhorizon? 1, noupper? 0, Last qh_addpoint p73, Last merge #0, max_outside 1.1e-16 qh_findbest: point p2 starting at f52 isnewfacets? 1, unless 0 exit if > 2.7e-15, testhorizon? 1, noupper? 0, Last qh_addpoint p87, Last merge #0, max_outside 1.1e-16 qh_findbest: point p2 starting at f72 isnewfacets? 1, unless 0 exit if > 2.7e-15, testhorizon? 1, noupper? 0, Last qh_addpoint p76, Last merge #0, max_outside 1.1e-16 qh_findbest: point p2 starting at f120 isnewfacets? 1, unless 0 exit if > 2.7e-15, testhorizon? 1, noupper? 0, Last qh_addpoint p84, Last merge #0, max_outside 1.1e-16 qh_findbest: point p2 starting at f211 isnewfacets? 1, unless 0 exit if > 2.7e-15, testhorizon? 1, noupper? 0, Last qh_addpoint p10, Last merge #0, max_outside 1.1e-16 qh_findbest: point p2 starting at f289 isnewfacets? 1, unless 0 exit if > 2.7e-15, testhorizon? 1, noupper? 0, Last qh_addpoint p6, Last merge #0, max_outside 1.1e-16 [QH1049]qh_addpoint: add p2(v79) 0.014 above f288 to hull of 152 facets, 0 merges, 22 outside at 0.001 CPU secs. Previous p56(v78) delta 0.001 CPU, 152 facets, 0 merges, 390 hyperplanes, 3835 distplanes, 0 retries [QH1040]qh_findhorizon: find horizon for point p2 facet f288 [QH1041]qh_findhorizon: 5 horizon facets(good 5), 3 visible(good 3), 0 coplanar [QH1032]qh_makenewfacets: created 5 new facets f390..f394 from point p2 to horizon [QH1019]qh_matchnewfacets: match neighbors for new facets. [QH1043]qh_partitionvisible: partitioned 0 points from outsidesets, 0 points from coplanarsets, and 0 deleted vertices [QH1018]qh_deletevisible: delete 3 visible facets and 0 vertices [QH1027]qh_checkpolygon: check all facets from f62, qh.NEWtentative? 0 [QH1039]qh_buildhull: completed the hull construction [QH1036]Qhull: algorithm completed [QH1027]qh_checkpolygon: check all facets from f62, qh.NEWtentative? 0 [QH1064]qh_checkconvex: check that facets are not-flipped and for qh.ZEROcentrum that simplicial vertices are below their neighbor (dist<0.0) Early exit due to 'TAn', 'TVn', 'TCn', 'TRn', or precision error with 'QJn'. Convex hull of 100 points in 3-d: Number of vertices: 79 Number of facets: 154 Statistics for: rbox 100 s D3 | qhull T1cvV2P2 Number of points processed: 79 Number of hyperplanes created: 395 Number of distance tests for qhull: 1495 CPU seconds to compute hull (after input): 0.001 [QH1006]qh_freeqhull: free global memory [QH1005]qh_freebuild: free memory from qh_inithull and qh_buildhull [QH1061]qh_freeqhull: clear qhT except for qh.qhmem and qh.qhstat rbox 100 s D3 | qhull TcvF100 At 22:27:35 & 0.001 CPU secs, qhull has created 102 facets and merged 0. The current hull contains 46 facets and 25 vertices. There are 75 outside points. Next is point p55(v26), 0.035 above f44. At 22:27:35 & 0.001 CPU secs, qhull has created 203 facets and merged 0. The current hull contains 86 facets and 45 vertices. There are 55 outside points. Next is point p82(v46), 0.067 above f117. At 22:27:35 & 0.002 CPU secs, qhull has created 306 facets and merged 0. The current hull contains 122 facets and 63 vertices. There are 37 outside points. Next is point p50(v64), 0.042 above f218. At 22:27:35 & 0.002 CPU secs, qhull has created 412 facets and merged 0. The current hull contains 160 facets and 82 vertices. There are 18 outside points. Next is point p60(v83), 0.031 above f307. Convex hull of 100 points in 3-d: Number of vertices: 100 Number of facets: 196 Statistics for: rbox 100 s D3 | qhull TcvF100 Number of points processed: 100 Number of hyperplanes created: 514 Number of distance tests for qhull: 1690 CPU seconds to compute hull (after input): 0.002 Output completed. Verifying that all points are below 2e-15 of all facets. Will make 19600 distance computations. rbox 100 s D3 | qhull Qf Tcv Convex hull of 100 points in 3-d: Number of vertices: 100 Number of facets: 196 Statistics for: rbox 100 s D3 | qhull Qf Tcv Number of points processed: 100 Number of hyperplanes created: 506 Number of distance tests for qhull: 4421 CPU seconds to compute hull (after input): 0.002 Output completed. Verifying that all points are below 2e-15 of all facets. Will make 19600 distance computations. rbox 100 D3 | qhull Tcv Convex hull of 100 points in 3-d: Number of vertices: 26 Number of facets: 48 Statistics for: rbox 100 D3 | qhull Tcv Number of points processed: 28 Number of hyperplanes created: 109 Number of distance tests for qhull: 1163 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 4800 distance computations. rbox 100 D3 | qhull Qs Tcv Convex hull of 100 points in 3-d: Number of vertices: 26 Number of facets: 48 Statistics for: rbox 100 D3 | qhull Qs Tcv Number of points processed: 29 Number of hyperplanes created: 105 Number of distance tests for qhull: 1172 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 4800 distance computations. rbox 100 D5 | qhull Qs Tcv Convex hull of 100 points in 5-d: Number of vertices: 78 Number of facets: 1174 Statistics for: rbox 100 D5 | qhull Qs Tcv Number of points processed: 85 Number of hyperplanes created: 4014 Number of distance tests for qhull: 9050 CPU seconds to compute hull (after input): 0.01 QH7076 qhull input warning: exact merge ('Qx'). Verify may report that a point is outside of a facet. See qh-optq.htm#Qx Output completed. Verifying that all points are below outer planes of all facets. Will make 117400 distance computations. rbox 100 D3 | qhull Qr Tcv Convex hull of 100 points in 3-d: Number of vertices: 26 Number of facets: 48 Statistics for: rbox 100 D3 | qhull Qr Tcv Number of points processed: 56 Number of hyperplanes created: 293 Number of distance tests for qhull: 2135 Output completed. Verifying that all points are below outer planes of all facets. Will make 4800 distance computations. rbox 100 D3 | qhull Qxv Tcv Convex hull of 100 points in 3-d: Number of vertices: 26 Number of facets: 48 Statistics for: rbox 100 D3 | qhull Qxv Tcv Number of points processed: 28 Number of hyperplanes created: 109 Number of distance tests for qhull: 1163 CPU seconds to compute hull (after input): 0 QH7076 qhull input warning: exact merge ('Qx'). Verify may report that a point is outside of a facet. See qh-optq.htm#Qx Output completed. Verifying that all points are below outer planes of all facets. Will make 4800 distance computations. rbox 100 D3 | qhull Qi f Pd0 Pd1 Pd2 Pg Tcv Vertices and facets: - p11(v14): -0.31 0.47 0.07 - p59(v8): 0.44 0.42 -0.11 - p33(v3): -0.067 0.49 -0.11 - p48(v25): 0.25 0.24 0.44 - p37(v15): 0.45 0.26 0.04 - p38(v5): 0.42 -0.25 0.42 - f42 - flags: bottom simplicial - normal: 0.1292 0.9495 0.2858 - offset: -0.4221543 - coplanar set(furthest p70): p70: 0.04762 0.3507 -0.06712 furthest distance= -0.1 - vertices: p11(v14) p59(v8) p33(v3) - neighboring facets: f52 f41 f93 - f93 - flags: top simplicial - normal: 0.142 0.9273 0.3463 - offset: -0.4120445 - coplanar set(furthest p28): p27: 0.1182 0.3419 0.068 p25: 0.1663 0.2352 0.3516 p15: 0.2743 0.2665 0.07375 p44: -0.1321 0.3861 0.167 p28: -0.1003 0.4263 0.07335 furthest distance= -0.0056 - vertices: p48(v25) p11(v14) p59(v8) - neighboring facets: f42 f94 f95 - f94 - flags: bottom simplicial - normal: 0.7783 0.4631 0.4241 - offset: -0.4905394 - vertices: p48(v25) p37(v15) p59(v8) - neighboring facets: f47 f93 f97 - f97 - flags: top simplicial - normal: 0.8488 0.2736 0.4523 - offset: -0.4744876 - vertices: p48(v25) p37(v15) p38(v5) - neighboring facets: f46 f99 f94 Output completed. Verifying that all points are below outer planes of all facets. Will make 400 distance computations. rbox c d | qhull Qc f Tcv Vertices and facets: - p6(v6): 0.5 0.5 -0.5 neighbors: f1 f9 f10 - p2(v3): -0.5 0.5 -0.5 neighbors: f1 f3 f10 - p4(v2): 0.5 -0.5 -0.5 neighbors: f1 f2 f9 - p0(v1): -0.5 -0.5 -0.5 neighbors: f1 f2 f3 - p5(v7): 0.5 -0.5 0.5 neighbors: f2 f9 f13 - p1(v4): -0.5 -0.5 0.5 neighbors: f2 f3 f13 - p7(v5): 0.5 0.5 0.5 neighbors: f10 f13 f9 - p3(v8): -0.5 0.5 0.5 neighbors: f3 f10 f13 - f1 - flags: bottom tested - merges: 1 - normal: -0 -0 -1 - offset: -0.5 - center: 0 0 -0.5 - coplanar set(furthest p8): p8: 0 0 -0.5 furthest distance= 0 - vertices: p6(v6) p2(v3) p4(v2) p0(v1) - neighboring facets: f2 f3 f10 f9 - ridges: - r4 tested simplicialtop simplicialbot vertices: p2(v3) p0(v1) between f1 and f3 - r3 tested simplicialtop simplicialbot vertices: p4(v2) p0(v1) between f2 and f1 - r1 tested simplicialtop vertices: p6(v6) p4(v2) between f9 and f1 - r2 tested simplicialbot vertices: p6(v6) p2(v3) between f1 and f10 - f2 - flags: top tested - merges: 1 - normal: 0 -1 0 - offset: -0.5 - center: 0 -0.5 0 - coplanar set(furthest p10): p10: 0 -0.5 0 furthest distance= 0 - vertices: p5(v7) p1(v4) p4(v2) p0(v1) - neighboring facets: f1 f3 f13 f9 - ridges: - r3 tested simplicialtop simplicialbot vertices: p4(v2) p0(v1) between f2 and f1 - r8 tested simplicialtop simplicialbot vertices: p1(v4) p0(v1) between f3 and f2 - r7 tested simplicialtop vertices: p5(v7) p1(v4) between f13 and f2 - r6 tested vertices: p5(v7) p4(v2) between f2 and f9 - f9 - flags: bottom tested - merges: 1 - normal: 1 -0 -0 - offset: -0.5 - center: 0.5 0 0 - coplanar set(furthest p13): p13: 0.5 0 0 furthest distance= 0 - vertices: p5(v7) p6(v6) p7(v5) p4(v2) - neighboring facets: f2 f1 f10 f13 - ridges: - r1 tested simplicialtop vertices: p6(v6) p4(v2) between f9 and f1 - r6 tested vertices: p5(v7) p4(v2) between f2 and f9 - r10 tested simplicialbot vertices: p5(v7) p7(v5) between f9 and f13 - r11 tested simplicialtop simplicialbot vertices: p6(v6) p7(v5) between f10 and f9 - f3 - flags: bottom tested - merges: 1 - normal: -1 -0 -0 - offset: -0.5 - center: -0.5 0 0 - coplanar set(furthest p12): p12: -0.5 0 0 furthest distance= 0 - vertices: p3(v8) p1(v4) p2(v3) p0(v1) - neighboring facets: f1 f2 f13 f10 - ridges: - r4 tested simplicialtop simplicialbot vertices: p2(v3) p0(v1) between f1 and f3 - r13 tested vertices: p3(v8) p2(v3) between f10 and f3 - r14 tested vertices: p3(v8) p1(v4) between f3 and f13 - r8 tested simplicialtop simplicialbot vertices: p1(v4) p0(v1) between f3 and f2 - f10 - flags: top tested - merges: 1 - normal: 0 1 -0 - offset: -0.5 - center: 0 0.5 0 - coplanar set(furthest p11): p11: 0 0.5 0 furthest distance= 0 - vertices: p3(v8) p6(v6) p7(v5) p2(v3) - neighboring facets: f3 f1 f9 f13 - ridges: - r2 tested simplicialbot vertices: p6(v6) p2(v3) between f1 and f10 - r11 tested simplicialtop simplicialbot vertices: p6(v6) p7(v5) between f10 and f9 - r16 tested vertices: p3(v8) p7(v5) between f13 and f10 - r13 tested vertices: p3(v8) p2(v3) between f10 and f3 - f13 - flags: bottom tested - merges: 1 - normal: -0 -0 1 - offset: -0.5 - center: 0 0 0.5 - coplanar set(furthest p9): p9: 0 0 0.5 furthest distance= 0 - vertices: p3(v8) p5(v7) p7(v5) p1(v4) - neighboring facets: f10 f2 f9 f3 - ridges: - r7 tested simplicialtop vertices: p5(v7) p1(v4) between f13 and f2 - r14 tested vertices: p3(v8) p1(v4) between f3 and f13 - r16 tested vertices: p3(v8) p7(v5) between f13 and f10 - r10 tested simplicialbot vertices: p5(v7) p7(v5) between f9 and f13 Output completed. Verifying that all points are below outer planes of all facets. Will make 84 distance computations. rbox c d | qhull Qc p Tcv 3 14 -0.5 -0.5 -0.5 -0.5 -0.5 0.5 -0.5 0.5 -0.5 -0.5 0.5 0.5 0.5 -0.5 -0.5 0.5 -0.5 0.5 0.5 0.5 -0.5 0.5 0.5 0.5 0 0 -0.5 0 0 0.5 0 -0.5 0 0 0.5 0 -0.5 0 0 0.5 0 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 84 distance computations. rbox 100 D3 | qhull QbB FO Tcv Options selected for Qhull 2020.2.r 2020/07/24: run-id 213865456 QbBound-unit-box 0.5 Tcheck-frequently Tverify _pre-merge _zero-centrum _max-width 1 Error-roundoff 6.9e-16 _one-merge 4.9e-15 _near-inside 2.4e-14 Visible-distance 1.4e-15 U-max-coplanar 1.4e-15 Width-outside 2.8e-15 _wide-facet 8.3e-15 Convex hull of 100 points in 3-d: Number of vertices: 26 Number of facets: 48 Statistics for: rbox 100 D3 | qhull QbB FO Tcv Number of points processed: 28 Number of hyperplanes created: 109 Number of distance tests for qhull: 1163 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below outer planes of all facets. Will make 4800 distance computations. rbox 1000 D2 B1e6 | qhull d Qbb FO Tcv Options selected for Qhull 2020.2.r 2020/07/24: run-id 213865456 delaunay Qbbound-last Tcheck-frequently Tverify _pre-merge _zero-centrum Pgood _max-width 2e+06 Error-roundoff 1.4e-09 _one-merge 9.7e-09 _near-inside 4.9e-08 Visible-distance 2.8e-09 U-max-coplanar 2.8e-09 Width-outside 5.5e-09 _wide-facet 1.7e-08 Delaunay triangulation by the convex hull of 1000 points in 3-d: Number of input sites: 1000 Number of Delaunay regions: 1982 Statistics for: rbox 1000 D2 B1e6 | qhull d Qbb FO Tcv Number of points processed: 1000 Number of hyperplanes created: 5457 Number of facets in hull: 1996 Number of distance tests for qhull: 27959 CPU seconds to compute hull (after input): 0.036 qhull output completed. Verifying that 1000 points are below 4.2e-09 of the nearest facet. rbox 10 D3 | qhull QbB p Tcv 3 9 -0.08928142660407055 -0.3194671263098747 0.3605569202297553 -0.1534778158747162 0.03516440701453921 0.5 -0.01663016790622804 0.3709299907861695 0.0764863283135003 0.3932651765570926 0.4421392241401818 -0.09396622763110282 0.199424728304684 0.5 0.06620718432588452 -0.2331094527352667 0.3262436269787957 -0.128966098672764 -0.5 0.2819439085196089 -0.5 0.4999999999999999 0.3760666748352666 0.1399187075693636 0.4888102268053206 -0.5 -0.2153953634886358 Output completed. Verifying that all points are below 2.1e-15 of all facets. Will make 140 distance computations. rbox 10 D3 | qhull Qbb p Tcv QH7040 qhull option warning: option 'Qbb' (scale-last-coordinate) is normally used with 'd' or 'v' 3 9 -0.0222149361131852 -0.366434993563625 0.4072229792632261 -0.06676722137887703 -0.1566931052661437 0.4732086509216659 0.02820502736438535 0.04189077954915421 0.272798317696016 0.3126723396709863 0.08400649026409401 0.1921386936513206 0.1781470954214661 0.1182274414396169 0.2679341378370068 -0.1220315663349177 0.01546165115708642 0.1755764518932639 -0.3072535691850387 -0.01073880122111998 0 0.3867462923626847 0.04492879989084675 0.3028150683084346 0.3789805913148268 -0.4732086509216658 0.1346773760895938 Output completed. Verifying that all points are below 2e-15 of all facets. Will make 140 distance computations. rbox 10 D3 | qhull Qb0:-10B2:20 p Tcv 3 9 -5.733970380575339 -0.366434993563625 17.14322461142018 -6.400761988815288 -0.1566931052661437 20 -4.97936018866004 0.04189077954915421 11.32346018178493 -0.7218812392989191 0.08400649026409401 7.831392539952951 -2.735252796494545 0.1182274414396169 11.11287098934976 -7.227875597731384 0.01546165115708642 7.114348923589702 -10 -0.01073880122111998 -0.4870359524963758 0.3867462923626847 0.04492879989084675 12.62300161615219 0.2705209571204694 -0.4732086509216658 5.343669467959105 Output completed. Verifying that all points are below 7.5e-14 of all facets. Will make 140 distance computations. rbox 10 D3 | qhull Qb0:-10B2:20 p Tcv | qhull QbB p Tcv Output completed. Verifying that all points are below 7.5e-14 of all facets. Will make 140 distance computations. 3 9 -0.08928142660407051 -0.3194671263098747 0.3605569202297555 -0.153477815874716 0.03516440701453921 0.5 -0.01663016790622796 0.3709299907861695 0.07648632831350011 0.3932651765570927 0.4421392241401818 -0.09396622763110274 0.1994247283046841 0.5 0.06620718432588446 -0.2331094527352668 0.3262436269787957 -0.1289660986727639 -0.5 0.2819439085196089 -0.4999999999999999 0.5 0.3760666748352666 0.1399187075693635 0.4888102268053207 -0.5 -0.2153953634886357 Output completed. Verifying that all points are below 2.1e-15 of all facets. Will make 126 distance computations. rbox 10 D3 | qhull Qb1:0B1:0 d Tcv Q8 Delaunay triangulation by the convex hull of 10 points in 3-d: Number of input sites: 10 Number of Delaunay regions: 14 Statistics for: rbox 10 D3 | qhull Qb1:0B1:0 d Tcv Q8 Number of points processed: 10 Number of hyperplanes created: 31 Number of facets in hull: 16 Number of distance tests for qhull: 61 CPU seconds to compute hull (after input): 0 QH7077 qhull input warning: no outer plane check ('Q5') or no processing of near-inside points ('Q8'). Verify may report that a point is outside of a facet. Output completed. Verifying that all points are below 2e-15 of all facets. Will make 140 distance computations. rbox 10 D3 | qhull Qb1:0B1:0B2:0 d Tcv Q8 Delaunay triangulation by the convex hull of 10 points in 3-d: Number of input sites: 10 Number of Delaunay regions: 14 Statistics for: rbox 10 D3 | qhull Qb1:0B1:0B2:0 d Tcv Q8 Number of points processed: 10 Number of hyperplanes created: 31 Number of facets in hull: 16 Number of distance tests for qhull: 61 CPU seconds to compute hull (after input): 0 QH7077 qhull input warning: no outer plane check ('Q5') or no processing of near-inside points ('Q8'). Verify may report that a point is outside of a facet. Output completed. Verifying that all points are below 2e-15 of all facets. Will make 140 distance computations. rbox 10 D3 | qhull Qb1:0 d Tcv Delaunay triangulation by the convex hull of 10 points in 4-d: Number of input sites: 10 Number of Delaunay regions: 18 Statistics for: rbox 10 D3 | qhull Qb1:0 d Tcv Number of points processed: 10 Number of hyperplanes created: 43 Number of facets in hull: 27 Number of distance tests for qhull: 66 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below 2.9e-15 of all facets. Will make 180 distance computations. rbox 10 D3 | qhull Qb1:0B1:0 Tcv Convex hull of 10 points in 2-d: Number of vertices: 4 Number of facets: 4 Statistics for: rbox 10 D3 | qhull Qb1:0B1:0 Tcv Number of points processed: 4 Number of hyperplanes created: 6 Number of distance tests for qhull: 48 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below 1.3e-15 of all facets. Will make 40 distance computations. echo "== next command will error ${d:-`date`} ==" == next command will error Fri, Jul 24, 2020 10:27:36 PM == rbox 10 D2 | qhull Qb1:1B1:1 Tcv QH6154 Qhull precision error: Initial simplex is flat (facet 1 is coplanar with the interior point) While executing: rbox 10 D2 | qhull Qb1:1B1:1 Tcv Options selected for Qhull 2020.2.r 2020/07/24: run-id 213865456 Qbound-dim-low 1 1 QBound-dim-high 1 1 Tcheck-frequently Tverify _pre-merge _zero-centrum _max-width 0.81 Error-roundoff 8.6e-16 _one-merge 4.3e-15 _near-inside 2.1e-14 Visible-distance 1.7e-15 U-max-coplanar 1.7e-15 Width-outside 3.4e-15 _wide-facet 1e-14 _maxoutside 5.1e-15 The input to qhull appears to be less than 2 dimensional, or a computation has overflowed. Qhull could not construct a clearly convex simplex from points: - p0(v3): -0.022 1 - p4(v2): 0.38 1 - p1(v1): -0.43 1 The center point is coplanar with a facet, or a vertex is coplanar with a neighboring facet. The maximum round off error for computing distances is 8.6e-16. The center point, facets and distances to the center point are as follows: center point -0.02391 1 facet p4 p1 distance= 0 facet p0 p1 distance= 0 facet p0 p4 distance= 0 These points either have a maximum or minimum x-coordinate, or they maximize the determinant for k coordinates. Trial points are first selected from points that maximize a coordinate. The min and max coordinates for each dimension are: 0: -0.4285 0.379 difference= 0.8076 1: 1 1 difference= 0 If the input should be full dimensional, you have several options that may determine an initial simplex: - use 'QJ' to joggle the input and make it full dimensional - use 'QbB' to scale the points to the unit cube - use 'QR0' to randomly rotate the input for different maximum points - use 'Qs' to search all points for the initial simplex - use 'En' to specify a maximum roundoff error less than 8.6e-16. - trace execution with 'T3' to see the determinant for each point. If the input is lower dimensional: - use 'QJ' to joggle the input and make it full dimensional - use 'Qbk:0Bk:0' to delete coordinate k from the input. You should pick the coordinate with the least range. The hull will have the correct topology. - determine the flat containing the points, rotate the points into a coordinate plane, and delete the other coordinates. - add one or more points to make the input full dimensional. rbox 200 L20 D2 t | qhull FO Tcv C-0 Options selected for Qhull 2020.2.r 2020/07/24: run-id 213865456 Tcheck-frequently Tverify Centrum-premerge- 0 _zero-centrum _max-width 0.98 Error-roundoff 3.4e-16 _one-merge 1.7e-15 _near-inside 8.5e-15 Visible-distance 6.8e-16 U-max-coplanar 6.8e-16 Width-outside 1.4e-15 _wide-facet 4.1e-15 Convex hull of 200 points in 2-d: Number of vertices: 200 Number of facets: 200 Statistics for: rbox 200 L20 D2 t1595644056 | qhull FO Tcv C-0 Number of points processed: 200 Number of hyperplanes created: 397 Number of distance tests for qhull: 2118 CPU seconds to compute hull (after input): 0.002 Output completed. Verifying that all points are below 1e-15 of all facets. Will make 40000 distance computations. rbox 1000 L20 t | qhull FO Tcv C-0 Options selected for Qhull 2020.2.r 2020/07/24: run-id 213865456 Tcheck-frequently Tverify Centrum-premerge- 0 _zero-centrum _max-width 1 Error-roundoff 6.9e-16 _one-merge 4.8e-15 _near-inside 2.4e-14 Visible-distance 1.4e-15 U-max-coplanar 1.4e-15 Width-outside 2.8e-15 _wide-facet 8.3e-15 Convex hull of 1000 points in 3-d: Number of vertices: 49 Number of facets: 94 Statistics for: rbox 1000 L20 t1595644056 | qhull FO Tcv C-0 Number of points processed: 63 Number of hyperplanes created: 272 Number of distance tests for qhull: 13669 CPU seconds to compute hull (after input): 0.001 Output completed. Verifying that all points are below outer planes of all facets. Will make 94000 distance computations. rbox 200 L20 D4 t | qhull FO Tcv C-0 Options selected for Qhull 2020.2.r 2020/07/24: run-id 213865456 Tcheck-frequently Tverify Centrum-premerge- 0 _zero-centrum _max-width 0.99 Error-roundoff 1e-15 _one-merge 9.1e-15 _near-inside 4.5e-14 Visible-distance 6e-15 U-max-coplanar 6e-15 Width-outside 1.2e-14 _wide-facet 3.6e-14 Convex hull of 200 points in 4-d: Number of vertices: 55 Number of facets: 261 Statistics for: rbox 200 L20 D4 t1595644056 | qhull FO Tcv C-0 Number of points processed: 67 Number of hyperplanes created: 823 Number of distance tests for qhull: 6036 CPU seconds to compute hull (after input): 0.002 Output completed. Verifying that all points are below outer planes of all facets. Will make 52200 distance computations. rbox 200 L20 D5 t | qhull FO Tcv Qx Options selected for Qhull 2020.2.r 2020/07/24: run-id 213865456 Tcheck-frequently Tverify Qxact-merge _zero-centrum _max-width 0.99 Error-roundoff 1.4e-15 _one-merge 1.5e-14 _near-inside 7.5e-14 Visible-distance 8.2e-15 U-max-coplanar 8.2e-15 Width-outside 1.6e-14 _wide-facet 4.9e-14 Convex hull of 200 points in 5-d: Number of vertices: 90 Number of facets: 1272 Statistics for: rbox 200 L20 D5 t1595644056 | qhull FO Tcv Qx Number of points processed: 111 Number of hyperplanes created: 3928 Number of distance tests for qhull: 17297 CPU seconds to compute hull (after input): 0.013 QH7076 qhull input warning: exact merge ('Qx'). Verify may report that a point is outside of a facet. See qh-optq.htm#Qx Output completed. Verifying that all points are below outer planes of all facets. Will make 254400 distance computations. rbox 1000 W1e-3 s D2 t | qhull d FO Tcv Qu Q0 Options selected for Qhull 2020.2.r 2020/07/24: run-id 213882263 delaunay Tcheck-frequently Tverify QupperDelaunay Q0-no-premerge Pgood _max-width 1 Error-roundoff 6.9e-16 Visible-distance 6.9e-16 U-max-coplanar 6.9e-16 Width-outside 1.4e-15 _wide-facet 4.2e-15 Furthest-site Delaunay triangulation by the convex hull of 1000 points in 3-d: Number of input sites: 1000 Number of Delaunay regions: 259 Statistics for: rbox 1000 W1e-3 s D2 t1595644057 | qhull d FO Tcv Qu Q0 Number of points processed: 1000 Number of hyperplanes created: 4694 Number of facets in hull: 1996 Number of distance tests for qhull: 27601 CPU seconds to compute hull (after input): 0.037 Output completed. Verifying that all points are below 2.1e-15 of all facets. Will make 259000 distance computations. rbox 1000 W1e-3 s D2 t | qhull d FO Tcv Qu C-0 Options selected for Qhull 2020.2.r 2020/07/24: run-id 213882263 delaunay Tcheck-frequently Tverify QupperDelaunay Centrum-premerge- 0 _zero-centrum Pgood _max-width 1 Error-roundoff 6.9e-16 _one-merge 4.9e-15 _near-inside 2.4e-14 Visible-distance 1.4e-15 U-max-coplanar 1.4e-15 Width-outside 2.8e-15 _wide-facet 8.3e-15 Furthest-site Delaunay triangulation by the convex hull of 1000 points in 3-d: Number of input sites: 1000 Number of Delaunay regions: 259 Statistics for: rbox 1000 W1e-3 s D2 t1595644057 | qhull d FO Tcv Qu C-0 Number of points processed: 1000 Number of hyperplanes created: 4694 Number of facets in hull: 1996 Number of distance tests for qhull: 27601 CPU seconds to compute hull (after input): 0.035 Output completed. Verifying that all points are below 2.1e-15 of all facets. Will make 259000 distance computations. set +v === check joggle and TRn Fri, Jul 24, 2020 10:27:37 PM rbox 100 W0 | qhull QJ1e-14 Qc TR100 Tv Early exit due to 'TAn', 'TVn', 'TCn', 'TRn', or precision error with 'QJn'. Convex hull of 100 points in 3-d: Number of vertices: 15 Number of coplanar points: 4 Number of facets: 25 Statistics for: rbox 100 W0 | qhull QJ1e-14 Qc TR100 Tv Number of points processed: 15 Number of hyperplanes created: 11218 Number of distance tests for qhull: 119030 CPU seconds to compute hull (after input): 0.008 Percentage of runs with precision errors: 100.0 precision problems (corrected unless 'Q0' or an error) 100 coplanar horizon facets for new vertices 400 coplanar points during partitioning rbox 100 W0 | qhull QJ1e-13 Qc TR100 Tv Early exit due to 'TAn', 'TVn', 'TCn', 'TRn', or precision error with 'QJn'. Convex hull of 100 points in 3-d: Number of vertices: 28 Number of coplanar points: 12 Number of facets: 50 Statistics for: rbox 100 W0 | qhull QJ1e-13 Qc TR100 Tv Number of points processed: 28 Number of hyperplanes created: 24747 Number of distance tests for qhull: 195826 CPU seconds to compute hull (after input): 0.016 Percentage of runs with precision errors: 63.0 precision problems (corrected unless 'Q0' or an error) 10 coplanar half ridges in output 53 coplanar horizon facets for new vertices 119 coplanar points during partitioning rbox 100 W0 | qhull QJ1e-12 Qc TR100 Tv Early exit due to 'TAn', 'TVn', 'TCn', 'TRn', or precision error with 'QJn'. Convex hull of 100 points in 3-d: Number of vertices: 40 Number of coplanar points: 16 Number of facets: 75 Statistics for: rbox 100 W0 | qhull QJ1e-12 Qc TR100 Tv Number of points processed: 40 Number of hyperplanes created: 29152 Number of distance tests for qhull: 216487 CPU seconds to compute hull (after input): 0.017 Percentage of runs with precision errors: 8.0 precision problems (corrected unless 'Q0' or an error) 2 coplanar half ridges in output 6 coplanar horizon facets for new vertices 17 coplanar points during partitioning rbox 100 W0 | qhull QJ1e-11 Qc TR100 Tv Convex hull of 100 points in 3-d: Number of vertices: 66 Number of coplanar points: 34 Number of facets: 128 Statistics for: rbox 100 W0 | qhull QJ1e-11 Qc TR100 Tv Number of points processed: 75 Number of hyperplanes created: 29577 Number of distance tests for qhull: 218409 CPU seconds to compute hull (after input): 0.017 Percentage of runs with precision errors: 0.0 precision problems (corrected unless 'Q0' or an error) 3 coplanar points during partitioning Output completed. Verifying that all points are below 2.1e-15 of all facets. Will make 12800 distance computations. rbox 100 W0 | qhull QJ1e-10 Qc TR100 Tv Convex hull of 100 points in 3-d: Number of vertices: 66 Number of coplanar points: 34 Number of facets: 128 Statistics for: rbox 100 W0 | qhull QJ1e-10 Qc TR100 Tv Number of points processed: 75 Number of hyperplanes created: 29583 Number of distance tests for qhull: 218315 CPU seconds to compute hull (after input): 0.018 Percentage of runs with precision errors: 0.0 Output completed. Verifying that all points are below 2.1e-15 of all facets. Will make 12800 distance computations. rbox 100 | qhull d QJ Qb0:1e4 QB0:1e5 Qb1:1e4 QB1:1e6 Qb2:1e5 QB2:1e7 FO Tv Options selected for Qhull 2020.2.r 2020/07/24: run-id 213882263 delaunay Qbound-dim-low 0 1e+04 QBound-dim-high 0 1e+05 Qbound-dim-low 1 1e+04 QBound-dim-high 1 1e+06 Qbound-dim-low 2 1e+05 QBound-dim-high 2 1e+07 Tverify Pgood _run 1 QJoggle 6.7e+03 _joggle-seed 16807 _max-width 1e+14 Error-roundoff 0.11 Visible-distance 0.11 U-max-coplanar 0.11 Width-outside 0.23 _wide-facet 0.68 Delaunay triangulation by the convex hull of 100 points in 4-d: Number of input sites: 100 Number of Delaunay regions: 488 Statistics for: rbox 100 | qhull d QJ Qb0:1e4 QB0:1e5 Qb1:1e4 QB1:1e6 Qb2:1e5 QB2:1e7 FO Tv Number of points processed: 100 Number of hyperplanes created: 1477 Number of facets in hull: 560 Number of distance tests for qhull: 3418 CPU seconds to compute hull (after input): 0.001 Input joggled by: 6.7e+03 Output completed. Verifying that all points are below 0.34 of all facets. Will make 48800 distance computations. set +v === check precision options Fri, Jul 24, 2020 10:27:37 PM rbox 100 D3 s | qhull E0.01 Qx Tcv FO Options selected for Qhull 2020.2.r 2020/07/24: run-id 213882263 Distance-roundoff 0.01 Qxact-merge Tcheck-frequently Tverify _zero-centrum _max-width 0.98 _one-merge 0.07 _near-inside 0.35 Visible-distance 0.02 U-max-coplanar 0.02 Width-outside 0.04 _wide-facet 0.12 Convex hull of 100 points in 3-d: Number of vertices: 46 Number of facets: 41 Number of non-simplicial facets: 29 Statistics for: rbox 100 D3 s | qhull E0.01 Qx Tcv FO Number of points processed: 46 Number of hyperplanes created: 162 Number of distance tests for qhull: 3834 Number of distance tests for merging: 1887 Number of distance tests for checking: 1989 Number of merged facets: 60 CPU seconds to compute hull (after input): 0.001 Maximum distance of point above facet: 0.048 (0.6x) Maximum distance of vertex below facet: -0.072 (0.9x) QH7076 qhull input warning: exact merge ('Qx'). Verify may report that a point is outside of a facet. See qh-optq.htm#Qx Output completed. Verifying that all points are below outer planes of all facets. Will make 4100 distance computations. rbox 100 D3 W1e-1 | qhull W1e-3 Tcv Convex hull of 100 points in 3-d: Number of vertices: 33 Number of facets: 62 Statistics for: rbox 100 D3 W1e-1 | qhull W1e-3 Tcv Number of points processed: 37 Number of hyperplanes created: 169 Number of distance tests for qhull: 1565 CPU seconds to compute hull (after input): 0 Maximum distance of point above facet: 0.00084 Output completed. Verifying that all points are below outer planes of all facets. Will make 6200 distance computations. rbox 100 D3 W1e-1 | qhull W1e-2 Tcv Q0 Convex hull of 100 points in 3-d: Number of vertices: 28 Number of facets: 52 Statistics for: rbox 100 D3 W1e-1 | qhull W1e-2 Tcv Q0 Number of points processed: 29 Number of hyperplanes created: 127 Number of distance tests for qhull: 1691 CPU seconds to compute hull (after input): 0 precision problems (corrected unless 'Q0' or an error) 23 coplanar points during partitioning Output completed. Verifying that all points are below outer planes of all facets. Will make 5200 distance computations. rbox 100 D3 W1e-1 | qhull W1e-2 Tcv Convex hull of 100 points in 3-d: Number of vertices: 29 Number of facets: 54 Statistics for: rbox 100 D3 W1e-1 | qhull W1e-2 Tcv Number of points processed: 30 Number of hyperplanes created: 131 Number of distance tests for qhull: 1720 CPU seconds to compute hull (after input): 0 Maximum distance of point above facet: 0.0057 Output completed. Verifying that all points are below outer planes of all facets. Will make 5400 distance computations. rbox 100 D3 W1e-1 | qhull W1e-1 Tcv Convex hull of 100 points in 3-d: Number of vertices: 13 Number of facets: 22 Statistics for: rbox 100 D3 W1e-1 | qhull W1e-1 Tcv Number of points processed: 13 Number of hyperplanes created: 45 Number of distance tests for qhull: 2377 CPU seconds to compute hull (after input): 0 Maximum distance of point above facet: 0.098 Output completed. Verifying that all points are below outer planes of all facets. Will make 2200 distance computations. rbox 15 D2 P0 P1e-14,1e-14 | qhull d Quc Tcv Furthest-site Delaunay triangulation by the convex hull of 17 points in 3-d: Number of input sites: 17 Number of Delaunay regions: 5 Statistics for: rbox 15 D2 P0 P1e-14,1e-14 | qhull d Quc Tcv Number of points processed: 17 Number of hyperplanes created: 63 Number of facets in hull: 28 Number of distance tests for qhull: 141 Number of distance tests for merging: 474 Number of distance tests for checking: 236 Number of merged facets: 7 CPU seconds to compute hull (after input): 0 Maximum distance of point above facet: 1.6e-15 (0.3x) Output completed. Verifying that all points are below outer planes of all facets. Will make 85 distance computations. rbox 15 D3 P0 P1e-12,1e-14,1e-14 | qhull d Qcu Tcv Furthest-site Delaunay triangulation by the convex hull of 17 points in 4-d: Number of input sites: 17 Number of Delaunay regions: 14 Statistics for: rbox 15 D3 P0 P1e-12,1e-14,1e-14 | qhull d Qcu Tcv Number of points processed: 17 Number of hyperplanes created: 123 Number of facets in hull: 60 Number of distance tests for qhull: 224 CPU seconds to compute hull (after input): 0 Output completed. Verifying that all points are below 2.8e-15 of all facets. Will make 238 distance computations. rbox 1000 s D3 | qhull C-0.01 Tcv Qc Convex hull of 1000 points in 3-d: Number of vertices: 108 Number of coplanar points: 892 Number of facets: 95 Number of non-simplicial facets: 78 Statistics for: rbox 1000 s D3 | qhull C-0.01 Tcv Qc Number of points processed: 112 Number of hyperplanes created: 464 Number of distance tests for qhull: 62162 Number of distance tests for merging: 6682 Number of distance tests for checking: 24376 Number of merged facets: 264 CPU seconds to compute hull (after input): 0.007 Maximum distance of point above facet: 0.021 (0.7x) Maximum distance of vertex below facet: -0.029 (1.0x) Output completed. Verifying that all points are below outer planes of all facets. Will make 95000 distance computations. rbox 1000 s D3 | qhull C-0.01 V0 Qc Tcv Convex hull of 1000 points in 3-d: Number of vertices: 137 Number of coplanar points: 863 Number of facets: 87 Number of non-simplicial facets: 82 Statistics for: rbox 1000 s D3 | qhull C-0.01 V0 Qc Tcv Number of points processed: 466 Number of hyperplanes created: 2572 Number of distance tests for qhull: 232429 Number of distance tests for merging: 47390 Number of distance tests for checking: 38513 Number of merged facets: 1818 CPU seconds to compute hull (after input): 0.046 Maximum distance of point above facet: 0.026 (0.9x) Maximum distance of vertex below facet: -0.075 (2.5x) Output completed. Verifying that all points are below outer planes of all facets. Will make 87000 distance computations. rbox 1000 s D3 | qhull C-0.01 U0 Qc Tcv Convex hull of 1000 points in 3-d: Number of vertices: 108 Number of coplanar points: 892 Number of facets: 97 Number of non-simplicial facets: 77 Statistics for: rbox 1000 s D3 | qhull C-0.01 U0 Qc Tcv Number of points processed: 112 Number of hyperplanes created: 505 Number of distance tests for qhull: 62212 Number of distance tests for merging: 7315 Number of distance tests for checking: 24575 Number of merged facets: 260 CPU seconds to compute hull (after input): 0.006 Maximum distance of point above facet: 0.021 (0.7x) Maximum distance of vertex below facet: -0.029 (1.0x) Output completed. Verifying that all points are below outer planes of all facets. Will make 97000 distance computations. rbox 1000 s D3 | qhull C-0.01 V0 Qcm Tcv Convex hull of 1000 points in 3-d: Number of vertices: 87 Number of coplanar points: 913 Number of facets: 88 Number of non-simplicial facets: 56 Statistics for: rbox 1000 s D3 | qhull C-0.01 V0 Qcm Tcv Number of points processed: 90 Number of hyperplanes created: 457 Number of distance tests for qhull: 46341 Number of distance tests for merging: 5761 Number of distance tests for checking: 21602 Number of merged facets: 192 CPU seconds to compute hull (after input): 0.005 Maximum distance of point above facet: 0.032 (1.1x) Maximum distance of vertex below facet: -0.041 (1.4x) Output completed. Verifying that all points are below outer planes of all facets. Will make 88000 distance computations. rbox 1000 s D3 | qhull C-0.01 Qcm Tcv Convex hull of 1000 points in 3-d: Number of vertices: 101 Number of coplanar points: 899 Number of facets: 95 Number of non-simplicial facets: 69 Statistics for: rbox 1000 s D3 | qhull C-0.01 Qcm Tcv Number of points processed: 104 Number of hyperplanes created: 433 Number of distance tests for qhull: 59136 Number of distance tests for merging: 6024 Number of distance tests for checking: 24116 Number of merged facets: 232 CPU seconds to compute hull (after input): 0.006 Maximum distance of point above facet: 0.023 (0.8x) Maximum distance of vertex below facet: -0.031 (1.0x) Output completed. Verifying that all points are below outer planes of all facets. Will make 95000 distance computations. rbox 1000 s D3 | qhull C-0.01 Q1 FO Tcv Qc Options selected for Qhull 2020.2.r 2020/07/24: run-id 213899070 Centrum-premerge- 0.01 Q1-angle-merge Tcheck-frequently Tverify Qcoplanar-keep _max-width 1 Error-roundoff 6.9e-16 _one-merge 0.03 _near-inside 0.15 Visible-distance 0.01 U-max-coplanar 0.01 Width-outside 0.02 _wide-facet 0.06 Convex hull of 1000 points in 3-d: Number of vertices: 107 Number of coplanar points: 893 Number of facets: 97 Number of non-simplicial facets: 80 Statistics for: rbox 1000 s D3 | qhull C-0.01 Q1 FO Tcv Qc Number of points processed: 111 Number of hyperplanes created: 450 Number of distance tests for qhull: 61776 Number of distance tests for merging: 6387 Number of distance tests for checking: 24594 Number of merged facets: 253 CPU seconds to compute hull (after input): 0.006 Maximum distance of point above facet: 0.02 (0.7x) Maximum distance of vertex below facet: -0.035 (1.2x) Output completed. Verifying that all points are below outer planes of all facets. Will make 97000 distance computations. rbox 1000 s D3 | qhull C-0.01 Q2 FO Tcv Qc Options selected for Qhull 2020.2.r 2020/07/24: run-id 213899070 Centrum-premerge- 0.01 Q2-no-merge-independent Tcheck-frequently Tverify Qcoplanar-keep _max-width 1 Error-roundoff 6.9e-16 _one-merge 0.03 _near-inside 0.15 Visible-distance 0.01 U-max-coplanar 0.01 Width-outside 0.02 _wide-facet 0.06 Convex hull of 1000 points in 3-d: Number of vertices: 106 Number of coplanar points: 894 Number of facets: 92 Number of non-simplicial facets: 74 Statistics for: rbox 1000 s D3 | qhull C-0.01 Q2 FO Tcv Qc Number of points processed: 110 Number of hyperplanes created: 451 Number of distance tests for qhull: 60312 Number of distance tests for merging: 6396 Number of distance tests for checking: 23893 Number of merged facets: 260 CPU seconds to compute hull (after input): 0.007 Maximum distance of point above facet: 0.023 (0.8x) Maximum distance of vertex below facet: -0.049 (1.6x) Output completed. Verifying that all points are below outer planes of all facets. Will make 92000 distance computations. rbox 1000 s D3 | qhull C-0.01 Q3 FO Tcv Qc Options selected for Qhull 2020.2.r 2020/07/24: run-id 213899070 Centrum-premerge- 0.01 Q3-no-merge-vertices Tcheck-frequently Tverify Qcoplanar-keep _max-width 1 Error-roundoff 6.9e-16 _one-merge 0.03 _near-inside 0.15 Visible-distance 0.01 U-max-coplanar 0.01 Width-outside 0.02 _wide-facet 0.06 Convex hull of 1000 points in 3-d: Number of vertices: 112 Number of coplanar points: 888 Number of facets: 94 Number of non-simplicial facets: 78 Statistics for: rbox 1000 s D3 | qhull C-0.01 Q3 FO Tcv Qc Number of points processed: 112 Number of hyperplanes created: 468 Number of distance tests for qhull: 61911 Number of distance tests for merging: 6879 Number of distance tests for checking: 24243 Number of merged facets: 268 CPU seconds to compute hull (after input): 0.007 Maximum distance of point above facet: 0.021 (0.7x) Maximum distance of vertex below facet: -0.03 (1.0x) Output completed. Verifying that all points are below outer planes of all facets. Will make 94000 distance computations. rbox 1000 s D3 | qhull C-0.01 Q4 FO Tcv Qc Options selected for Qhull 2020.2.r 2020/07/24: run-id 213899070 Centrum-premerge- 0.01 Q4-avoid-old-into-new Tcheck-frequently Tverify Qcoplanar-keep _max-width 1 Error-roundoff 6.9e-16 _one-merge 0.03 _near-inside 0.15 Visible-distance 0.01 U-max-coplanar 0.01 Width-outside 0.02 _wide-facet 0.06 Convex hull of 1000 points in 3-d: Number of vertices: 108 Number of coplanar points: 892 Number of facets: 95 Number of non-simplicial facets: 78 Statistics for: rbox 1000 s D3 | qhull C-0.01 Q4 FO Tcv Qc Number of points processed: 112 Number of hyperplanes created: 464 Number of distance tests for qhull: 62162 Number of distance tests for merging: 6682 Number of distance tests for checking: 24376 Number of merged facets: 264 CPU seconds to compute hull (after input): 0.007 Maximum distance of point above facet: 0.021 (0.7x) Maximum distance of vertex below facet: -0.029 (1.0x) Output completed. Verifying that all points are below outer planes of all facets. Will make 95000 distance computations. echo === this may generate an error ${d:-`date`} === this may generate an error Fri, Jul 24, 2020 10:27:38 PM rbox 1000 s D3 | qhull C-0.01 Q5 FO Tcv Options selected for Qhull 2020.2.r 2020/07/24: run-id 213899070 Centrum-premerge- 0.01 Q5-no-check-outer Tcheck-frequently Tverify _max-width 1 Error-roundoff 6.9e-16 _one-merge 0.03 Visible-distance 0.01 U-max-coplanar 0.01 Width-outside 0.02 _wide-facet 0.06 Convex hull of 1000 points in 3-d: Number of vertices: 108 Number of facets: 95 Number of non-simplicial facets: 78 Statistics for: rbox 1000 s D3 | qhull C-0.01 Q5 FO Tcv Number of points processed: 112 Number of hyperplanes created: 464 Number of distance tests for qhull: 35756 Number of distance tests for merging: 6682 Number of distance tests for checking: 2036 Number of merged facets: 264 CPU seconds to compute hull (after input): 0.005 Maximum distance of point above facet: 0.022 (0.7x) Maximum distance of vertex below facet: -0.031 (1.0x) QH7077 qhull input warning: no outer plane check ('Q5') or no processing of near-inside points ('Q8'). Verify may report that a point is outside of a facet. Output completed. Verifying that all points are below 0.022 of all facets. Will make 95000 distance computations. echo === this should generate an error ${d:-`date`} === this should generate an error Fri, Jul 24, 2020 10:27:38 PM rbox 1000 s D3 | qhull C-0.01 Q6 FO Po Tcv Qc Options selected for Qhull 2020.2.r 2020/07/24: run-id 213899070 Centrum-premerge- 0.01 Q6-no-concave-merge Poutput-forced Tcheck-frequently Tverify Qcoplanar-keep _max-width 1 Error-roundoff 6.9e-16 _one-merge 0.03 _near-inside 0.15 Visible-distance 0.01 U-max-coplanar 0.01 Width-outside 0.02 _wide-facet 0.06 QH6117 qhull precision error: f328 is concave to f329. Centrum of f328 is 0.001027 above f329 QH6117 qhull precision error: f329 is concave to f328. Centrum of f329 is 0.004134 above f328 QH6117 qhull precision error: f482 is concave to f484. Centrum of f482 is 0.0001795 above f484 QH6117 qhull precision error: f484 is concave to f482. Centrum of f484 is 6.818e-05 above f482 Convex hull of 1000 points in 3-d: Number of vertices: 115 Number of coplanar points: 885 Number of facets: 184 Number of non-simplicial facets: 40 Statistics for: rbox 1000 s D3 | qhull C-0.01 Q6 FO Po Tcv Qc Number of points processed: 115 Number of hyperplanes created: 455 Number of distance tests for qhull: 52081 Number of distance tests for merging: 1190 Number of distance tests for checking: 28981 Number of merged facets: 88 CPU seconds to compute hull (after input): 0.005 Maximum distance of point above facet: 0.02 (0.7x) Maximum distance of vertex below facet: -0.009 (0.3x) rbox 1000 s D3 | qhull C-0.01 Q7 FO Tcv Qc Options selected for Qhull 2020.2.r 2020/07/24: run-id 213899070 Centrum-premerge- 0.01 Q7-no-breadth-first Tcheck-frequently Tverify Qcoplanar-keep _max-width 1 Error-roundoff 6.9e-16 _one-merge 0.03 _near-inside 0.15 Visible-distance 0.01 U-max-coplanar 0.01 Width-outside 0.02 _wide-facet 0.06 Convex hull of 1000 points in 3-d: Number of vertices: 108 Number of coplanar points: 892 Number of facets: 99 Number of non-simplicial facets: 77 Statistics for: rbox 1000 s D3 | qhull C-0.01 Q7 FO Tcv Qc Number of points processed: 110 Number of hyperplanes created: 449 Number of distance tests for qhull: 55287 Number of distance tests for merging: 6050 Number of distance tests for checking: 22232 Number of merged facets: 242 CPU seconds to compute hull (after input): 0.006 Maximum distance of point above facet: 0.021 (0.7x) Maximum distance of vertex below facet: -0.031 (1.0x) Output completed. Verifying that all points are below outer planes of all facets. Will make 99000 distance computations. rbox 1000 s D3 | qhull C-0.01 Qx Tcv Qc Convex hull of 1000 points in 3-d: Number of vertices: 115 Number of coplanar points: 885 Number of facets: 101 Number of non-simplicial facets: 76 Statistics for: rbox 1000 s D3 | qhull C-0.01 Qx Tcv Qc Number of points processed: 115 Number of hyperplanes created: 455 Number of distance tests for qhull: 89505 Number of distance tests for merging: 5154 Number of distance tests for checking: 19846 Number of merged facets: 171 CPU seconds to compute hull (after input): 0.006 Maximum distance of point above facet: 0.02 (0.7x) Maximum distance of vertex below facet: -0.034 (1.1x) QH7076 qhull input warning: exact merge ('Qx'). Verify may report that a point is outside of a facet. See qh-optq.htm#Qx Output completed. Verifying that all points are below outer planes of all facets. Will make 101000 distance computations. echo === this may generate an error e.g., t1263080158 ${d:-`date`} === this may generate an error e.g., t1263080158 Fri, Jul 24, 2020 10:27:38 PM rbox 100 s D3 t | qhull R1e-3 Tcv Qc Convex hull of 100 points in 3-d: Number of vertices: 99 Number of coplanar points: 1 Number of facets: 173 Number of non-simplicial facets: 19 Statistics for: rbox 100 s D3 t1595644058 | qhull R1e-3 Tcv Qc Number of points processed: 100 Number of hyperplanes created: 471 Number of distance tests for qhull: 1627 Number of distance tests for merging: 2780 Number of distance tests for checking: 1528 Number of merged facets: 33 CPU seconds to compute hull (after input): 0.002 Maximum distance of point above facet: 0.0017 (0.4x) Maximum distance of vertex below facet: -0.0062 (1.6x) Output completed. Verifying that all points are below outer planes of all facets. Will make 17300 distance computations. rbox 100 s D3 t | qhull R1e-2 Tcv Qc Convex hull of 100 points in 3-d: Number of vertices: 59 Number of coplanar points: 41 Number of facets: 57 Number of non-simplicial facets: 34 Statistics for: rbox 100 s D3 t1595644059 | qhull R1e-2 Tcv Qc Number of points processed: 61 Number of hyperplanes created: 269 Number of distance tests for qhull: 3527 Number of distance tests for merging: 3559 Number of distance tests for checking: 2604 Number of merged facets: 120 CPU seconds to compute hull (after input): 0.002 Maximum distance of point above facet: 0.034 (0.8x) Maximum distance of vertex below facet: -0.061 (1.5x) Output completed. Verifying that all points are below outer planes of all facets. Will make 5700 distance computations. rbox 500 s D3 t | qhull R0.05 A-1 Tcv Qc Convex hull of 500 points in 3-d: Number of vertices: 20 Number of coplanar points: 480 Number of facets: 15 Number of non-simplicial facets: 13 Statistics for: rbox 500 s D3 t1595644059 | qhull R0.05 A-1 Tcv Qc Number of points processed: 24 Number of hyperplanes created: 76 Number of distance tests for qhull: 20339 Number of distance tests for merging: 1188 Number of distance tests for checking: 6863 Number of merged facets: 49 CPU seconds to compute hull (after input): 0.002 Maximum distance of point above facet: 0.14 (0.2x) Maximum distance of vertex below facet: -0.24 (0.4x) Output completed. Verifying that all points are below outer planes of all facets. Will make 7500 distance computations. rbox 100 W0 D3 t | qhull R1e-3 Tcv Qc Convex hull of 100 points in 3-d: Number of vertices: 36 Number of coplanar points: 64 Number of facets: 46 Number of non-simplicial facets: 7 Statistics for: rbox 100 W0 D3 t1595644059 | qhull R1e-3 Tcv Qc Number of points processed: 48 Number of hyperplanes created: 160 Number of distance tests for qhull: 1898 Number of distance tests for merging: 1433 Number of distance tests for checking: 1387 Number of merged facets: 49 CPU seconds to compute hull (after input): 0.001 Maximum distance of point above facet: 0.0018 (0.5x) Maximum distance of vertex below facet: -0.0077 (1.9x) Output completed. Verifying that all points are below outer planes of all facets. Will make 4600 distance computations. rbox 100 W0 D3 t | qhull R1e-3 Qx Tcv Qc Convex hull of 100 points in 3-d: Number of vertices: 35 Number of coplanar points: 65 Number of facets: 46 Number of non-simplicial facets: 7 Statistics for: rbox 100 W0 D3 t1595644059 | qhull R1e-3 Qx Tcv Qc Number of points processed: 48 Number of hyperplanes created: 157 Number of distance tests for qhull: 2121 Number of distance tests for merging: 1562 Number of distance tests for checking: 1086 Number of merged facets: 46 CPU seconds to compute hull (after input): 0.001 Maximum distance of point above facet: 0.0018 (0.4x) Maximum distance of vertex below facet: -0.0041 (1.0x) QH7076 qhull input warning: exact merge ('Qx'). Verify may report that a point is outside of a facet. See qh-optq.htm#Qx Output completed. Verifying that all points are below outer planes of all facets. Will make 4600 distance computations. rbox 100 W0 D3 t | qhull R1e-2 Tcv Qc Convex hull of 100 points in 3-d: Number of vertices: 24 Number of coplanar points: 76 Number of facets: 25 Number of non-simplicial facets: 8 Statistics for: rbox 100 W0 D3 t1595644059 | qhull R1e-2 Tcv Qc Number of points processed: 32 Number of hyperplanes created: 105 Number of distance tests for qhull: 2303 Number of distance tests for merging: 1290 Number of distance tests for checking: 1263 Number of merged facets: 47 CPU seconds to compute hull (after input): 0.001 Maximum distance of point above facet: 0.026 (0.6x) Maximum distance of vertex below facet: -0.08 (2.0x) Output completed. Verifying that all points are below outer planes of all facets. Will make 2500 distance computations. rbox 100 W0 D3 t | qhull R1e-2 Qx Tcv Qc Convex hull of 100 points in 3-d: Number of vertices: 25 Number of coplanar points: 75 Number of facets: 26 Number of non-simplicial facets: 11 Statistics for: rbox 100 W0 D3 t1595644059 | qhull R1e-2 Qx Tcv Qc Number of points processed: 32 Number of hyperplanes created: 106 Number of distance tests for qhull: 2604 Number of distance tests for merging: 1089 Number of distance tests for checking: 1026 Number of merged facets: 37 CPU seconds to compute hull (after input): 0 Maximum distance of point above facet: 0.026 (0.7x) Maximum distance of vertex below facet: -0.051 (1.3x) QH7076 qhull input warning: exact merge ('Qx'). Verify may report that a point is outside of a facet. See qh-optq.htm#Qx Output completed. Verifying that all points are below outer planes of all facets. Will make 2600 distance computations. rbox 500 W0 D3 t | qhull R0.05 A-1 Tcv Qc Convex hull of 500 points in 3-d: Number of vertices: 8 Number of coplanar points: 492 Number of facets: 6 Number of non-simplicial facets: 6 Statistics for: rbox 500 W0 D3 t1595644059 | qhull R0.05 A-1 Tcv Qc Number of points processed: 17 Number of hyperplanes created: 48 Number of distance tests for qhull: 16359 Number of distance tests for merging: 670 Number of distance tests for checking: 3635 Number of merged facets: 33 CPU seconds to compute hull (after input): 0.001 Maximum distance of point above facet: 0.11 (0.2x) Maximum distance of vertex below facet: -0.2 (0.3x) Output completed. Verifying that all points are below outer planes of all facets. Will make 3000 distance computations. rbox 500 W0 D3 t | qhull R0.05 Qx Tcv Qc Convex hull of 500 points in 3-d: Number of vertices: 8 Number of coplanar points: 492 Number of facets: 6 Number of non-simplicial facets: 6 Statistics for: rbox 500 W0 D3 t1595644059 | qhull R0.05 Qx Tcv Qc Number of points processed: 20 Number of hyperplanes created: 52 Number of distance tests for qhull: 22372 Number of distance tests for merging: 729 Number of distance tests for checking: 3426 Number of merged facets: 43 CPU seconds to compute hull (after input): 0.001 Maximum distance of point above facet: 0.094 (0.5x) Maximum distance of vertex below facet: -0.14 (0.7x) QH7076 qhull input warning: exact merge ('Qx'). Verify may report that a point is outside of a facet. See qh-optq.htm#Qx Output completed. Verifying that all points are below outer planes of all facets. Will make 3000 distance computations. rbox 1000 W1e-20 t | qhull Tcv Qc Convex hull of 1000 points in 3-d: Number of vertices: 81 Number of coplanar points: 919 Number of facets: 95 Number of non-simplicial facets: 6 Statistics for: rbox 1000 W1e-20 t1595644059 | qhull Tcv Qc Number of points processed: 93 Number of hyperplanes created: 303 Number of distance tests for qhull: 18699 Number of distance tests for merging: 3015 Number of distance tests for checking: 16676 Number of merged facets: 87 CPU seconds to compute hull (after input): 0.002 Output completed. Verifying that all points are below outer planes of all facets. Will make 95000 distance computations. rbox 1000 W1e-20 D4 t | qhull Tcv Qc Convex hull of 1000 points in 4-d: Number of vertices: 287 Number of coplanar points: 713 Number of facets: 1029 Number of non-simplicial facets: 8 Statistics for: rbox 1000 W1e-20 D4 t1595644059 | qhull Tcv Qc Number of points processed: 340 Number of hyperplanes created: 4227 Number of distance tests for qhull: 69008 Number of distance tests for merging: 51153 Number of distance tests for checking: 88363 Number of merged facets: 997 CPU seconds to compute hull (after input): 0.086 Output completed. Verifying that all points are below outer planes of all facets. Will make 1029000 distance computations. rbox 500 W1e-20 D5 t | qhull Tv Qc Convex hull of 500 points in 5-d: Number of vertices: 348 Number of coplanar points: 152 Number of facets: 5402 Number of non-simplicial facets: 10 Statistics for: rbox 500 W1e-20 D5 t1595644059 | qhull Tv Qc Number of points processed: 405 Number of hyperplanes created: 27428 Number of distance tests for qhull: 130100 Number of distance tests for merging: 299784 Number of distance tests for checking: 118368 Number of merged facets: 3468 CPU seconds to compute hull (after input): 0.045 QH7076 qhull input warning: exact merge ('Qx'). Verify may report that a point is outside of a facet. See qh-optq.htm#Qx Output completed. Verifying that all points are below outer planes of all facets. Will make 2701000 distance computations. rbox 100 W1e-20 D6 t | qhull Tv Qc Convex hull of 100 points in 6-d: Number of vertices: 100 Number of facets: 6076 Number of non-simplicial facets: 10 Statistics for: rbox 100 W1e-20 D6 t1595644059 | qhull Tv Qc Number of points processed: 100 Number of hyperplanes created: 21104 Number of distance tests for qhull: 32827 Number of distance tests for merging: 181994 Number of distance tests for checking: 62831 Number of merged facets: 141 CPU seconds to compute hull (after input): 0.026 QH7076 qhull input warning: exact merge ('Qx'). Verify may report that a point is outside of a facet. See qh-optq.htm#Qx Output completed. Verifying that all points are below outer planes of all facets. Will make 607600 distance computations. rbox 50 W1e-20 D6 t | qhull Qv Tv Qc Convex hull of 50 points in 6-d: Number of vertices: 50 Number of facets: 2067 Number of non-simplicial facets: 1 Statistics for: rbox 50 W1e-20 D6 t1595644059 | qhull Qv Tv Qc Number of points processed: 50 Number of hyperplanes created: 5952 Number of distance tests for qhull: 8579 Number of distance tests for merging: 3400138 Number of distance tests for checking: 21120 Number of merged facets: 3 CPU seconds to compute hull (after input): 0.056 QH7076 qhull input warning: exact merge ('Qx'). Verify may report that a point is outside of a facet. See qh-optq.htm#Qx Output completed. Verifying that all points are below outer planes of all facets. Will make 103350 distance computations. rbox 10000 D4 t | qhull QR0 Qc C-0.01 A0.3 Tv Convex hull of 10000 points in 4-d: Number of vertices: 16 Number of coplanar points: 8483 Number of facets: 8 Number of non-simplicial facets: 8 Statistics for: rbox 10000 D4 t1595644059 | qhull QR0 Qc C-0.01 A0.3 Tv QR1595644060 Number of points processed: 43 Number of hyperplanes created: 282 Number of distance tests for qhull: 1406709 Number of distance tests for merging: 18069 Number of distance tests for checking: 89655 Number of merged facets: 291 CPU seconds to compute hull (after input): 0.032 Maximum distance of point above facet: 0.053 Maximum distance of vertex below facet: -0.18 (0.1x) Output completed. Verifying that all points are below outer planes of all facets. Will make 80000 distance computations. rbox 1000 D2 t | qhull d QR0 Qc C-1e-8 Qu Tv Furthest-site Delaunay triangulation by the convex hull of 1000 points in 3-d: Number of input sites: 1000 Number of Delaunay regions: 16 Statistics for: rbox 1000 D2 t1595644060 | qhull d QR0 Qc C-1e-8 Qu Tv QR1595644060 Number of points processed: 1000 Number of hyperplanes created: 5585 Number of facets in hull: 1996 Number of distance tests for qhull: 30012 CPU seconds to compute hull (after input): 0.004 Output completed. Verifying that all points are below outer planes of all facets. Will make 16000 distance computations. rbox 300 D5 t |qhull A-0.999 Qx Qc Tcv Convex hull of 300 points in 5-d: Number of vertices: 160 Number of coplanar points: 23 Number of facets: 1756 Number of non-simplicial facets: 471 Statistics for: rbox 300 D5 t1595644060 | qhull A-0.999 Qx Qc Tcv Number of points processed: 188 Number of hyperplanes created: 11314 Number of distance tests for qhull: 145495 Number of distance tests for merging: 59109 Number of distance tests for checking: 31214 Number of merged facets: 1190 CPU seconds to compute hull (after input): 0.027 Maximum distance of vertex below facet: -0.018 (0.2x) QH7076 qhull input warning: exact merge ('Qx'). Verify may report that a point is outside of a facet. See qh-optq.htm#Qx Output completed. Verifying that all points are below outer planes of all facets. Will make 526800 distance computations. rbox 100 D6 t |qhull A-0.9999 Qx Qc Tcv Convex hull of 100 points in 6-d: Number of vertices: 87 Number of facets: 3852 Number of non-simplicial facets: 249 Statistics for: rbox 100 D6 t1595644060 | qhull A-0.9999 Qx Qc Tcv Number of points processed: 95 Number of hyperplanes created: 15426 Number of distance tests for qhull: 36579 Number of distance tests for merging: 63310 Number of distance tests for checking: 65746 Number of merged facets: 597 CPU seconds to compute hull (after input): 0.03 Maximum distance of vertex below facet: -0.0061 (0.2x) QH7076 qhull input warning: exact merge ('Qx'). Verify may report that a point is outside of a facet. See qh-optq.htm#Qx Output completed. Verifying that all points are below outer planes of all facets. Will make 385200 distance computations. rbox 50 D7 t |qhull A-0.99999 Qx Qc Tcv W0.1 Convex hull of 50 points in 7-d: Number of vertices: 47 Number of coplanar points: 3 Number of facets: 5092 Number of non-simplicial facets: 84 Statistics for: rbox 50 D7 t1595644060 | qhull A-0.99999 Qx Qc Tcv W0.1 Number of points processed: 47 Number of hyperplanes created: 15267 Number of distance tests for qhull: 21958 Number of distance tests for merging: 67744 Number of distance tests for checking: 146550 Number of merged facets: 238 CPU seconds to compute hull (after input): 0.033 Maximum distance of point above facet: 0.081 Maximum distance of vertex below facet: -0.0017 (0.1x) QH7076 qhull input warning: exact merge ('Qx'). Verify may report that a point is outside of a facet. See qh-optq.htm#Qx Output completed. Verifying that all points are below outer planes of all facets. Will make 254600 distance computations. set +v ======================================================= === The following commands may cause errors Fri, Jul 24, 2020 10:27:40 PM ======================================================= === check bad cases for Qhull Fri, Jul 24, 2020 10:27:40 PM rbox 1000 L100000 s G1e-6 t | qhull Tv QH7089 qhull precision warning: The initial hull is narrow. Is the input lower dimensional (e.g., a square in 3-d instead of a cube)? Cosine of the minimum angle is 1.0000000000000000. If so, Qhull may produce a wide facet. Options 'Qs' (search all points), 'Qbb' (scale last coordinate), or 'QbB' (scale to unit box) may remove this warning. See 'Limitations' in qh-impre.htm. Use 'Pp' to skip this warning. Convex hull of 1000 points in 3-d: Number of vertices: 994 Number of facets: 1523 Number of non-simplicial facets: 6 Statistics for: rbox 1000 L100000 s G1e-6 t1595644060 | qhull Tv Number of points processed: 994 Number of hyperplanes created: 3610 Number of distance tests for qhull: 30049 Number of distance tests for merging: 128506 Number of distance tests for checking: 116631 Number of merged facets: 461 CPU seconds to compute hull (after input): 0.009 Maximum distance of point above facet: 2.1e-15 (0.4x) Maximum distance of vertex below facet: -4.7e-15 (0.8x) Output completed. Verifying that all points are below outer planes of all facets. Will make 1523000 distance computations. rbox 1000 L100000 s G1e-6 t | qhull Tv Q10 Convex hull of 1000 points in 3-d: Number of vertices: 994 Number of facets: 1523 Number of non-simplicial facets: 6 Statistics for: rbox 1000 L100000 s G1e-6 t1595644060 | qhull Tv Q10 Number of points processed: 994 Number of hyperplanes created: 3610 Number of distance tests for qhull: 30053 Number of distance tests for merging: 128506 Number of distance tests for checking: 116638 Number of merged facets: 461 CPU seconds to compute hull (after input): 0.008 Maximum distance of point above facet: 2.1e-15 (0.4x) Maximum distance of vertex below facet: -4.7e-15 (0.8x) Output completed. Verifying that all points are below outer planes of all facets. Will make 1523000 distance computations. rbox 1000 s Z1 G1e-13 t | qhull Tv Convex hull of 1001 points in 3-d: Number of vertices: 1001 Number of facets: 1489 Number of non-simplicial facets: 134 Statistics for: rbox 1000 s Z1 G1e-13 t1595644060 | qhull Tv Number of points processed: 1001 Number of hyperplanes created: 5159 Number of distance tests for qhull: 32536 Number of distance tests for merging: 139652 Number of distance tests for checking: 306125 Number of merged facets: 2330 CPU seconds to compute hull (after input): 0.016 Maximum distance of point above facet: 1.2e-14 (2.1x) Maximum distance of vertex below facet: -1.8e-14 (3.2x) Output completed. Verifying that all points are below outer planes of all facets. Will make 1490489 distance computations. rbox 1000 s W1e-13 P0 t | qhull d Qbb Qc Q12 Tv Delaunay triangulation by the convex hull of 1001 points in 4-d: Number of input sites: 1001 Number of Delaunay regions: 1996 Statistics for: rbox 1000 s W1e-13 P0 t1595644060 | qhull d Qbb Qc Q12 Tv Number of points processed: 1001 Number of hyperplanes created: 12921 Number of facets in hull: 3711 Number of distance tests for qhull: 56202 Number of distance tests for merging: 330422 Number of distance tests for checking: 310646 Number of merged facets: 3733 CPU seconds to compute hull (after input): 0.033 Maximum distance of point above facet: 1.8e-14 (1.8x) Maximum distance of vertex below facet: -3.5e-14 (3.5x) Output completed. Verifying that all points are below outer planes of all facets. Will make 1997996 distance computations. rbox 1000 s W1e-13 t | qhull d Q12 Tv QH7089 qhull precision warning: The initial hull is narrow. Is the input lower dimensional (e.g., a square in 3-d instead of a cube)? Cosine of the minimum angle is 1.0000000000000000. If so, Qhull may produce a wide facet. Options 'Qs' (search all points), 'Qbb' (scale last coordinate), or 'QbB' (scale to unit box) may remove this warning. See 'Limitations' in qh-impre.htm. Use 'Pp' to skip this warning. QH6170 qhull topology error (qh_partitionvisible): all new facets deleted as degenerate facets. Can not continue. While executing: rbox 1000 s W1e-13 t1595644060 | qhull d Q12 Tv Options selected for Qhull 2020.2.r 2020/07/24: run-id 213932684 delaunay Q12-allow-wide Tverify _pre-merge _zero-centrum Pgood _max-width 1 Error-roundoff 1e-15 _one-merge 9.1e-15 _near-inside 4.5e-14 Visible-distance 6e-15 U-max-coplanar 6e-15 Width-outside 1.2e-14 _wide-facet 3.6e-14 _narrow-hull 0 _maxoutside 6.4e-13 Last point added to hull was p716. Last merge was #2225. At error exit: Delaunay triangulation by the convex hull of 1000 points in 4-d: Number of input sites: 53 Total number of deleted points due to merging: 184 Total number of nearly incident points: 763 Number of Delaunay regions: 31 Number of non-simplicial Delaunay regions: 11 Statistics for: rbox 1000 s W1e-13 t1595644060 | qhull d Q12 Tv Number of points processed: 243 Number of hyperplanes created: 2811 Number of facets in hull: 72 Number of distance tests for qhull: 995247 Number of distance tests for merging: 231583 Number of distance tests for checking: 0 Number of merged facets: 2301 Maximum distance of point above facet: 6.4e-13 (63.5x) Maximum distance of vertex below facet: -1.6e-12 (158.2x) precision problems (corrected unless 'Q0' or an error) 235 flipped facets 394 coplanar horizon facets for new vertices 11 coplanar points during partitioning 6 dupridges with flip facet into good neighbor 1 dupridges with flip facet into good flip neighbor A Qhull topology error has occurred. Qhull did not recover from facet merges and vertex merges. This usually occurs when the input is nearly degenerate and substantial merging has occurred. See http://www.qhull.org/html/qh-impre.htm#limit rbox 1000 s W1e-13 t D2 | qhull d Tv QH7089 qhull precision warning: The initial hull is narrow. Is the input lower dimensional (e.g., a square in 3-d instead of a cube)? Cosine of the minimum angle is 1.0000000000000000. If so, Qhull may produce a wide facet. Options 'Qs' (search all points), 'Qbb' (scale last coordinate), or 'QbB' (scale to unit box) may remove this warning. See 'Limitations' in qh-impre.htm. Use 'Pp' to skip this warning. QH7086 Qhull precision warning: repartition coplanar point p440 from f817 as an outside point above hidden facet f817 dist 2.8e-13 nearest vertices 0.00052 Delaunay triangulation by the convex hull of 1000 points in 3-d: Number of input sites: 977 Total number of deleted points due to merging: 13 Total number of nearly incident points: 10 Number of Delaunay regions: 718 Number of non-simplicial Delaunay regions: 130 Statistics for: rbox 1000 s W1e-13 D2 t1595644060 | qhull d Tv Number of points processed: 990 Number of hyperplanes created: 3949 Number of facets in hull: 1457 Number of distance tests for qhull: 48902 Number of distance tests for merging: 41502 Number of distance tests for checking: 74612 Number of merged facets: 882 CPU seconds to compute hull (after input): 0.007 Maximum distance of point above facet: 7.5e-14 (13.5x) Maximum distance of vertex below facet: -9.7e-15 (1.7x) Output completed. Verifying that all points are below outer planes of all facets. Will make 718000 distance computations. set +v === check Qhull without merging Q0 Fri, Jul 24, 2020 10:27:40 PM rbox c D7 | qhull Q0 Tcv Convex hull of 128 points in 7-d: Number of vertices: 128 Number of facets: 8666 Statistics for: rbox c D7 | qhull Q0 Tcv Number of points processed: 128 Number of hyperplanes created: 12287 Number of distance tests for qhull: 26353 CPU seconds to compute hull (after input): 0.016 precision problems (corrected unless 'Q0' or an error) 41888 coplanar half ridges in output 10185 coplanar horizon facets for new vertices 8389 nearly singular or axis-parallel hyperplanes 8389 zero divisors during back substitute 11903 zero divisors during gaussian elimination qhull output completed. Verifying that 128 points are below 6.6e-15 of the nearest facet. rbox 100 s D3 | qhull Q0 E1e-3 Tc Po QH6115 qhull precision error: f100 is concave to f247, since p44(v13) is 0.002232 above f247 QH6115 qhull precision error: f139 is concave to f274, since p90(v32) is 0.007128 above f274 QH6115 qhull precision error: f163 is concave to f232, since p5(v6) is 0.001226 above f232 QH6115 qhull precision error: f293 is concave to f389, since p11(v61) is 0.002161 above f389 QH6115 qhull precision error: f307 is concave to f459, since p75(v21) is 0.01537 above f459 Convex hull of 100 points in 3-d: Number of vertices: 100 Number of facets: 196 Statistics for: rbox 100 s D3 | qhull Q0 E1e-3 Tc Po Number of points processed: 100 Number of hyperplanes created: 508 Number of distance tests for qhull: 1727 CPU seconds to compute hull (after input): 0.001 precision problems (corrected unless 'Q0' or an error) 16 coplanar half ridges in output 5 concave half ridges in output 18 coplanar horizon facets for new vertices rbox 100 s D3 | qhull Q0 E1e-2 Tc Po QH6115 qhull precision error: f123 is concave to f235, since p85(v8) is 0.06092 above f235 QH6115 qhull precision error: f177 is concave to f272, since p98(v20) is 0.03571 above f272 QH6115 qhull precision error: f246 is concave to f252, since p7(v57) is 0.02104 above f252 QH6115 qhull precision error: f261 is concave to f305, since p82(v60) is 0.01847 above f305 QH6115 qhull precision error: f266 is concave to f317, since p82(v60) is 0.02592 above f317 Convex hull of 100 points in 3-d: Number of vertices: 72 Number of facets: 140 Statistics for: rbox 100 s D3 | qhull Q0 E1e-2 Tc Po Number of points processed: 72 Number of hyperplanes created: 321 Number of distance tests for qhull: 1664 CPU seconds to compute hull (after input): 0.001 precision problems (corrected unless 'Q0' or an error) 52 coplanar half ridges in output 5 concave half ridges in output 54 coplanar horizon facets for new vertices 27 coplanar points during partitioning rbox 100 s D3 | qhull Q0 E1e-1 Tc Po Convex hull of 100 points in 3-d: Number of vertices: 10 Number of facets: 16 Statistics for: rbox 100 s D3 | qhull Q0 E1e-1 Tc Po Number of points processed: 10 Number of hyperplanes created: 27 Number of distance tests for qhull: 917 CPU seconds to compute hull (after input): 0 precision problems (corrected unless 'Q0' or an error) 3 coplanar half ridges in output 3 coplanar horizon facets for new vertices 59 coplanar points during partitioning rbox 100 s D3 | qhull Q0 R1e-3 Tc Po QH6115 qhull precision error: f94 is concave to f270, since p44(v13) is 0.003303 above f270 QH6115 qhull precision error: f157 is concave to f255, since p5(v6) is 0.005886 above f255 QH6115 qhull precision error: f289 is concave to f386, since p30(v62) is 0.000726 above f386 QH6115 qhull precision error: f381 is concave to f293, since p56(v79) is 0.0006018 above f293 Convex hull of 100 points in 3-d: Number of vertices: 100 Number of facets: 196 Statistics for: rbox 100 s D3 | qhull Q0 R1e-3 Tc Po Number of points processed: 100 Number of hyperplanes created: 498 Number of distance tests for qhull: 1643 CPU seconds to compute hull (after input): 0.002 precision problems (corrected unless 'Q0' or an error) 10 coplanar half ridges in output 4 concave half ridges in output 10 coplanar horizon facets for new vertices rbox 100 s D3 | qhull Q0 R1e-2 Tc Po QH6115 qhull precision error: f78 is concave to f147, since p57(v1) is 0.01085 above f147 QH6115 qhull precision error: f89 is concave to f194, since p17(v2) is 0.0111 above f194 QH6115 qhull precision error: f106 is concave to f122, since p74(v27) is 0.01501 above f122 QH6115 qhull precision error: f122 is concave to f106, since p95(v30) is 0.00822 above f106 QH6115 qhull precision error: f126 is concave to f213, since p95(v30) is 0.007437 above f213 QH6115 qhull precision error: f141 is concave to f288, since p81(v34) is 0.007157 above f288 QH6115 qhull precision error: f147 is concave to f227, since p90(v19) is 0.1078 above f227 QH6115 qhull precision error: f161 is concave to f252, since p20(v24) is 0.008976 above f252 QH6115 qhull precision error: f176 is concave to f277, since p38(v22) is 0.008285 above f277 QH6115 qhull precision error: f181 is concave to f276, since p73(v12) is 0.02209 above f276 QH6115 qhull precision error: f186 is concave to f291, since p85(v8) is 0.04316 above f291 QH6115 qhull precision error: f194 is concave to f89, since p82(v45) is 0.009743 above f89 QH6115 qhull precision error: f198 is concave to f273, since p82(v45) is 0.01834 above f273 QH6115 qhull precision error: f213 is concave to f126, since p93(v48) is 0.01071 above f126 QH6115 qhull precision error: f227 is concave to f147, since p37(v51) is 0.007006 above f147 QH6115 qhull precision error: f273 is concave to f198, since p29(v60) is 0.006128 above f198 QH6115 qhull precision error: f288 is concave to f141, since p96(v63) is 0.005493 above f141 QH6115 qhull precision error: f291 is concave to f186, since p34(v64) is 0.008643 above f186 QH6115 qhull precision error: f300 is concave to f355, since p30(v66) is 0.006345 above f355 QH6115 qhull precision error: f324 is concave to f384, since p75(v20) is 0.02388 above f384 QH6115 qhull precision error: f361 is concave to f406, since p41(v5) is 0.009438 above f406 QH6115 qhull precision error: f368 is concave to f367, since p11(v69) is 0.007227 above f367 QH6115 qhull precision error: f390 is concave to f391, since p99(v73) is 0.007279 above f391 QH6115 qhull precision error: f391 is concave to f390, since p43(v74) is 0.01052 above f390 Convex hull of 100 points in 3-d: Number of vertices: 88 Number of facets: 172 Statistics for: rbox 100 s D3 | qhull Q0 R1e-2 Tc Po Number of points processed: 88 Number of hyperplanes created: 413 Number of distance tests for qhull: 1702 CPU seconds to compute hull (after input): 0.001 precision problems (corrected unless 'Q0' or an error) 49 coplanar half ridges in output 24 concave half ridges in output 53 coplanar horizon facets for new vertices 12 coplanar points during partitioning rbox 100 s D3 | qhull Q0 R0.05 Tc QH6136 qhull precision error: facet f193 is flipped, distance= 0.391655882694 ERRONEOUS FACET: - f193 - flags: top simplicial flipped - normal: -0.2813 -0.9389 0.1981 - offset: 0.2910058 - vertices: p19(v46) p65(v35) p74(v28) - neighboring facets: f183 f194 f195 A flipped facet occurs when its distance to the interior point is greater than or equal to -0.024, the maximum roundoff error. While executing: rbox 100 s D3 | qhull Q0 R0.05 Tc Options selected for Qhull 2020.2.r 2020/07/24: run-id 213949491 Q0-no-premerge Random-perturb 0.05 Tcheck-frequently _max-width 0.94 Error-roundoff 0.024 Visible-distance 0.024 U-max-coplanar 0.024 Width-outside 0.048 _wide-facet 0.15 _maxoutside 0.19 Last point added to hull was p19. Qhull has finished constructing the hull. At error exit: Convex hull of 100 points in 3-d: Number of vertices: 46 Number of facets: 88 Statistics for: rbox 100 s D3 | qhull Q0 R0.05 Tc Number of points processed: 46 Number of hyperplanes created: 196 Number of distance tests for qhull: 2023 CPU seconds to compute hull (after input): 0 precision problems (corrected unless 'Q0' or an error) 1 flipped facets 34 coplanar horizon facets for new vertices 51 coplanar points during partitioning Precision problems were detected during construction of the convex hull. This occurs because convex hull algorithms assume that calculations are exact, but floating-point arithmetic has roundoff errors. To correct for precision problems, do not use 'Q0'. By default, Qhull selects 'C-0' or 'Qx' and merges non-convex facets. With option 'QJ', Qhull joggles the input to prevent precision problems. See "Imprecision in Qhull" (qh-impre.htm). If you use 'Q0', the output may include coplanar ridges, concave ridges, and flipped facets. In 4-d and higher, Qhull may produce a ridge with four neighbors or two facets with the same vertices. Qhull reports these events when they occur. It stops when a concave ridge, flipped facet, or duplicate facet occurs. If you need triangular output: - use option 'Qt' to triangulate the output - use option 'QJ' to joggle the input points and remove precision errors - use option 'Ft'. It triangulates non-simplicial facets with added points. If you must use 'Q0', try one or more of the following options. They can not guarantee an output. - use 'QbB' to scale the input to a cube. - use 'Po' to produce output and prevent partitioning for flipped facets - use 'V0' to set min. distance to visible facet as 0 instead of roundoff - use 'En' to specify a maximum roundoff error less than 0.024. - options 'Qf', 'Qbb', and 'QR0' may also help To guarantee simplicial output: - use option 'Qt' to triangulate the output - use option 'QJ' to joggle the input points and remove precision errors - use option 'Ft' to triangulate the output by adding points - use exact arithmetic (see "Imprecision in Qhull", qh-impre.htm) rbox 100 s D3 | qhull Q0 R0.05 Tc Po QH6136 qhull precision error: facet f193 is flipped, distance= 0.391655882694 QH6115 qhull precision error: f119 is concave to f134, since p31(v31) is 0.05178 above f134 QH6115 qhull precision error: f124 is concave to f131, since p5(v6) is 0.1065 above f131 QH6115 qhull precision error: f147 is concave to f91, since p69(v36) is 0.0354 above f91 QH6113 qhull precision error: f193 is flipped (interior point is outside) Convex hull of 100 points in 3-d: Number of vertices: 46 Number of facets: 88 Statistics for: rbox 100 s D3 | qhull Q0 R0.05 Tc Po Number of points processed: 46 Number of hyperplanes created: 196 Number of distance tests for qhull: 2023 CPU seconds to compute hull (after input): 0 precision problems (corrected unless 'Q0' or an error) 35 coplanar half ridges in output 3 concave half ridges in output 1 flipped facets 34 coplanar horizon facets for new vertices 51 coplanar points during partitioning rbox 1000 W1e-7 | qhull Q0 Tc Po Convex hull of 1000 points in 3-d: Number of vertices: 164 Number of facets: 324 Statistics for: rbox 1000 W1e-7 | qhull Q0 Tc Po Number of points processed: 221 Number of hyperplanes created: 1160 Number of distance tests for qhull: 22590 CPU seconds to compute hull (after input): 0.006 rbox 50 s | qhull Q0 V0.05 W0.01 Tc Po QH7088 Qhull precision warning: in post-processing (qh_check_maxout) p0 for f36 is 0.061 above hidden facet f70 nearest vertices 0.15 QH7088 Qhull precision warning: in post-processing (qh_check_maxout) p8 for f38 is 0.26 above hidden facet f145 nearest vertices 0.14 QH6297 Qhull precision error (qh_check_maxout): large increase in qh.max_outside during post-processing dist 0.26 (46669910714866.6x). See warning QH0032/QH0033. Allow with 'Q12' (allow-wide) and 'Pp' ERRONEOUS FACET: - f145 - flags: top simplicial - normal: -0.6276 0.1677 -0.7602 - offset: -0.2196772 - maxoutside: 0.2588526 - vertices: p2(v43) p0(v13) p24(v6) - neighboring facets: f39 f146 f147 ERRONEOUS and NEIGHBORING FACETS to output While executing: rbox 50 s | qhull Q0 V0.05 W0.01 Tc Po Options selected for Qhull 2020.2.r 2020/07/24: run-id 213949491 Q0-no-premerge Visible 0.05 W-outside 0.01 Tcheck-frequently Poutput-forced _max-width 0.98 Error-roundoff 6.9e-16 _near-inside 2.4e-14 U-max-coplanar 0.05 _wide-facet 0.3 _maxoutside 0.01 Last point added to hull was p10. At error exit: Convex hull of 50 points in 3-d: Number of vertices: 50 Number of facets: 96 Statistics for: rbox 50 s | qhull Q0 V0.05 W0.01 Tc Po Number of points processed: 50 Number of hyperplanes created: 171 Number of distance tests for qhull: 538 precision problems (corrected unless 'Q0' or an error) 7 flipped facets 82 coplanar horizon facets for new vertices Precision problems were detected during construction of the convex hull. This occurs because convex hull algorithms assume that calculations are exact, but floating-point arithmetic has roundoff errors. To correct for precision problems, do not use 'Q0'. By default, Qhull selects 'C-0' or 'Qx' and merges non-convex facets. With option 'QJ', Qhull joggles the input to prevent precision problems. See "Imprecision in Qhull" (qh-impre.htm). If you use 'Q0', the output may include coplanar ridges, concave ridges, and flipped facets. In 4-d and higher, Qhull may produce a ridge with four neighbors or two facets with the same vertices. Qhull reports these events when they occur. It stops when a concave ridge, flipped facet, or duplicate facet occurs. If you need triangular output: - use option 'Qt' to triangulate the output - use option 'QJ' to joggle the input points and remove precision errors - use option 'Ft'. It triangulates non-simplicial facets with added points. If you must use 'Q0', try one or more of the following options. They can not guarantee an output. - use 'QbB' to scale the input to a cube. - use 'Po' to produce output and prevent partitioning for flipped facets - use 'V0' to set min. distance to visible facet as 0 instead of roundoff - use 'En' to specify a maximum roundoff error less than 6.9e-16. - options 'Qf', 'Qbb', and 'QR0' may also help To guarantee simplicial output: - use option 'Qt' to triangulate the output - use option 'QJ' to joggle the input points and remove precision errors - use option 'Ft' to triangulate the output by adding points - use exact arithmetic (see "Imprecision in Qhull", qh-impre.htm) rbox 100 s D5 | qhull Q0 R1e-2 Tc Po QH6107 qhull topology error: facets f721, f756 and f722 meet at a ridge with more than 2 neighbors. Can not continue due to no qh.PREmerge and no 'Qx' (MERGEexact) ERRONEOUS FACET: - f721 - flags: bottom simplicial newfacet - offset: 0 - vertices: p84(v29) p2(v19) p58(v12) p3(v7) p9(v2) - neighboring facets: f362 f720 f728 f722 f740 ERRONEOUS OTHER FACET: - f756 - flags: top simplicial newfacet - offset: 0 - vertices: p84(v29) p40(v26) p2(v19) p58(v12) p9(v2) - neighboring facets: f566 ERRONEOUS and NEIGHBORING FACETS to output While executing: rbox 100 s D5 | qhull Q0 R1e-2 Tc Po Options selected for Qhull 2020.2.r 2020/07/24: run-id 213949491 Q0-no-premerge Random-perturb 0.01 Tcheck-frequently Poutput-forced _max-width 0.88 Error-roundoff 0.0045 Visible-distance 0.0045 U-max-coplanar 0.0045 Width-outside 0.009 _wide-facet 0.027 _maxoutside 0.054 Last point added to hull was p84. Convex hull of 100 points in 5-d: Number of vertices: 29 Number of facets: 340 Statistics for: rbox 100 s D5 | qhull Q0 R1e-2 Tc Po Number of points processed: 28 Number of hyperplanes created: 720 Number of distance tests for qhull: 2275 precision problems (corrected unless 'Q0' or an error) 1 flipped facets 24 coplanar horizon facets for new vertices Precision problems were detected during construction of the convex hull. This occurs because convex hull algorithms assume that calculations are exact, but floating-point arithmetic has roundoff errors. To correct for precision problems, do not use 'Q0'. By default, Qhull selects 'C-0' or 'Qx' and merges non-convex facets. With option 'QJ', Qhull joggles the input to prevent precision problems. See "Imprecision in Qhull" (qh-impre.htm). If you use 'Q0', the output may include coplanar ridges, concave ridges, and flipped facets. In 4-d and higher, Qhull may produce a ridge with four neighbors or two facets with the same vertices. Qhull reports these events when they occur. It stops when a concave ridge, flipped facet, or duplicate facet occurs. If you need triangular output: - use option 'Qt' to triangulate the output - use option 'QJ' to joggle the input points and remove precision errors - use option 'Ft'. It triangulates non-simplicial facets with added points. If you must use 'Q0', try one or more of the following options. They can not guarantee an output. - use 'QbB' to scale the input to a cube. - use 'Po' to produce output and prevent partitioning for flipped facets - use 'V0' to set min. distance to visible facet as 0 instead of roundoff - use 'En' to specify a maximum roundoff error less than 0.0045. - options 'Qf', 'Qbb', and 'QR0' may also help To guarantee simplicial output: - use option 'Qt' to triangulate the output - use option 'QJ' to joggle the input points and remove precision errors - use option 'Ft' to triangulate the output by adding points - use exact arithmetic (see "Imprecision in Qhull", qh-impre.htm) set +v === check nearly incident points Fri, Jul 24, 2020 10:27:41 PM rbox L100 2000 D4 s C1,1e-13 t2 | qhull Convex hull of 4000 points in 4-d: Number of vertices: 2096 Number of facets: 13614 Number of non-simplicial facets: 52 Statistics for: rbox L100 2000 D4 s C1,1e-13 t2 | qhull Number of points processed: 2111 Number of hyperplanes created: 51581 Number of distance tests for qhull: 585497 Number of distance tests for merging: 267217 Number of distance tests for checking: 152193 Number of merged facets: 129 CPU seconds to compute hull (after input): 0.056 Maximum distance of point above facet: 1.8e-14 (1.9x) Maximum distance of vertex below facet: -8.9e-15 (0.9x) rbox L100 2000 D4 s C1,1e-13 t2 | qhull Q12 Convex hull of 4000 points in 4-d: Number of vertices: 2096 Number of facets: 13614 Number of non-simplicial facets: 52 Statistics for: rbox L100 2000 D4 s C1,1e-13 t2 | qhull Q12 Number of points processed: 2111 Number of hyperplanes created: 51581 Number of distance tests for qhull: 585497 Number of distance tests for merging: 267217 Number of distance tests for checking: 152193 Number of merged facets: 129 CPU seconds to compute hull (after input): 0.056 Maximum distance of point above facet: 1.8e-14 (1.9x) Maximum distance of vertex below facet: -8.9e-15 (0.9x) rbox 50 C1,1E-13 t1447644703 | qhull d QH6271 qhull topology error (qh_check_dupridge): wide merge (1125070907263.1x wider) due to dupridge between f1143 and f1169 (vertex dist 6.5e-14), merge dist 0.015, while processing p54 - Allow error with option 'Q12' - Experimental option merge-pinched-vertices ('Q14') may avoid this error. It merges nearly adjacent vertices. - A bounding box for the input sites may alleviate this error. ERRONEOUS FACET: - f1143 - flags: bottom upperDelaunay newfacet dupridge mergeridge2 flipped - normal: 0.2935 0.3842 0.4668 0.7405 - offset: 0.05514914 - vertices: p54(v76) p45(v56) p76(v36) p44(v19) - neighboring facets: f405 f1159 f1169 f1144 - ridges: - r576 tested simplicialbot vertices: p45(v56) p76(v36) p44(v19) between f405 and f1143 - r1072 simplicialtop simplicialbot vertices: p54(v76) p76(v36) p44(v19) between f1143 and f1159 - r1073 simplicialbot vertices: p54(v76) p45(v56) p44(v19) between f1169 and f1143 - r1074 simplicialtop simplicialbot vertices: p54(v76) p45(v56) p76(v36) between f1143 and f1144 ERRONEOUS OTHER FACET: - f1169 - flags: bottom upperDelaunay newfacet dupridge mergeridge1 flipped - normal: -0.3214 0.1166 0.5495 0.7623 - offset: 0.114967 - vertices: p54(v76) p45(v56) p44(v19) p92(v11) - neighboring facets: f405 f1159 f1170 f1143 - ridges: - r561 tested simplicialbot vertices: p45(v56) p44(v19) p92(v11) between f405 and f1169 - r1070 simplicialtop simplicialbot vertices: p54(v76) p44(v19) p92(v11) between f1169 and f1159 - r1071 simplicialtop simplicialbot vertices: p54(v76) p45(v56) p92(v11) between f1170 and f1169 - r1073 simplicialbot vertices: p54(v76) p45(v56) p44(v19) between f1169 and f1143 While executing: rbox 50 C1,1E-13 t1447644703 | qhull d Options selected for Qhull 2020.2.r 2020/07/24: run-id 213949491 delaunay _pre-merge _zero-centrum Pgood _max-width 0.94 Error-roundoff 1e-15 _one-merge 9.2e-15 _near-inside 4.6e-14 Visible-distance 6.1e-15 U-max-coplanar 6.1e-15 Width-outside 1.2e-14 _wide-facet 3.7e-14 _maxoutside 1.2e-14 Last point added to hull was p54. Last merge was #247. At error exit: Delaunay triangulation by the convex hull of 100 points in 4-d: Number of input sites: 76 Number of nearly incident points: 1 Number of Delaunay regions: 266 Number of non-simplicial Delaunay regions: 73 Statistics for: rbox 50 C1,1E-13 t1447644703 | qhull d Number of points processed: 76 Number of hyperplanes created: 1087 Number of facets in hull: 303 Number of distance tests for qhull: 5296 Number of distance tests for merging: 10632 Number of distance tests for checking: 0 Number of merged facets: 249 Maximum distance of point above facet: 1.3e-14 (1.3x) Maximum distance of vertex below facet: -1.3e-14 (1.3x) precision problems (corrected unless 'Q0' or an error) 4 flipped facets 73 coplanar horizon facets for new vertices 1 coplanar points during partitioning 213 degenerate hyperplanes recomputed with gaussian elimination 17 nearly singular or axis-parallel hyperplanes 1 dupridges with multiple neighbors A wide merge error has occurred. Qhull has produced a wide facet due to facet merges and vertex merges. This usually occurs when the input is nearly degenerate and substantial merging has occurred. See http://www.qhull.org/html/qh-impre.htm#limit rbox 50 C1,1E-13 t1447644703 | qhull d Q12 QH6271 qhull topology error (qh_check_dupridge): wide merge (1125070907263.1x wider) due to dupridge between f1143 and f1169 (vertex dist 6.5e-14), merge dist 0.015, while processing p54 - Allow error with option 'Q12' - Experimental option merge-pinched-vertices ('Q14') may avoid this error. It merges nearly adjacent vertices. - A bounding box for the input sites may alleviate this error. Delaunay triangulation by the convex hull of 100 points in 4-d: Number of input sites: 99 Total number of nearly incident points: 1 Number of Delaunay regions: 307 Number of non-simplicial Delaunay regions: 133 Statistics for: rbox 50 C1,1E-13 t1447644703 | qhull d Q12 Number of points processed: 99 Number of hyperplanes created: 1504 Number of facets in hull: 345 Number of distance tests for qhull: 7670 Number of distance tests for merging: 18284 Number of distance tests for checking: 7318 Number of merged facets: 456 CPU seconds to compute hull (after input): 0.003 Maximum distance of point above facet: 1.3e-14 (1.3x) Maximum distance of vertex below facet: -0.0012 (119810840063.5x) rbox 50 C1,1E-13 t1447644703 | qhull d Q14 Delaunay triangulation by the convex hull of 100 points in 4-d: Number of input sites: 99 Total number of nearly incident points: 1 Number of Delaunay regions: 312 Number of non-simplicial Delaunay regions: 137 Statistics for: rbox 50 C1,1E-13 t1447644703 | qhull d Q14 Number of points processed: 99 Number of hyperplanes created: 1487 Number of facets in hull: 350 Number of distance tests for qhull: 5360 Number of distance tests for merging: 17768 Number of distance tests for checking: 4953 Number of merged facets: 513 CPU seconds to compute hull (after input): 0.003 Maximum distance of point above facet: 1.3e-14 (1.3x) Maximum distance of vertex below facet: -1.4e-14 (1.4x) set +v ======================================================= === Testing done. Print documentation ======================================================= qhull - qhull -- compute convex hulls and related structures. http://www.qhull.org 2020.2.r 2020/07/24 input (stdin): first lines: dimension and number of points (or vice-versa). other lines: point coordinates, best if one point per line comments: start with a non-numeric character halfspaces: use dim plus one and put offset after coefficients. May be preceded by a single interior point ('H'). options: d - Delaunay triangulation by lifting points to a paraboloid d Qu - furthest-site Delaunay triangulation (upper convex hull) Hn,n,... - halfspace intersection about point [n,n,0,...] Qc - keep coplanar points with nearest facet Qi - keep interior points with nearest facet QJ - joggled input instead of merged facets Qt - triangulated output v - Voronoi diagram (dual of the Delaunay triangulation) v Qu - furthest-site Voronoi diagram Qhull control options: Qa - allow input with fewer or more points than coordinates Qbk:n - scale coord k so that low bound is n QBk:n - scale coord k so that upper bound is n (QBk is 0.5) QbB - scale input to unit cube centered at the origin Qbb - scale last coordinate to [0,m] for Delaunay triangulations Qbk:0Bk:0 - remove k-th coordinate from input QJn - randomly joggle input in range [-n,n] QRn - random rotation (n=seed, n=0 time, n=-1 time/no rotate) Qs - search all points for the initial simplex Qu - for 'd' or 'v', compute upper hull without point at-infinity returns furthest-site Delaunay triangulation QVn - good facet if it includes point n, -n if not Qx - exact pre-merges (skips coplanar and angle-coplanar facets) Qz - add point-at-infinity to Delaunay triangulation Qhull extra options: Qf - partition point to furthest outside facet Qg - only build good facets (needs 'QGn', 'QVn', or 'PdD') QGn - good facet if visible from point n, -n for not visible Qm - only process points that would increase max_outside Qr - process random outside points instead of furthest ones Qv - test vertex neighbors for convexity Qw - allow option warnings Q0 - turn off default premerge with 'C-0'/'Qx' Q1 - merge by mergetype/angle instead of mergetype/distance Q2 - merge all coplanar facets instead of merging independent sets Q3 - do not merge redundant vertices Q4 - avoid old->new merges Q5 - do not correct outer planes at end of qhull Q6 - do not pre-merge concave or coplanar facets Q7 - depth-first processing instead of breadth-first Q8 - do not process near-inside points Q9 - process furthest of furthest points Q10 - no special processing for narrow distributions Q11 - copy normals and recompute centrums for tricoplanar facets Q12 - allow wide facets and wide dupridge Q14 - merge pinched vertices that create a dupridge Q15 - check for duplicate ridges with the same vertices T options: TFn - report summary when n or more facets created TI file - input file, may be enclosed in single quotes TO file - output file, may be enclosed in single quotes Ts - statistics Tv - verify result: structure, convexity, and point inclusion Tz - send all output to stdout Trace options: T4 - trace at level n, 4=all, 5=mem/gauss, -1= events Ta - annotate output with message codes TAn - stop qhull after adding n vertices TCn - stop qhull after building cone for point n TVn - stop qhull after adding point n, -n for before Tc - check frequently during execution Tf - flush each qh_fprintf for debugging segfaults TPn - turn on tracing when point n added to hull TP-1 turn on tracing after qh_buildhull and qh_postmerge TMn - turn on tracing at merge n TWn - trace merge facets when width > n TRn - rerun qhull n times for statistics to adjust 'QJn' Precision options: Cn - radius of centrum (roundoff added). Merge facets if non-convex An - cosine of maximum angle. Merge facets if cosine > n or non-convex C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge En - max roundoff error for distance computation Rn - randomly perturb computations by a factor of [1-n,1+n] Vn - min distance above plane for a visible facet (default 3C-n or En) Un - max distance below plane for a new, coplanar point (default Vn) Wn - min facet width for outside point (before roundoff, default 2Vn) Output formats (may be combined; if none, produces a summary to stdout): f - facet dump G - Geomview output (see below) i - vertices incident to each facet m - Mathematica output (2-d and 3-d) n - normals with offsets o - OFF format (dim, points and facets; Voronoi regions) p - vertex coordinates or Voronoi vertices (coplanar points if 'Qc') s - summary (stderr) More formats: Fa - area for each facet FA - compute total area and volume for option 's' Fc - count plus coplanar points for each facet use 'Qc' (default) for coplanar and 'Qi' for interior FC - centrum or Voronoi center for each facet Fd - use cdd format for input (homogeneous with offset first) FD - use cdd format for numeric output (offset first) FF - facet dump without ridges Fi - inner plane for each facet for 'v', separating hyperplanes for bounded Voronoi regions FI - ID of each facet Fm - merge count for each facet (511 max) FM - Maple output (2-d and 3-d) Fn - count plus neighboring facets for each facet FN - count plus neighboring facets for each point Fo - outer plane (or max_outside) for each facet for 'v', separating hyperplanes for unbounded Voronoi regions FO - options and precision constants Fp - dim, count, and intersection coordinates (halfspace only) FP - nearest vertex and distance for each coplanar point FQ - command used for qhull Fs - summary: #int (8), dimension, #points, tot vertices, tot facets, output: #vertices, #facets, #coplanars, #nonsimplicial #real (2), max outer plane, min vertex FS - sizes: #int (0) #real (2) tot area, tot volume Ft - triangulation with centrums for non-simplicial facets (OFF format) Fv - count plus vertices for each facet for 'v', Voronoi diagram as Voronoi vertices for pairs of sites FV - average of vertices (a feasible point for 'H') Fx - extreme points (in order for 2-d) Geomview output (2-d, 3-d, and 4-d; 2-d Voronoi) Ga - all points as dots Gp - coplanar points and vertices as radii Gv - vertices as spheres Gc - centrums GDn - drop dimension n in 3-d and 4-d output Gh - hyperplane intersections Gi - inner planes only Gn - no planes Go - outer planes only Gr - ridges Gt - for 3-d 'd', transparent outer ridges Print options: PAn - keep n largest facets by area Pdk:n - drop facet if normal[k] <= n (default 0.0) PDk:n - drop facet if normal[k] >= n PFn - keep facets whose area is at least n Pg - print good facets (needs 'QGn' or 'QVn') PG - print neighbors of good facets PMn - keep n facets with most merges Po - force output. If error, output neighborhood of facet Pp - do not report precision problems . - list of all options - - one line descriptions of all options -? - help with examples -V - version rbox rbox -- generate various point distributions. Default is random in cube. args (any order, space separated): Version: 2019/11/10 3000 number of random points in cube, lens, spiral, sphere or grid D3 dimension 3-d c add a unit cube to the output ('c G2.0' sets size) d add a unit diamond to the output ('d G2.0' sets size) l generate a regular 3-d spiral r generate a regular polygon, ('r s Z1 G0.1' makes a cone) s generate cospherical points x generate random points in simplex, may use 'r' or 'Wn' y same as 'x', plus simplex Cn,r,m add n nearly adjacent points within radius r of m points Pn,m,r add point [n,m,r] first, pads with 0, maybe repeated Ln lens distribution of radius n. Also 's', 'r', 'G', 'W'. Mn,m,r lattice(Mesh) rotated by [n,-m,0], [m,n,0], [0,0,r], ... '27 M1,0,1' is {0,1,2} x {0,1,2} x {0,1,2}. Try 'M3,4 z'. W0.1 random distribution within 0.1 of the cube's or sphere's surface Z0.5 s random points in a 0.5 disk projected to a sphere Z0.5 s G0.6 same as Z0.5 within a 0.6 gap Bn bounding box coordinates, default 0.5 h output as homogeneous coordinates for cdd n remove command line from the first line of output On offset coordinates by n t use time as the random number seed(default is command line) tn use n as the random number seed z print integer coordinates, default 'Bn' is 1e+06 cat html/qhull.txt html/rbox.txt qhull(1) qhull(1) NAME qhull - convex hull, Delaunay triangulation, Voronoi dia- gram, halfspace intersection about a point, hull volume, facet area SYNOPSIS qhull- compute convex hulls and related structures input (stdin): dimension, #points, point coordinates first comment (non-numeric) is listed in the summary halfspace: use dim plus one with offsets after coefficients options (qh-quick.htm): d - Delaunay triangulation by lifting points to a paraboloid d Qu - furthest-site Delaunay triangulation (upper convex hull) v - Voronoi diagram as the dual of the Delaunay triangulation v Qu - furthest-site Voronoi diagram H1,1 - Halfspace intersection about [1,1,0,...] via polar duality Qt - triangulated output QJ - joggled input instead of merged facets Tv - verify result: structure, convexity, and point inclusion . - concise list of all options - - one-line description of each option -? - this message -V - version Output options (subset): s - summary of results (default) i - vertices incident to each facet n - normals with offsets p - vertex coordinates (if 'Qc', includes coplanar points) if 'v', Voronoi vertices FA - report total area and volume Fp - halfspace intersections FS - total area and volume Fx - extreme points (convex hull vertices) G - Geomview output (2-d, 3-d and 4-d) m - Mathematica output (2-d and 3-d) o - OFF format (if 'v', outputs Voronoi regions) QVn - print facets that include point n, -n if not TI file - input file, may be enclosed in single quotes TO file - output file, may be enclosed in single quotes examples: rbox D4 | qhull Tv rbox 1000 s | qhull Tv s FA rbox 10 D2 | qhull d QJ s i TO result rbox 10 D2 | qhull v Qbb Qt p rbox 10 D2 | qhull d Qu QJ m rbox 10 D2 | qhull v Qu QJ o rbox c d D2 | qhull Qc s f Fx | more rbox c | qhull FV n | qhull H Fp rbox d D12 | qhull QR0 FA rbox c D7 | qhull FA TF1000 rbox y 1000 W0 | qhull Qc rbox c | qhull n - html manual: html/index.htm - installation: README.txt - see also: COPYING.txt, REGISTER.txt, Changes.txt - WWW: - GIT: - news: - Geomview: - news group: - FAQ: - email: qhull@qhull.org - bug reports: qhull_bug@qhull.org Geometry Center 2019/05/03 1 qhull(1) qhull(1) The sections are: - INTRODUCTION - DESCRIPTION, a description of Qhull - IMPRECISION, how Qhull handles imprecision - OPTIONS - Input and output options - Additional input/output formats - Precision options - Geomview options - Print options - Qhull options - Trace options - BUGS - E-MAIL - SEE ALSO - AUTHORS - ACKNOWLEGEMENTS This man page briefly describes all Qhull options. Please report any mismatches with Qhull's html manual (html/index.htm). INTRODUCTION Qhull is a general dimension code for computing convex hulls, Delaunay triangulations, Voronoi diagram, furthest- site Voronoi diagram, furthest-site Delaunay triangula- tions, and halfspace intersections about a point. It implements the Quickhull algorithm for computing the con- vex hull. Qhull handles round-off errors from floating point arithmetic. It can approximate a convex hull. The program includes options for hull volume, facet area, partial hulls, input transformations, randomization, trac- ing, multiple output formats, and execution statistics. The program can be called from within your application. You can view the results in 2-d, 3-d and 4-d with Geomview. DESCRIPTION The format of input is the following: first line contains the dimension, second line contains the number of input points, and point coordinates follow. The dimension and number of points can be reversed. Comments and line breaks are ignored. A comment starts with a non-numeric character and continues to the end of line. The first comment is reported in summaries and statistics. Error reporting is better if there is one point per line. The default printout option is a short summary. There are many other output formats. Geometry Center 2019/05/03 2 qhull(1) qhull(1) Qhull implements the Quickhull algorithm for convex hull. This algorithm combines the 2-d Quickhull algorithm with the n-d beneath-beyond algorithm [c.f., Preparata & Shamos '85]. It is similar to the randomized algorithms of Clarkson and others [Clarkson et al. '93]. The main advantages of Quickhull are output sensitive performance, reduced space requirements, and automatic handling of pre- cision problems. The data structure produced by Qhull consists of vertices, ridges, and facets. A vertex is a point of the input set. A ridge is a set of d vertices and two neighboring facets. For example in 3-d, a ridge is an edge of the polyhedron. A facet is a set of ridges, a set of neighboring facets, a set of incident vertices, and a hyperplane equation. For simplicial facets, the ridges are defined by the vertices and neighboring facets. When Qhull merges two facets, it produces a non-simplicial facet. A non-simplicial facet has more than d neighbors and may share more than one ridge with a neighbor. IMPRECISION Since Qhull uses floating point arithmetic, roundoff error may occur for each calculation. This causes problems for most geometric algorithms. Qhull automatically sets option 'C-0' in 2-d, 3-d, and 4-d, or option 'Qx' in 5-d and higher. These options han- dle precision problems by merging facets. Alternatively, use option 'QJ' to joggle the input. With 'C-0', Qhull merges non-convex facets while con- structing the hull. The remaining facets are clearly con- vex. With 'Qx', Qhull merges coplanar horizon facets, flipped facets, concave facets and duplicated ridges. It merges coplanar facets after constructing the hull. With 'Qx', coplanar points may be missed, but it appears to be unlikely. To guarantee triangular output, joggle the input with option 'QJ'. Facet merging will not occur. OPTIONS To get a list of the most important options, execute 'qhull -?'. To get a complete list of options, execute 'qhull -'. To get a complete, concise list of options, execute 'qhull .'. Options can be in any order. Capitalized options take an argument (except 'PG' and 'F' options). Single letters are used for output formats and precision constants. The other options are grouped into menus: output formats ('F'), Geomview output ('G'), printing ('P'), Qhull control ('Q'), Geometry Center 2019/05/03 3 qhull(1) qhull(1) and tracing ('T'). Main options: default Compute the convex hull of the input points. Report a summary of the result. d Compute the Delaunay triangulation by lifting the input points to a paraboloid. The 'o' option prints the input points and facets. The 'QJ' option guarantees triangular output. The 'Ft' option prints a triangulation. It adds points (the centrums) to non-simplicial facets. v Compute the Voronoi diagram from the Delaunay tri- angulation. The 'p' option prints the Voronoi ver- tices. The 'o' option prints the Voronoi vertices and the vertices in each Voronoi region. It lists regions in site id order. The 'Fv' option prints each ridge of the Voronoi diagram. The first or zero'th vertex indicates the infinity vertex. Its coordinates are qh_INFINITE (-10.101). It indi- cates unbounded Voronoi regions or degenerate Delaunay triangles. Hn,n,... Compute halfspace intersection about [n,n,0,...]. The input is a set of halfspaces defined in the same format as 'n', 'Fo', and 'Fi'. Use 'Fp' to print the intersection points. Use 'Fv' to list the intersection points for each halfspace. The other output formats display the dual convex hull. The point [n,n,n,...] is a feasible point for the halfspaces, i.e., a point that is inside all of the halfspaces (Hx+b <= 0). The default coordinate value is 0. The input may start with a feasible point. If so, use 'H' by itself. The input starts with a feasi- ble point when the first number is the dimension, the second number is "1", and the coordinates com- plete a line. The 'FV' option produces a feasible point for a convex hull. d Qu Compute the furthest-site Delaunay triangulation from the upper convex hull. The 'o' option prints the input points and facets. The 'QJ' option guar- antees triangular otuput. You can also use facets. v Qu Compute the furthest-site Voronoi diagram. The 'p' option prints the Voronoi vertices. The 'o' option prints the Voronoi vertices and the vertices in Geometry Center 2019/05/03 4 qhull(1) qhull(1) each Voronoi region. The 'Fv' option prints each ridge of the Voronoi diagram. The first or zero'th vertex indicates the infinity vertex at infinity. Its coordinates are qh_INFINITE (-10.101). It indicates unbounded Voronoi regions and degenerate Delaunay triangles. Qt Triangulated output. Input/Output options: f Print all facets and all fields of each facet. G Output the hull in Geomview format. For imprecise hulls, Geomview displays the inner and outer hull. Geomview can also display points, ridges, vertices, coplanar points, and facet intersections. See below for a list of options. For Delaunay triangulations, 'G' displays the cor- responding paraboloid. For halfspace intersection, 'G' displays the dual polytope. i Output the incident vertices for each facet. Qhull prints the number of facets followed by the ver- tices of each facet. One facet is printed per line. The numbers are the 0-relative indices of the corresponding input points. The facets are oriented. In 4-d and higher, Qhull triangulates non-simpli- cial facets. Each apex (the first vertex) is a created point that corresponds to the facet's cen- trum. Its index is greater than the indices of the input points. Each base corresponds to a simpli- cial ridge between two facets. To print the ver- tices without triangulation, use option 'Fv'. To print the centrum coordinates, use option 'Ft'. The centrum indices for option 'i' are one more than the centrum indices for option 'Ft'. m Output the hull in Mathematica format. Qhull writes a Mathematica file for 2-d and 3-d convex hulls and for 2-d Delaunay triangulations. Qhull produces a list of objects that you can assign to a variable in Mathematica, for example: "list= << ". If the object is 2-d, it can be visualized by "Show[Graphics[list]] ". For 3-d objects the command is "Show[Graphics3D[list]]". n Output the normal equation for each facet. Qhull prints the dimension (plus one), the number of facets, and the normals for each facet. The facet's offset follows its normal coefficients. o Output the facets in OFF file format. Qhull prints the dimension, number of points, number of facets, and number of ridges. Then it prints the Geometry Center 2019/05/03 5 qhull(1) qhull(1) coordinates of the input points and the vertices for each facet. Each facet is on a separate line. The first number is the number of vertices. The remainder are the indices of the corresponding points. The vertices are oriented in 2-d, 3-d, and in simplicial facets. For 2-d Voronoi diagrams, the vertices are sorted by adjacency, but not oriented. In 3-d and higher, the Voronoi vertices are sorted by index. See the 'v' option for more information. p Output the coordinates of each vertex point. Qhull prints the dimension, the number of points, and the coordinates for each vertex. With the 'Gc' and 'Gi' options, it also prints coplanar and interior points. For Voronoi diagrams, it prints the coor- dinates of each Voronoi vertex. s Print a summary to stderr. If no output options are specified, a summary goes to stdout. The summary lists the number of input points, the dimension, the number of vertices in the convex hull, the number of facets in the convex hull, the number of good facets (if 'Pg'), and statistics. The last two statistics (if needed) measure the maximum distance from a point or vertex to a facet. The number in parenthesis (e.g., 2.1x) is the ratio between the maximum distance and the worst-case distance due to merging two simplicial facets. Precision options An Maximum angle given as a cosine. If the angle between a pair of facet normals is greater than n, Qhull merges one of the facets into a neighbor. If 'n' is negative, Qhull tests angles after adding each point to the hull (pre-merging). If 'n' is posi- tive, Qhull tests angles after constructing the hull (post-merging). Both pre- and post-merging can be defined. Option 'C0' or 'C-0' is set if the corresponding 'Cn' or 'C-n' is not set. If 'Qx' is set, then 'A- n' and 'C-n' are checked after the hull is con- structed and before 'An' and 'Cn' are checked. Cn Centrum radius. If a centrum is less than n below a neighboring facet, Qhull merges one of the facets. If 'n' is negative or '-0', Qhull tests and merges facets after adding each point to the hull. This is called "pre-merging". If 'n' is Geometry Center 2019/05/03 6 qhull(1) qhull(1) positive, Qhull tests for convexity after con- structing the hull ("post-merging"). Both pre- and post-merging can be defined. For 5-d and higher, 'Qx' should be used instead of 'C-n'. Otherwise, most or all facets may be merged together. En Maximum roundoff error for distance computations. Rn Randomly perturb distance computations up to +/- n * max_coord. This option perturbs every distance, hyperplane, and angle computation. To use time as the random number seed, use option 'QR-1'. Vn Minimum distance for a facet to be visible. A facet is visible if the distance from the point to the facet is greater than 'Vn'. Without merging, the default value for 'Vn' is the round-off error ('En'). With merging, the default value is the pre-merge centrum ('C-n') in 2-d or 3--d, or three times that in other dimensions. If the outside width is specified ('Wn'), the maximum, default value for 'Vn' is 'Wn'. Un Maximum distance below a facet for a point to be coplanar to the facet. The default value is 'Vn'. Wn Minimum outside width of the hull. Points are added to the convex hull only if they are clearly outside of a facet. A point is outside of a facet if its distance to the facet is greater than 'Wn'. The normal value for 'Wn' is 'En'. If the user specifies pre-merging and does not set 'Wn', than 'Wn' is set to the premerge 'Cn' and maxco- ord*(1-An). Additional input/output formats Fa Print area for each facet. For Delaunay triangula- tions, the area is the area of the triangle. For Voronoi diagrams, the area is the area of the dual facet. Use 'PAn' for printing the n largest facets, and option 'PFn' for printing facets larger than 'n'. The area for non-simplicial facets is the sum of the areas for each ridge to the centrum. Vertices far below the facet's hyperplane are ignored. The reported area may be significantly less than the actual area. Geometry Center 2019/05/03 7 qhull(1) qhull(1) FA Compute the total area and volume for option 's'. It is an approximation for non-simplicial facets (see 'Fa'). Fc Print coplanar points for each facet. The output starts with the number of facets. Then each facet is printed one per line. Each line is the number of coplanar points followed by the point ids. Option 'Qi' includes the interior points. Each coplanar point (interior point) is assigned to the facet it is furthest above (resp., least below). FC Print centrums for each facet. The output starts with the dimension followed by the number of facets. Then each facet centrum is printed, one per line. Fd Read input in cdd format with homogeneous points. The input starts with comments. The first comment is reported in the summary. Data starts after a "begin" line. The next line is the number of points followed by the dimension+1 and "real" or "integer". Then the points are listed with a leading "1" or "1.0". The data ends with an "end" line. For halfspaces ('Fd Hn,n,...'), the input format is the same. Each halfspace starts with its offset. The sign of the offset is the opposite of Qhull's convention. FD Print normals ('n', 'Fo', 'Fi') or points ('p') in cdd format. The first line is the command line that invoked Qhull. Data starts with a "begin" line. The next line is the number of normals or points followed by the dimension+1 and "real". Then the normals or points are listed with the offset before the coefficients. The offset for points is 1.0. The offset for normals has the opposite sign. The data ends with an "end" line. FF Print facets (as in 'f') without printing the ridges. Fi Print inner planes for each facet. The inner plane is below all vertices. Fi Print separating hyperplanes for bounded, inner regions of the Voronoi diagram. The first line is the number of ridges. Then each hyperplane is printed, one per line. A line starts with the num- ber of indices and floats. The first pair lists adjacent input sites, the next d floats are the normalized coefficients for the hyperplane, and the Geometry Center 2019/05/03 8 qhull(1) qhull(1) last float is the offset. The hyperplane is ori- ented toward 'QVn' (if defined), or the first input site of the pair. Use 'Tv' to verify that the hyperplanes are perpendicular bisectors. Use 'Fo' for unbounded regions, and 'Fv' for the corresponding Voronoi vertices. FI Print facet identifiers. Fm Print number of merges for each facet. At most 511 merges are reported for a facet. See 'PMn' for printing the facets with the most merges. FM Output the hull in Maple format. See 'm' Fn Print neighbors for each facet. The output starts with the number of facets. Then each facet is printed one per line. Each line is the number of neighbors followed by an index for each neighbor. The indices match the other facet output formats. A negative index indicates an unprinted facet due to printing only good facets ('Pg'). It is the negation of the facet's id (option 'FI'). For example, negative indices are used for facets "at infinity" in the Delaunay triangulation. FN Print vertex neighbors or coplanar facet for each point. The first line is the number of points. Then each point is printed, one per line. If the point is coplanar, the line is "1" followed by the facet's id. If the point is not a selected vertex, the line is "0". Otherwise, each line is the num- ber of neighbors followed by the corresponding facet indices (see 'Fn'). Fo Print outer planes for each facet in the same for- mat as 'n'. The outer plane is above all points. Fo Print separating hyperplanes for unbounded, outer regions of the Voronoi diagram. The first line is the number of ridges. Then each hyperplane is printed, one per line. A line starts with the num- ber of indices and floats. The first pair lists adjacent input sites, the next d floats are the normalized coefficients for the hyperplane, and the last float is the offset. The hyperplane is ori- ented toward 'QVn' (if defined), or the first input site of the pair. Use 'Tv' to verify that the hyperplanes are perpendicular bisectors. Use 'Fi' for bounded regions, and 'Fv' for the corresponding Voronoi vertices. FO List all options to stderr, including the default values. Additional 'FO's are printed to stdout. Fp Print points for halfspace intersections (option 'Hn,n,...'). Each intersection corresponds to a Geometry Center 2019/05/03 9 qhull(1) qhull(1) facet of the dual polytope. The "infinity" point [-10.101,-10.101,...] indicates an unbounded intersection. FP For each coplanar point ('Qc') print the point id of the nearest vertex, the point id, the facet id, and the distance. FQ Print command used for qhull and input. Fs Print a summary. The first line consists of the number of integers ("7"), followed by the dimen- sion, the number of points, the number of vertices, the number of facets, the number of vertices selected for output, the number of facets selected for output, the number of coplanar points selected for output. The second line consists of the number of reals ("2"), followed by the maxmimum offset to an outer plane and and minimum offset to an inner plane. Roundoff is included. Later versions of Qhull may produce additional integers or reals. FS Print the size of the hull. The first line con- sists of the number of integers ("0"). The second line consists of the number of reals ("2"), fol- lowed by the total facet area, and the total vol- ume. Later versions of Qhull may produce addi- tional integers or reals. The total volume measures the volume of the inter- section of the halfspaces defined by each facet. Both area and volume are approximations for non- simplicial facets. See option 'Fa'. Ft Print a triangulation with added points for non- simplicial facets. The first line is the dimension and the second line is the number of points and the number of facets. The points follow, one per line, then the facets follow as a list of point indices. With option points include the point-at-infinity. Fv Print vertices for each facet. The first line is the number of facets. Then each facet is printed, one per line. Each line is the number of vertices followed by the corresponding point ids. Vertices are listed in the order they were added to the hull (the last one is first). Fv Print all ridges of a Voronoi diagram. The first line is the number of ridges. Then each ridge is printed, one per line. A line starts with the num- ber of indices. The first pair lists adjacent Geometry Center 2019/05/03 10 qhull(1) qhull(1) input sites, the remaining indices list Voronoi vertices. Vertex '0' indicates the vertex-at- infinity (i.e., an unbounded ray). In 3-d, the vertices are listed in order. See 'Fi' and 'Fo' for separating hyperplanes. FV Print average vertex. The average vertex is a fea- sible point for halfspace intersection. Fx List extreme points (vertices) of the convex hull. The first line is the number of points. The other lines give the indices of the corresponding points. The first point is '0'. In 2-d, the points occur in counter-clockwise order; otherwise they occur in input order. For Delaunay triangulations, 'Fx' lists the extreme points of the input sites. The points are unordered. Geomview options G Produce a file for viewing with Geomview. Without other options, Qhull displays edges in 2-d, outer planes in 3-d, and ridges in 4-d. A ridge can be explicit or implicit. An explicit ridge is a dim-1 dimensional simplex between two facets. In 4-d, the explicit ridges are triangles. When displaying a ridge in 4-d, Qhull projects the ridge's vertices to one of its facets' hyperplanes. Use 'Gh' to project ridges to the intersection of both hyper- planes. Ga Display all input points as dots. Gc Display the centrum for each facet in 3-d. The centrum is defined by a green radius sitting on a blue plane. The plane corresponds to the facet's hyperplane. The radius is defined by 'C-n' or 'Cn'. GDn Drop dimension n in 3-d or 4-d. The result is a 2-d or 3-d object. Gh Display hyperplane intersections in 3-d and 4-d. In 3-d, the intersection is a black line. It lies on two neighboring hyperplanes (c.f., the blue squares associated with centrums ('Gc')). In 4-d, the ridges are projected to the intersection of both hyperplanes. Gi Display inner planes in 2-d and 3-d. The inner plane of a facet is below all of its vertices. It is parallel to the facet's hyperplane. The inner plane's color is the opposite (1-r,1-g,1-b) of the Geometry Center 2019/05/03 11 qhull(1) qhull(1) outer plane. Its edges are determined by the ver- tices. Gn Do not display inner or outer planes. By default, Geomview displays the precise plane (no merging) or both inner and output planes (merging). Under merging, Geomview does not display the inner plane if the the difference between inner and outer is too small. Go Display outer planes in 2-d and 3-d. The outer plane of a facet is above all input points. It is parallel to the facet's hyperplane. Its color is determined by the facet's normal, and its edges are determined by the vertices. Gp Display coplanar points and vertices as radii. A radius defines a ball which corresponds to the imprecision of the point. The imprecision is the maximum of the roundoff error, the centrum radius, and maxcoord * (1-An). It is at least 1/20'th of the maximum coordinate, and ignores post-merging if pre-merging is done. Gr Display ridges in 3-d. A ridge connects the two vertices that are shared by neighboring facets. Ridges are always displayed in 4-d. Gt A 3-d Delaunay triangulation looks like a convex hull with interior facets. Option 'Gt' removes the outside ridges to reveal the outermost facets. It automatically sets options 'Gr' and 'GDn'. Gv Display vertices as spheres. The radius of the sphere corresponds to the imprecision of the data. See 'Gp' for determining the radius. Print options PAn Only the n largest facets are marked good for printing. Unless 'PG' is set, 'Pg' is automati- cally set. Pdk:n Drop facet from output if normal[k] <= n. The option 'Pdk' uses the default value of 0 for n. PDk:n Drop facet from output if normal[k] >= n. The option 'PDk' uses the default value of 0 for n. PFn Only facets with area at least 'n' are marked good for printing. Unless 'PG' is set, 'Pg' is automat- ically set. Geometry Center 2019/05/03 12 qhull(1) qhull(1) Pg Print only good facets. A good facet is either visible from a point (the 'QGn' option) or includes a point (the 'QVn' option). It also meets the requirements of 'Pdk' and 'PDk' options. Option 'Pg' is automatically set for options 'd', 'PAn', 'PFn', and 'PMn' PG Print neighbors of good facets. PMn Only the n facets with the most merges are marked good for printing. Unless 'PG' is set, 'Pg' is automatically set. Po Force output despite precision problems. Verify ('Tv') does not check coplanar points. Flipped facets are reported and concave facets are counted. If 'Po' is used, points are not partitioned into flipped facets and a flipped facet is always visible to a point. Also, if an error occurs before the completion of Qhull and tracing is not active, 'Po' outputs a neighborhood of the erroneous facets (if any). Pp Do not report precision problems. Qhull control options Qa Allow input with fewer or more points than coordinates Qbk:0Bk:0 Drop dimension k from the input points. This allows the user to take convex hulls of sub-dimen- sional objects. It happens before the Delaunay and Voronoi transformation. QbB Scale the input points to fit the unit cube. After scaling, the lower bound will be -0.5 and the upper bound +0.5 in all dimensions. For Delaunay and Voronoi diagrams, scaling happens after projection to the paraboloid. Under precise arithmetic, scal- ing does not change the topology of the convex hull. Qbb Scale the last coordinate to [0, m] where m is the maximum absolute value of the other coordinates. For Delaunay and Voronoi diagrams, scaling happens after projection to the paraboloid. It reduces roundoff error for inputs with integer coordinates. Under precise arithmetic, scaling does not change the topology of the convex hull. Qbk:n Scale the k'th coordinate of the input points. After scaling, the lower bound of the input points will be n. 'Qbk' scales to -0.5. Geometry Center 2019/05/03 13 qhull(1) qhull(1) QBk:n Scale the k'th coordinate of the input points. After scaling, the upper bound will be n. 'QBk' scales to +0.5. Qc Keep coplanar points with the nearest facet. Out- put formats 'p', 'f', 'Gp', 'Fc', 'FN', and 'FP' will print the points. Qf Partition points to the furthest outside facet. Qg Only build good facets. With the 'Qg' option, Qhull will only build those facets that it needs to determine the good facets in the output. See 'QGn', 'QVn', and 'PdD' for defining good facets, and 'Pg' and 'PG' for printing good facets and their neighbors. QGn A facet is good (see 'Qg' and 'Pg') if it is visi- ble from point n. If n < 0, a facet is good if it is not visible from point n. Point n is not added to the hull (unless 'TCn' or 'TPn'). With rbox, use the 'Pn,m,r' option to define your point; it will be point 0 (QG0). Qi Keep interior points with the nearest facet. Out- put formats 'p', 'f', 'Gp', 'FN', 'FP', and 'Fc' will print the points. QJn Joggle each input coordinate by adding a random number in [-n,n]. If a precision error occurs, then qhull increases n and tries again. It does not increase n beyond a certain value, and it stops after a certain number of attempts [see user.h]. Option 'QJ' selects a default value for n. The output will be simplicial. For Delaunay triangula- tions, 'QJn' sets 'Qbb' to scale the last coordi- nate (not if 'Qbk:n' or 'QBk:n' is set). 'QJn' is deprecated for Voronoi diagrams. See also 'Qt'. Qm Only process points that would otherwise increase max_outside. Other points are treated as coplanar or interior points. Qr Process random outside points instead of furthest ones. This makes Qhull equivalent to the random- ized incremental algorithms. CPU time is not reported since the randomization is inefficient. QRn Randomly rotate the input points. If n=0, use time as the random number seed. If n>0, use n as the random number seed. If n=-1, don't rotate but use time as the random number seed. For Delaunay tri- angulations ('d' and 'v'), rotate about the last axis. Geometry Center 2019/05/03 14 qhull(1) qhull(1) Qs Search all points for the initial simplex. Qt Triangulated output. Triangulate non-simplicial facets. 'Qt' is deprecated for Voronoi diagrams. See also 'QJn' Qv Test vertex neighbors for convexity after post- merging. To use the 'Qv' option, you also need to set a merge option (e.g., 'Qx' or 'C-0'). QVn A good facet (see 'Qg' and 'Pg') includes point n. If n<0, then a good facet does not include point n. The point is either in the initial simplex or it is the first point added to the hull. Option 'QVn' may not be used with merging. Qw Allow option warnings. Otherwise Qhull returns an error after most option warnings. Qx Perform exact merges while building the hull. The "exact" merges are merging a point into a coplanar facet (defined by 'Vn', 'Un', and 'C-n'), merging concave facets, merging duplicate ridges, and merg- ing flipped facets. Coplanar merges and angle coplanar merges ('A-n') are not performed. Concav- ity testing is delayed until a merge occurs. After the hull is built, all coplanar merges are performed (defined by 'C-n' and 'A-n'), then post- merges are performed (defined by 'Cn' and 'An'). Qz Add a point "at infinity" that is above the paraboloid for Delaunay triangulations and Voronoi diagrams. This reduces precision problems and allows the triangulation of cospherical points. Qhull experiments and speedups Q0 Turn off pre-merging as a default option. With 'Q0'/'Qx' and without explicit pre-merge options, Qhull ignores precision issues while constructing the convex hull. This may lead to precision errors. If so, a descriptive warning is generated. Q1 With 'Q1', Qhull merges by mergetype/angle instead of mergetype/distance. Q2 With 'Q2', Qhull merges all facets at once instead of using independent sets of merges and then retesting. Q3 With 'Q3', Qhull does not remove redundant ver- tices. Q4 With 'Q4', Qhull avoids merges of an old facet into a new facet. Q5 With 'Q5', Qhull does not correct outer planes at the end. The maximum outer plane is used instead. Geometry Center 2019/05/03 15 qhull(1) qhull(1) Q6 With 'Q6', Qhull does not pre-merge concave or coplanar facets. Q7 With 'Q7', Qhull processes facets in depth-first order instead of breadth-first order. Q8 With 'Q8' and merging, Qhull does not retain near- interior points for adjusting outer planes. 'Qc' will probably retain all points that adjust outer planes. Q9 With 'Q9', Qhull processes the furthest of all out- side sets at each iteration. Q10 With 'Q10', Qhull does not use special processing for narrow distributions. Q11 With 'Q11', Qhull copies normals and recomputes centrums for tricoplanar facets. Q12 With 'Q12', Qhull allows wide facets and wide dupridge Q14 With 'Q14', Qhull merges pinched vertices that create a dupridge. Q15 With 'Q15', Qhull checks for duplicate ridges with the same vertices. Trace options Tn Trace at level n. Qhull includes full execution tracing. 'T-1' traces events. 'T1' traces the overall execution of the program. 'T2' and 'T3' trace overall execution and geometric and topologi- cal events. 'T4' traces the algorithm. 'T5' includes information about memory allocation and Gaussian elimination. Ta Annotate output with codes that identify the corresponding qh_fprintf() statement. TAn Stop Qhull after adding n vertices. Tc Check frequently during execution. This will catch most inconsistency errors. TCn Stop Qhull after building the cone of new facets for point n. The output for 'f' includes the cone and the old hull. See also 'TVn'. Tf Flush output after each qh_fprintf. Use 'Tf' for debugging segfaults. See 'Tz' for redirecting stderr. TFn Report progress whenever more than n facets are created During post-merging, 'TFn' reports progress after more than n/2 merges. TI file Input data from 'file'. The filename may not include spaces or quotes. TMn Turn on tracing at n'th merge. TO file Output results to 'file'. The name may be enclosed in single quotes. TPn Turn on tracing when point n is added to the hull. Trace partitions of point n. If used with TWn, turn off tracing after adding point n to the hull. TP-1 Turn on tracing after qh_buildhull and qh_postmerge. TRn Rerun qhull n times. Usually used with 'QJn' to determine the probability that a given joggle will fail. Ts Collect statistics and print to stderr at the end of execution. Tv Verify the convex hull. This checks the topologi- cal structure, facet convexity, and point inclu- sion. If precision problems occurred, facet con- vexity is tested whether or not 'Tv' is selected. Option 'Tv' does not check point inclusion if Geometry Center 2019/05/03 16 qhull(1) qhull(1) forcing output with 'Po', or if 'Q5' is set. For point inclusion testing, Qhull verifies that all points are below all outer planes (facet->max- outside). Point inclusion is exhaustive if merging or if the facet-point product is small enough; oth- erwise Qhull verifies each point with a directed search (qh_findbest). Point inclusion testing occurs after producing out- put. It prints a message to stderr unless option 'Pp' is used. This allows the user to interrupt Qhull without changing the output. TVn Stop Qhull after adding point n. If n < 0, stop Qhull before adding point n. Output shows the hull at this time. See also 'TCn' TWn Trace merge facets when the width is greater than n. Tz Redirect stderr to stdout. See 'Tf' for flushing writes. BUGS Please report bugs to Brad Barber at qhull_bug@qhull.org. If Qhull does not compile, it is due to an incompatibility between your system and ours. The first thing to check is that your compiler is ANSI standard. If it is, check the man page for the best options, or find someone to help you. If you locate the cause of your problem, please send email since it might help others. If Qhull compiles but crashes on the test case (rbox D4), there's still incompatibility between your system and ours. Typically it's been due to mem.c and memory align- ment. You can use qh_NOmem in mem.h to turn off memory management. Please let us know if you figure out how to fix these problems. If you do find a problem, try to simplify it before reporting the error. Try different size inputs to locate the smallest one that causes an error. You're welcome to hunt through the code using the execution trace as a guide. This is especially true if you're incorporating Qhull into your own program. When you do report an error, please attach a data set to the end of your message. This allows us to see the error for ourselves. Qhull is maintained part-time. Geometry Center 2019/05/03 17 qhull(1) qhull(1) E-MAIL Please send correspondence to qhull@qhull.org and report bugs to qhull_bug@qhull.org. Let us know how you use Qhull. If you mention it in a paper, please send the reference and an abstract. If you would like to get Qhull announcements (e.g., a new version) and news (any bugs that get fixed, etc.), let us know and we will add you to our mailing list. If you would like to communicate with other Qhull users, we will add you to the qhull_users alias. For Internet news about geometric algorithms and convex hulls, look at comp.graph- ics.algorithms and sci.math.num-analysis SEE ALSO rbox(1) Barber, C. B., D.P. Dobkin, and H.T. Huhdanpaa, "The Quickhull Algorithm for Convex Hulls," ACM Trans. on Math- ematical Software, 22(4):469-483, Dec. 1996. http://portal.acm.org/citation.cfm?doid=235815.235821 http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.117.405 Clarkson, K.L., K. Mehlhorn, and R. Seidel, "Four results on randomized incremental construction," Computational Geometry: Theory and Applications, vol. 3, p. 185-211, 1993. Preparata, F. and M. Shamos, Computational Geometry, Springer-Verlag, New York, 1985. AUTHORS C. Bradford Barber Hannu Huhdanpaa bradb@shore.net hannu@qhull.org ACKNOWLEDGEMENTS A special thanks to Albert Marden, Victor Milenkovic, the Geometry Center, Harvard University, and Endocardial Solu- tions, Inc. for supporting this work. Qhull 1.0 and 2.0 were developed under National Science Foundation grants NSF/DMS-8920161 and NSF-CCR-91-15793 750-7504. David Dobkin Geometry Center 2019/05/03 18 qhull(1) qhull(1) guided the original work at Princeton University. If you find it useful, please let us know. The Geometry Center was supported by grant DMS-8920161 from the National Science Foundation, by grant DOE/DE-FG02-92ER25137 from the Department of Energy, by the University of Minnesota, and by Minnesota Technology, Inc. Qhull is available from http://www.qhull.org Geometry Center 2019/05/03 19 rbox(1) rbox(1) NAME rbox - generate point distributions for qhull SYNOPSIS Command "rbox" (w/o arguments) lists the options. DESCRIPTION rbox generates random or regular points according to the options given, and outputs the points to stdout. The points are generated in a cube, unless 's' or given. The format of the output is the following: first line contains the dimension and a comment, second line contains the num- ber of points, and the following lines contain the points, one point per line. Points are represented by their coor- dinate values. EXAMPLES rbox 10 10 random points in the unit cube centered at the origin. rbox 10 s D2 10 random points on a 2-d circle. rbox 100 W0 100 random points on the surface of a cube. rbox 1000 s D4 1000 random points on a 4-d sphere. rbox c D5 O0.5 a 5-d hypercube with one corner at the origin. rbox d D10 a 10-d diamond. rbox x 1000 r W0 100 random points on the surface of a fixed simplex rbox y D12 a 12-d simplex. rbox l 10 10 random points along a spiral rbox l 10 r 10 regular points along a spiral plus two end points rbox 1000 L10000 D4 s 1000 random points on the surface of a narrow lens. rbox c G2 d G3 a cube with coordinates +2/-2 and a diamond with Geometry Center August 10, 1998 1 rbox(1) rbox(1) coordinates +3/-3. rbox 64 M3,4 z a rotated, {0,1,2,3} x {0,1,2,3} x {0,1,2,3} lat- tice (Mesh) of integer points. rbox P0 P0 P0 P0 P0 5 copies of the origin in 3-d. Try 'rbox P0 P0 P0 P0 P0 | qhull QJ'. r 100 s Z1 G0.1 two cospherical 100-gons plus another cospherical point. 100 s Z1 a cone of points. 100 s Z1e-7 a narrow cone of points with many precision errors. OPTIONS n number of points Dn dimension n-d (default 3-d) Bn bounding box coordinates (default 0.5) l spiral distribution, available only in 3-d Ln lens distribution of radius n. May be used with 's', 'r', 'G', and 'W'. Mn,m,r lattice (Mesh) rotated by {[n,-m,0], [m,n,0], [0,0,r], ...}. Use 'Mm,n' for a rigid rotation with r = sqrt(n^2+m^2). 'M1,0' is an orthogonal lattice. For example, '27 M1,0' is {0,1,2} x {0,1,2} x {0,1,2}. s cospherical points randomly generated in a cube and projected to the unit sphere x simplicial distribution. It is fixed for option 'r'. May be used with 'W'. y simplicial distribution plus a simplex. Both 'x' and 'y' generate the same points. Wn restrict points to distance n of the surface of a sphere or a cube c add a unit cube to the output c Gm add a cube with all combinations of +m and -m to the output Geometry Center August 10, 1998 2 rbox(1) rbox(1) d add a unit diamond to the output. d Gm add a diamond made of 0, +m and -m to the output Cn,r,m add n nearly coincident points within radius r of m points Pn,m,r add point [n,m,r] to the output first. Pad coordi- nates with 0.0. n Remove the command line from the first line of out- put. On offset the data by adding n to each coordinate. t use time in seconds as the random number seed (default is command line). tn set the random number seed to n. z generate integer coordinates. Use 'Bn' to change the range. The default is 'B1e6' for six-digit coordinates. In R^4, seven-digit coordinates will overflow hyperplane normalization. Zn s restrict points to a disk about the z+ axis and the sphere (default Z1.0). Includes the opposite pole. 'Z1e-6' generates degenerate points under single precision. Zn Gm s same as Zn with an empty center (default G0.5). r s D2 generate a regular polygon r s Z1 G0.1 generate a regular cone BUGS Some combinations of arguments generate odd results. Report bugs to qhull_bug@qhull.org, other correspon- dence to qhull@qhull.org SEE ALSO qhull(1) AUTHOR C. Bradford Barber bradb@shore.net Geometry Center August 10, 1998 3 # end of q_test eg/q_benchmark test 1 1 1 1 eg/q_benchmark: Temporarily add "$PWD/bin" to $PATH for access to rbox ============================================ == eg/q_benchmark [test] [precision-count] [other-count] [pinched-count] [time-count] == Time and precision benchmarks for qhull ============================================ [jun'20] Many timing figures 5-10% faster than jun'19 results. No change to code 'q_benchmark test 1 1 1 1' Fri, Jul 24, 2020 10:27:42 PM # $Id: //main/2019/qhull/eg/q_benchmark#5 $$DateTime: 2020/06/05 16:33:18 $ # $Id: //main/2019/qhull/eg/qtest.sh#4 $$DateTime: 2019/06/25 15:24:47 $ qhull => qhull_r 8.0.1 (2020.2.r 2020/07/24) -rwxr-xr-x 1 bbarber 197121 339968 Jul 24 21:06 /d/bash/local/qhull/bin/qhull rbox => Version: 2019/11/10 -rwxr-xr-x 1 bbarber 197121 32768 Jul 24 21:06 /d/bash/local/qhull/bin/rbox MINGW64_NT-10.0-19041 kelwyn 3.0.7-338.x86_64 2019-04-30 21:52 UTC x86_64 Msys Logging to /d/bash/local/qhull/eg/qhull-benchmark.log and eg/qhull-benchmark-show.log ======================== === test eg/qtest.sh === ======================== == qtest.sh help qtest.sh -- test qhull runs qtest.sh N 'rbox c | qhull' -- N random qhull runs qtest.sh N 'rbox-opts' 'qhull-opts' -- N random rbox|qhull runs qtest.sh -N 'rbox c | qhull' -- N qhull runs qtest.sh -N 'rbox opts' 'qhull opts' -- N rbox|qhull runs execute rbox and qhull qtest.sh run 'rbox c | qhull' -- execute 'qhull command' qtest.sh run QR... 'rbox | qhull' -- execute 'qhull command QR...' qtest.sh run t... 'rbox-opts' 'qhull-opts' -- execute 'rbox t... | qhull' log execution of rbox and qhull qtest.sh log 'rbox c | qhull' -- log qhull to qhull.log/qhull-step.log qtest.sh QR... 'rbox c | qhull' -- log a qhull run qtest.sh t... 'rbox-opts' 'qhull-opts' -- log a 'rbox|qhull' run qtest.sh grep 'include-regexp' -- grep qhull.log for events to grep.log qtest.sh grep 'include-regexp' 'exclude-regexp' qtest.sh grep-merge logfile -- grep logfile for qh_mergefacet,etc. to stdout qtest.sh grep-step logfile -- grep logfile for steps to stdout qtest.sh -v ... -- verbose output with environment vars variables defined in qtest.sh QH_TEST_BASE -- first tNN for negative counts QH_TEST_DEST -- qtest.sh log QH_TEST_GREP -- grep expression for qtest.sh log QH_SHOW_DEST -- qtest.sh show log QH_SHOW_GREPX -- exclude grep for show log QH_LOG_DEST -- qhull log QH_LOG_GREP -- grep expression for qhull log QH_STEP_DEST -- qhull step log QH_STEP_GREP -- grep expression for step log and grep-step QH_MERGE_GREP -- grep expression for grep-merge QH_MERGE_GREPX -- exclude grep for grep-merge environment variables QHULL -- qhull program, may be qconvex, etc QH_APPEND_DEST -- append qtest.sh log QH_APPEND_SHOW -- append show log QH_TEST -- additional grep expression for qtest.sh log QH_TESTX -- exclude grep for qtest.sh log QH_SHOW -- grep expression for show log QH_SHOWX -- additional exclude grep for show log QH_GREP -- additional grep expression for grep log QH_GREPX -- additional exclude grep for grep log Tnz -- Trace setting for 'qtest.sh log' examples qtest.sh help qtest.sh 25 '1000 W1e-13 D4' '' qtest.sh 25 '1000 W0 D4 C2,2e-13' 'Q14' qtest.sh 25 '300 D4 C1,2e-13' 'd Q14' qtest.sh -10 '10000 D4' '' qtest.sh -10 '1000 s D4' '' qtest.sh -10 'rbox 1000 s D4 | qhull' qtest.sh run QR4 'rbox 1000 s D4 | qhull' qtest.sh run t876333 '1000 s D4' '' qtest.sh log 'rbox 500 s D4 | qhull' # qhull.log qhull-step.log qtest.sh t876333 '500 s D4' '' qtest.sh QR4 'rbox 500 s D4 | qhull' qtest.sh grep 'qh_addpoint|qh_mark_dupridges' | head -20 # QH_GREP QH_GREPX qtest.sh grep 'qh_addpoint' 'added| qh_addpoint' | head -20 qtest.sh grep-merge qhull.log | head -20 qtest.sh grep-step qhull.log >qhull-step.log qtest.sh -v -10 '10000 D4' '' # verbose # $Id: //main/2019/qhull/eg/qtest.sh#4 $$DateTime: 2019/06/25 15:24:47 $ == qtest.sh 1 '10' '' Testing -- rbox 10 t330528 | qhull >/d/bash/var/tmp/qtest-2020-07-24/qhull-330528.log Test -- t330528 CPU seconds to compute hull (after input): 0 == qtest.sh 2 'rbox 10 | qhull' Testing -- rbox 10 | qhull >/d/bash/var/tmp/qtest-2020-07-24/qhull-864005.log Test -- QR864005 CPU seconds to compute hull (after input): 0 Test -- QR864006 CPU seconds to compute hull (after input): 0 == qtest.sh -3 '10' '' Testing -- rbox 10 t1 | qhull >/d/bash/var/tmp/qtest-2020-07-24/qhull-930959.log Test -- t1 CPU seconds to compute hull (after input): 0 Test -- t2 CPU seconds to compute hull (after input): 0 Test -- t3 CPU seconds to compute hull (after input): 0 1595644068 Test 3 runs in 1 seconds (ave. 333 msec) -- rbox 10 t1 | qhull == qtest.sh -3 'rbox 10 | qhull' Testing -- rbox 10 | qhull >/d/bash/var/tmp/qtest-2020-07-24/qhull-464436.log Test -- QR1 CPU seconds to compute hull (after input): 0 Test -- QR2 CPU seconds to compute hull (after input): 0 Test -- QR3 CPU seconds to compute hull (after input): 0 1595644069 Test 3 runs in 0 seconds (average 0 msec) -- rbox 10 | qhull == qtest.sh run t123456 '10' 'Tz' Convex hull of 10 points in 3-d: Number of vertices: 8 Number of facets: 12 Statistics for: rbox 10 t123456 | qhull Tz Number of points processed: 8 Number of hyperplanes created: 20 Number of distance tests for qhull: 53 CPU seconds to compute hull (after input): 0 == qtest.sh run QR123456 'rbox 10 | qhull Tz' Convex hull of 10 points in 3-d: Number of vertices: 10 Number of facets: 16 Statistics for: rbox 10 | qhull Tz QR123456 QR123456 Number of points processed: 10 Number of hyperplanes created: 27 Number of distance tests for qhull: 45 CPU seconds to compute hull (after input): 0 == qtest.sh log 'rbox 10 | qhull' qtest.sh: log 'rbox 10 | qhull T4z' to 'qhull.log' and 'qhull-step.log' ==== EXTRA Fri, Jul 24, 2020 10:27:51 PM ==== 1801:Convex hull of 10 points in 3-d: 1802: 1803: Number of vertices: 10 1804: Number of facets: 16 1805: 1806:Statistics for: rbox 10 | qhull T4z 1807: 1808: Number of points processed: 10 1809: Number of hyperplanes created: 26 1810: Number of distance tests for qhull: 43 1811: CPU seconds to compute hull (after input): 0.002 qhull.log qtest.sh: log 'rbox 10 | qhull T4z' to 'qhull.log' and 'qhull-step.log' kelwyn Fri, Jul 24, 2020 10:27:50 PM /d/bash/local/qhull -rwxr-xr-x 1 bbarber 197121 339968 Jul 24 21:06 /d/bash/local/qhull/bin/qhull qhull_r 8.0.1 (2020.2.r 2020/07/24) 1:qh_initflags: option flags initialized 2:[QH1008]qh_readpoints: read in 10 3-dimensional points 3:[QH0013]qh_initqhull_globals: for rbox 10 | qhull T4z 4:[QH2005]qh_initqhull_globals: initialize globals. input_dim 3, numpoints 10, malloc? 1, projected 0 to hull_dim 3 5:[QH3024]qh_initqhull_outputflags: qhull T4z == qtest.sh t123456 '10' '' qtest.sh: logging 'rbox 10 t123456 | qhull T4sz ' to 'qhull.log' and 'qhull-step.log' ==== EXTRA Fri, Jul 24, 2020 10:27:52 PM ==== 1320:Convex hull of 10 points in 3-d: 1321: 1322: Number of vertices: 8 1323: Number of facets: 12 1324: 1325:Statistics for: rbox 10 t123456 | qhull T4z 1326: 1327: Number of points processed: 8 1328: Number of hyperplanes created: 20 1329: Number of distance tests for qhull: 53 1330: CPU seconds to compute hull (after input): 0.003 qhull.log qtest.sh: logging 'rbox 10 t123456 | qhull T4sz ' to 'qhull.log' and 'qhull-step.log' Fri, Jul 24, 2020 10:27:51 PM /d/bash/local/qhull -rwxr-xr-x 1 bbarber 197121 339968 Jul 24 21:06 /d/bash/local/qhull/bin/qhull qhull_r 8.0.1 (2020.2.r 2020/07/24) 1:qh_initflags: option flags initialized 2:[QH1008]qh_readpoints: read in 10 3-dimensional points 3:[QH0013]qh_initqhull_globals: for rbox 10 t123456 | qhull T4z 4:[QH2005]qh_initqhull_globals: initialize globals. input_dim 3, numpoints 10, malloc? 1, projected 0 to hull_dim 3 5:[QH3024]qh_initqhull_outputflags: qhull T4z == qtest.sh QR123456 'rbox 10 | qhull' qtest.sh: log 'rbox 10 | qhull T4z QR123456' to 'qhull.log' and 'qhull-step.log' ==== EXTRA Fri, Jul 24, 2020 10:27:53 PM ==== 1850:Convex hull of 10 points in 3-d: 1851: 1852: Number of vertices: 10 1853: Number of facets: 16 1854: 1855:Statistics for: rbox 10 | qhull T4z QR123456 QR123456 1856: 1857: Number of points processed: 10 1858: Number of hyperplanes created: 27 1859: Number of distance tests for qhull: 45 1860: CPU seconds to compute hull (after input): 0.004 qhull-step.log qtest.sh: log 'rbox 10 | qhull T4z QR123456' to 'qhull.log' and 'qhull-step.log' 2:[QH1008]qh_readpoints: read in 10 3-dimensional points 3:[QH0013]qh_initqhull_globals: for rbox 10 | qhull T4z QR123456 4:[QH2005]qh_initqhull_globals: initialize globals. input_dim 3, numpoints 10, malloc? 1, projected 0 to hull_dim 3 5:[QH3024]qh_initqhull_outputflags: qhull T4z QR123456 7:[QH3078]qh_memsize: quick memory of 32 bytes 8:[QH3078]qh_memsize: quick memory of 24 bytes 9:[QH3078]qh_memsize: quick memory of 48 bytes 10:[QH3078]qh_memsize: quick memory of 88 bytes 11:[QH3078]qh_memsize: quick memory of 16 bytes == qtest.sh grep 'qh_addpoint|QH1' >qhull-grep.log qtest.sh: grep from 'qhull.log' to stdout 2:[QH1008]qh_readpoints: read in 10 3-dimensional points 32:[QH1002]qh_maxsimplex: selected point p9 for 3`th initial vertex, det=0.3388, targetdet=0.6029, mindet=0.006029 36:[QH1002]qh_maxsimplex: selected point p7 for 4`th initial vertex, det=0.253, targetdet=0.3628, mindet=0.003628 53:[QH1028]qh_createsimplex: created simplex 93:[QH1027]qh_checkpolygon: check all facets from f1, qh.NEWtentative? 0 99:[QH1064]qh_checkconvex: check that facets are not-flipped and for qh.ZEROcentrum that simplicial vertices are below their neighbor (dist<0.0) 113:[QH1042]qh_partitionall: partition all points into outside sets 177:[QH1029]qh_furthestnext: made f1 next facet(dist 0.53) 178:[QH1030]qh_initbuild: initial hull created and points partitioned qhull-grep.log 1706: qh.visible_list f24, newfacet_list f24, facet_next f14 for qh_addpoint 1742:[QH1027]qh_checkpolygon: check all facets from f5, qh.NEWtentative? 0 1761:[QH2056]qh_addpoint: added p4 to convex hull with point balance 0 1762:[QH1039]qh_buildhull: completed the hull construction 1764:[QH1036]Qhull: algorithm completed 1765:[QH1027]qh_checkpolygon: check all facets from f5, qh.NEWtentative? 0 1799:[QH1064]qh_checkconvex: check that facets are not-flipped and for qh.ZEROcentrum that simplicial vertices are below their neighbor (dist<0.0) 1863:[QH1006]qh_freeqhull: free global memory 1864:[QH1005]qh_freebuild: free memory from qh_inithull and qh_buildhull 1865:[QH1061]qh_freeqhull: clear qhT except for qh.qhmem and qh.qhstat == qtest.sh grep 'qh_addpoint' 'added| qh_addpoint' >qhull-grep.log qtest.sh: grep from 'qhull.log' to stdout 182:[QH1049]qh_addpoint: add p1(v5) 0.53 above f1 to hull of 4 facets, 0 merges, 6 outside at 0.001 CPU secs. Previous p-1(v4) delta 0.001 CPU, 4 facets, 0 merges, 4 hyperplanes, 44 distplanes, 0 retries 453:[QH1049]qh_addpoint: add p3(v6) 0.18 above f3 to hull of 6 facets, 0 merges, 5 outside at 0.001 CPU secs. Previous p1(v5) delta 0 CPU, 2 facets, 0 merges, 4 hyperplanes, 32 distplanes, 0 retries 734:[QH1049]qh_addpoint: add p5(v7) 0.15 above f6 to hull of 8 facets, 0 merges, 4 outside at 0.002 CPU secs. Previous p3(v6) delta 0.001 CPU, 2 facets, 0 merges, 4 hyperplanes, 33 distplanes, 0 retries 954:[QH1049]qh_addpoint: add p2(v8) 0.24 above f8 to hull of 10 facets, 0 merges, 3 outside at 0.002 CPU secs. Previous p5(v7) delta 0 CPU, 2 facets, 0 merges, 3 hyperplanes, 24 distplanes, 0 retries 1223:[QH1049]qh_addpoint: add p8(v9) 0.18 above f12 to hull of 12 facets, 0 merges, 2 outside at 0.003 CPU secs. Previous p2(v8) delta 0.001 CPU, 2 facets, 0 merges, 4 hyperplanes, 30 distplanes, 0 retries 1494:[QH1049]qh_addpoint: add p4(v10) 0.073 above f13 to hull of 14 facets, 0 merges, 1 outside at 0.003 CPU secs. Previous p8(v9) delta 0 CPU, 2 facets, 0 merges, 4 hyperplanes, 30 distplanes, 0 retries qhull-grep.log qtest.sh: grep from 'qhull.log' to stdout 182:[QH1049]qh_addpoint: add p1(v5) 0.53 above f1 to hull of 4 facets, 0 merges, 6 outside at 0.001 CPU secs. Previous p-1(v4) delta 0.001 CPU, 4 facets, 0 merges, 4 hyperplanes, 44 distplanes, 0 retries 453:[QH1049]qh_addpoint: add p3(v6) 0.18 above f3 to hull of 6 facets, 0 merges, 5 outside at 0.001 CPU secs. Previous p1(v5) delta 0 CPU, 2 facets, 0 merges, 4 hyperplanes, 32 distplanes, 0 retries 734:[QH1049]qh_addpoint: add p5(v7) 0.15 above f6 to hull of 8 facets, 0 merges, 4 outside at 0.002 CPU secs. Previous p3(v6) delta 0.001 CPU, 2 facets, 0 merges, 4 hyperplanes, 33 distplanes, 0 retries 954:[QH1049]qh_addpoint: add p2(v8) 0.24 above f8 to hull of 10 facets, 0 merges, 3 outside at 0.002 CPU secs. Previous p5(v7) delta 0 CPU, 2 facets, 0 merges, 3 hyperplanes, 24 distplanes, 0 retries 1223:[QH1049]qh_addpoint: add p8(v9) 0.18 above f12 to hull of 12 facets, 0 merges, 2 outside at 0.003 CPU secs. Previous p2(v8) delta 0.001 CPU, 2 facets, 0 merges, 4 hyperplanes, 30 distplanes, 0 retries 1494:[QH1049]qh_addpoint: add p4(v10) 0.073 above f13 to hull of 14 facets, 0 merges, 1 outside at 0.003 CPU secs. Previous p8(v9) delta 0 CPU, 2 facets, 0 merges, 4 hyperplanes, 30 distplanes, 0 retries == qtest.sh grep-merge 'qhull.log' >qhull-grep.log qtest.sh: grep merges from 'qhull.log' to stdout qtest.sh: log 'rbox 10 | qhull T4z QR123456' to 'qhull.log' and 'qhull-step.log' 182:[QH1049]qh_addpoint: add p1(v5) 0.53 above f1 to hull of 4 facets, 0 merges, 6 outside at 0.001 CPU secs. Previous p-1(v4) delta 0.001 CPU, 4 facets, 0 merges, 4 hyperplanes, 44 distplanes, 0 retries 183:[QH1040]qh_findhorizon: find horizon for point 450:[QH2056]qh_addpoint: added p1 to convex hull with point balance 0 453:[QH1049]qh_addpoint: add p3(v6) 0.18 above f3 to hull of 6 facets, 0 merges, 5 outside at 0.001 CPU secs. Previous p1(v5) delta 0 CPU, 2 facets, 0 merges, 4 hyperplanes, 32 distplanes, 0 retries 454:[QH1040]qh_findhorizon: find horizon for point 731:[QH2056]qh_addpoint: added p3 to convex hull with point balance -1 734:[QH1049]qh_addpoint: add p5(v7) 0.15 above f6 to hull of 8 facets, 0 merges, 4 outside at 0.002 CPU secs. Previous p3(v6) delta 0.001 CPU, 2 facets, 0 merges, 4 hyperplanes, 33 distplanes, 0 retries 735:[QH1040]qh_findhorizon: find horizon for point 951:[QH2056]qh_addpoint: added p5 to convex hull with point balance -0.29 qhull-grep.log 954:[QH1049]qh_addpoint: add p2(v8) 0.24 above f8 to hull of 10 facets, 0 merges, 3 outside at 0.002 CPU secs. Previous p5(v7) delta 0 CPU, 2 facets, 0 merges, 3 hyperplanes, 24 distplanes, 0 retries 955:[QH1040]qh_findhorizon: find horizon for point 1220:[QH2056]qh_addpoint: added p2 to convex hull with point balance -0.75 1223:[QH1049]qh_addpoint: add p8(v9) 0.18 above f12 to hull of 12 facets, 0 merges, 2 outside at 0.003 CPU secs. Previous p2(v8) delta 0.001 CPU, 2 facets, 0 merges, 4 hyperplanes, 30 distplanes, 0 retries 1224:[QH1040]qh_findhorizon: find horizon for point 1491:[QH2056]qh_addpoint: added p8 to convex hull with point balance -0.33 1494:[QH1049]qh_addpoint: add p4(v10) 0.073 above f13 to hull of 14 facets, 0 merges, 1 outside at 0.003 CPU secs. Previous p8(v9) delta 0 CPU, 2 facets, 0 merges, 4 hyperplanes, 30 distplanes, 0 retries 1495:[QH1040]qh_findhorizon: find horizon for point 1761:[QH2056]qh_addpoint: added p4 to convex hull with point balance 0 1861:qh_maxouter: max distance from facet to outer plane is 1.571e-15, qh.max_outside is 9.714e-17 == qtest.sh grep-step 'qhull.log' >qhull-step.log qtest.sh: grep step log from 'qhull.log' to stdout 2:[QH1008]qh_readpoints: read in 10 3-dimensional points 3:[QH0013]qh_initqhull_globals: for rbox 10 | qhull T4z QR123456 4:[QH2005]qh_initqhull_globals: initialize globals. input_dim 3, numpoints 10, malloc? 1, projected 0 to hull_dim 3 5:[QH3024]qh_initqhull_outputflags: qhull T4z QR123456 7:[QH3078]qh_memsize: quick memory of 32 bytes 8:[QH3078]qh_memsize: quick memory of 24 bytes 9:[QH3078]qh_memsize: quick memory of 48 bytes 10:[QH3078]qh_memsize: quick memory of 88 bytes 11:[QH3078]qh_memsize: quick memory of 16 bytes 12:[QH3078]qh_memsize: quick memory of 24 bytes qhull-step.log 1851: 1852: Number of vertices: 10 1853: Number of facets: 16 1854: 1855:Statistics for: rbox 10 | qhull T4z QR123456 QR123456 1856: 1857: Number of points processed: 10 1858: Number of hyperplanes created: 27 1859: Number of distance tests for qhull: 45 1860: CPU seconds to compute hull (after input): 0.004 == qtest.sh -v -3 'rbox 10 | qhull' Testing -- rbox 10 | qhull >/d/bash/var/tmp/qtest-2020-07-24/qhull-198775.log qtest.sh: rbox 10 | qhull QR1 Tsz | grep -E 'QH[67]| Statis|[0-9][0-9][.][0-9]x|CPU|FIXUP|retries, input joggled|initial hull is narrow' | grep -Ev 'keep 239874664' | tee -a '/d/bash/var/tmp/qtest-2020-07-24/qhull-198775.log' | grep -E '.' | grep -Ev 'QH7[0-9][^8]|Stati' | tee -a '/d/bash/var/tmp/qtest-2020-07-24/qhull-198775-show.log' QH_TEST_DEST='/d/bash/var/tmp/qtest-2020-07-24/qhull-198775.log' QH_SHOW_DEST='/d/bash/var/tmp/qtest-2020-07-24/qhull-198775-show.log' QH_TEST_GREP='QH[67]| Statis|[0-9][0-9][.][0-9]x|CPU|FIXUP|retries, input joggled|initial hull is narrow' QH_SHOW_GREPX='QH7[0-9][^8]|Stati' QH_TEST='' QH_TESTX='' QH_SHOW='' QH_SHOWX='' Test -- QR1 CPU seconds to compute hull (after input): 0 Test -- QR2 CPU seconds to compute hull (after input): 0 Test -- QR3 CPU seconds to compute hull (after input): 0 1595644076 Test 3 runs in 0 seconds (average 0 msec) -- rbox 10 | qhull ============================ === test qtest.sh errors === ============================ == qtest.sh run -3 'rbox 10 | qhull' QH7094 qhull option warning: unknown option 'r'(72) QH7036 qhull option warning: missing space after option 'r'(72), reserved for sub-options, ignoring 'r' options to next space QH7094 qhull option warning: unknown option '1'(31) QH7036 qhull option warning: missing space after option '1'(31), reserved for sub-options, ignoring '1' options to next space QH7094 qhull option warning: unknown option '|'(7c) QH7094 qhull option warning: unknown option 'q'(71) QH7036 qhull option warning: missing space after option 'q'(71), reserved for sub-options, ignoring 'q' options to next space QH6035 qhull option error: see previous warnings, use 'Qw' to override: 'qhull rbox 10 | qhull' (last offset 16) While executing: | qhull rbox 10 | qhull Options selected for Qhull 2020.2.r 2020/07/24: run-id 214218403 _maxoutside 0 == qtest.sh run 3 '10' '' qtest.sh: Expecting 'run' followed by 'tNNN rbox-args qhull-args'. See 'qtest.sh help' == qtest.sh run '10' '' Convex hull of 10 points in 3-d: Number of vertices: 10 Number of facets: 16 Statistics for: rbox 10 | qhull Number of points processed: 10 Number of hyperplanes created: 26 Number of distance tests for qhull: 43 CPU seconds to compute hull (after input): 0 == qtest.sh run qtest.sh: Expecting 'run' followed by 1 to 3 arguments. Got total of 1 arguments. See 'qtest.sh help' == qtest.sh 3 '10' d T4 qtest.sh: Expecting 1 to 3 arguments. Got 4 arguments. See 'qtest.sh help' == qtest.sh 3 '10' 'd H' Testing -- rbox 10 t332683 | qhull d H >/d/bash/var/tmp/qtest-2020-07-24/qhull-332683.log QH6037 qhull option error (qh_readpoints): can not use Delaunay('d') or Voronoi('v') with halfspace intersection('H') While executing: rbox 20 | qhull d H TA1 Options selected for Qhull 2020.2.r 2020/07/24: run-id 214252017 delaunay Halfspace TA-stop-add 1 _maxoutside 0 qtest.sh error: 'rbox 20 | qhull d H TA1' failed == qtest.sh 3 qtest.sh: Expecting run count followed by rbox and qhull options. Only run count provided (3). == qtest.sh grep qtest.sh: Expecting 'grep' followed by include and exclude regexps or $QH_GREP or $QH_GREPX. None defined. == qtest.sh grep-merge '10' 'v' qtest.sh: Expecting 'grep-merge' followed by log file. Got 'grep-merge 10 v ...' == qtest.sh grep-merge qtest.sh: Expecting 'grep-merge' followed by log file. Got 'grep-merge ...' == qtest.sh grep-merge not-a-file qtest.sh: Expecting 'grep-merge' followed by log file. Got 'grep-merge not-a-file ...' == qtest.sh grep-step '10' 'v' qtest.sh: Expecting 'grep-step' followed by log file. Got 'grep-step 10 v ...' == qtest.sh grep-step qtest.sh: Expecting 'grep-step' followed by log file. Got 'grep-step ...' == qtest.sh grep-step not-a-file qtest.sh: Expecting 'grep-step' followed by log file. Got 'grep-step not-a-file ...' == qtest.sh log '10' 'd' qtest.sh: Expecting 'log' followed by a qhull command line in quotes. Got 3 arguments == qtest.sh t34 qtest.sh: Expecting txxxxxx followed by rbox and qhull options. Got tag 't34' only == qtest.sh t34 'rbox 10 | qhull' qtest.sh: Expecting txxxxxx followed by rbox and qhull options. Tag 't34' was followed by a qhull command -- rbox 10 | qhull == qtest.sh QR34 qtest.sh: Expecting QRxxxxxx followed by a qhull command. Got tag 'QR34' only == qtest.sh QR34 '10' 'v' qtest.sh: Expecting QRxxxxxx followed by a qhull command. Got rbox options '10' and qhull options 'v' == qtest.sh t34 '10 ZERROR' 'v' qtest.sh: logging 'rbox 10 ZERROR t34 | qhull T4sz v' to 'qhull.log' and 'qhull-step.log' QH6353 rbox error: missing space between flags at ERROR t34 1000. qtest.sh error: 'rbox 10 ZERROR t34' failed == Delete temporary log files ghull.log, qhull-grep.log, and qhull-step.log ============================== === N_PRECISION test cases === ============================== == difficult cases for qhull Fri, Jul 24, 2020 10:28:05 PM ==================== == Convex hull of fuzzy cube (large flat facets) ==================== Testing -- rbox 1000000 W1e-13 D2 t67022 | qhull Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-67022.log Test -- t67022 CPU seconds to compute hull (after input): 0.261 Testing -- rbox 500000 W1e-13 D3 t200930 | qhull Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-200930.log Test -- t200930 CPU seconds to compute hull (after input): 0.659 Testing -- rbox 10000 W1e-13 D4 t935269 | qhull Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-935269.log Test -- t935269 CPU seconds to compute hull (after input): 0.104 Testing -- rbox 2000 W1e-13 D5 t2223 | qhull Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-2223.log Test -- t2223 CPU seconds to compute hull (after input): 0.584 Testing -- rbox 1000 W1e-13 D6 t69177 | qhull Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-69177.log Test -- t69177 CPU seconds to compute hull (after input): 2.013 ==================== == narrow lense ==================== Testing -- rbox 1000000 L100000 s G1e-6 D2 t203085 | qhull Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-203085.log Test -- t203085 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.188 Testing -- rbox 10000 L100000 s G1e-6 D3 t336993 | qhull Q12 Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-336993.log Test -- t336993 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.689 Testing -- rbox 5000 L100000 s G1e-6 D4 t937424 | qhull Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-937424.log Test -- t937424 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.599 Testing -- rbox 1000 L100000 s G1e-6 D5 t537855 | qhull Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-537855.log Test -- t537855 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.216 Testing -- rbox 400 L100000 s G1e-6 D6 t604809 | qhull Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-604809.log Test -- t604809 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.494 ==================== == cone ==================== Testing -- rbox 100000 s Z1 G1e-13 D2 t671763 | qhull Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-671763.log Test -- t671763 CPU seconds to compute hull (after input): 0.02 Testing -- rbox 10000 s Z1 G1e-13 D3 t205240 | qhull Q12 Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-205240.log Test -- t205240 CPU seconds to compute hull (after input): 0.603 Testing -- rbox 2000 s Z1 G1e-13 D4 t339148 | qhull Q12 Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-339148.log Test -- t339148 CPU seconds to compute hull (after input): 3.031 Testing -- rbox 1000 s Z1 G1e-13 D5 t473056 | qhull Q12 Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-473056.log Test -- t473056 CPU seconds to compute hull (after input): 0.599 Testing -- rbox 400 s Z1 G1e-13 D6 t540010 | qhull Q12 Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-540010.log Test -- t540010 QH6271 qhull topology error (qh_check_dupridge): wide merge (1662534044043.3x wider) due to dupridge between f3740 and f124 (vertex dist 0.11), merge dist 0.48, while processing p68 QH6227 qhull topology error: Only 7 facets remain. The input is too degenerate or the convexity constraints are too strong. Maximum distance of point above facet: 0.26 (10708130307576.8x) Maximum distance of vertex below facet: -0.54 (22117535651526.7x) ========================== === N_OTHER test cases === ========================== ==================== == Delaunay triangulation of fuzzy circle (large, narrow disk) == No Qbb, highly degenerate due to narrow disk of two cospherical sets of points ==================== Testing -- rbox 10000 s W1e-13 D2 t606964 | qhull d Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-606964.log Test -- t606964 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.527 Maximum distance of point above facet: 1.1e-12 (191.6x) Testing -- rbox 2000 s W1e-13 D3 t207395 | qhull d Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-207395.log Test -- t207395 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6347 qhull precision error (qh_mergefacet): wide merge for facet f8586 into f5812 for mergetype 6 (flip). maxdist 0 (0.0x) mindist -1.8e-12 (178.9x) vertexdist 0.054 Allow with 'Q12' (allow-wide) Maximum distance of point above facet: 3.2e-13 (31.3x) Maximum distance of vertex below facet: -1.3e-13 (12.7x) Testing -- rbox 1000 s W1e-13 D4 t274349 | qhull d Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-274349.log Test -- t274349 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7086 Qhull precision warning: repartition coplanar point p819 from f106 as an outside point above hidden facet f64145 dist 7e-12 nearest vertices 0.11 CPU seconds to compute hull (after input): 0.994 Maximum distance of point above facet: 1.9e-12 (114.1x) Testing -- rbox 200 s W1e-13 D5 t341303 | qhull d Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-341303.log Test -- t341303 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.304 Maximum distance of point above facet: 2.8e-13 (12.0x) Testing -- rbox 100 s W1e-13 D6 t408257 | qhull d Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-408257.log Test -- t408257 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6227 qhull topology error: Only 8 facets remain. The input is too degenerate or the convexity constraints are too strong. =========================================================== === N_PINCHED test cases for Q14-merge-pinched-vertices === =========================================================== ==================== == Convex hull of fuzzy cube with point pairs (large flat facets) ==================== Testing -- rbox 1000000 W1e-13 C1,2e-13 D2 t475211 | qhull Q14 Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-475211.log Test -- t475211 CPU seconds to compute hull (after input): 0.355 Testing -- rbox 500000 W1e-13 C1,2e-13 D3 t209550 | qhull Q14 Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-209550.log Test -- t209550 CPU seconds to compute hull (after input): 0.645 Testing -- rbox 20000 W1e-13 C1,2e-13 D4 t745182 | qhull Q14 Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-745182.log Test -- t745182 CPU seconds to compute hull (after input): 0.205 Testing -- rbox 2000 W1e-13 C1,2e-13 D5 t879090 | qhull Q14 Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-879090.log Test -- t879090 QH6271 qhull topology error (qh_check_dupridge): wide merge (114884573208.0x wider) due to dupridge between f95160 and f95159 (vertex dist 2.4e-13), merge dist 0.008, while processing p2645 Testing -- rbox 500 W1e-13 C1,2e-13 D6 t946044 | qhull Q14 Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-946044.log Test -- t946044 QH6347 qhull precision error (qh_mergefacet): wide merge for facet f253245 into f252997 for mergetype 7 (dupridge). maxdist 0 (0.0x) mindist -5.7e-12 (231.7x) vertexdist 0.44 Allow with 'Q12' (allow-wide) Maximum distance of point above facet: 3.3e-13 (13.4x) ==================== == Convex hull of cube with point pairs (large flat facets) ==================== Testing -- rbox 1000000 W0 C1,2e-13 D2 t12998 | qhull Q14 Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-12998.log Test -- t12998 CPU seconds to compute hull (after input): 0.345 Testing -- rbox 100000 W0 C1,2e-13 D3 t747337 | qhull Q14 Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-747337.log Test -- t747337 CPU seconds to compute hull (after input): 0.092 Testing -- rbox 5000 W0 C1,2e-13 D4 t347768 | qhull Q14 Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-347768.log Test -- t347768 CPU seconds to compute hull (after input): 0.051 Testing -- rbox 1000 W0 C1,2e-13 D5 t881245 | qhull Q14 Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-881245.log Test -- t881245 CPU seconds to compute hull (after input): 0.189 Testing -- rbox 500 W0 C1,2e-13 D6 t948199 | qhull Q14 Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-948199.log Test -- t948199 QH6271 qhull topology error (qh_check_dupridge): wide merge (382263037091.0x wider) due to dupridge between f319376 and f320185 (vertex dist 2.4e-13), merge dist 0.21, while processing p208 Maximum distance of point above facet: 5.4e-13 (22.1x) Maximum distance of vertex below facet: -7.3e-13 (29.5x) ==================== == Delaunay triangulation of point pairs (large upper facet) == Difficult case due to large upper facet with nearly adjacent vertices == A bounding box helps avoid this case, see TIME_DELAUNAY_PAIRS ==================== Testing -- rbox 100000 C1,2e-13 D2 t548630 | qhull Q14 d Qbb >/d/bash/var/tmp/qtest-2020-07-24/qhull-548630.log Test -- t548630 CPU seconds to compute hull (after input): 1.306 Testing -- rbox 10000 C1,2e-13 D3 t149061 | qhull Q14 d Qbb Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-149061.log Test -- t149061 CPU seconds to compute hull (after input): 0.657 Testing -- rbox 500 C1,2e-13 D4 t684693 | qhull Q14 d Qbb Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-684693.log Test -- t684693 QH6271 qhull topology error (qh_check_dupridge): wide merge (37732005938.4x wider) due to dupridge between f52566 and f52538 (vertex dist 2.3e-13), merge dist 0.0032, while processing p553 Testing -- rbox 200 C1,2e-13 D5 t751647 | qhull Q14 d Qbb Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-751647.log Test -- t751647 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r108296 and r108302. Nearest v293 and v387 dist 0.16 (7021422850377.3x) Testing -- rbox 100 C1,2e-13 D6 t285124 | qhull Q14 d Qbb Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-285124.log Test -- t285124 CPU seconds to compute hull (after input): 1.292 ==================== == Delaunay triangulation of point quads (2e-13, large upper facet) == Difficult case due to large upper facet with many nearly adjacent vertices ==================== Testing -- rbox 50000 C3,2e-13 D2 t885555 | qhull Q14 d Qbb >/d/bash/var/tmp/qtest-2020-07-24/qhull-885555.log Test -- t885555 CPU seconds to compute hull (after input): 0.846 Testing -- rbox 10000 C3,2e-13 D3 t485986 | qhull Q14 d Qbb >/d/bash/var/tmp/qtest-2020-07-24/qhull-485986.log Test -- t485986 QH6348 qhull precision error (qh_mergefacet): wide merge for pinched facet f179300 into f83347 for mergetype 3 (concave). maxdist 0 (0x) mindist -0.00015 (15229327719.9x) vertexdist 1.1e-13 Allow with 'Q12' (allow-wide) Testing -- rbox 200 C3,2e-13 D4 t552940 | qhull Q14 d Qbb Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-552940.log Test -- t552940 QH6348 qhull precision error (qh_mergefacet): wide merge for pinched facet f17712 into f17726 for mergetype 10 (degen). maxdist 0 (0x) mindist -0.0021 (128521499042.8x) vertexdist 3e-13 Allow with 'Q12' (allow-wide) Testing -- rbox 100 C3,2e-13 D5 t86417 | qhull Q14 d Qbb Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-86417.log Test -- t86417 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f66306 and f66308 have the same vertices (skip 1, skip 1) and same horizon ridges to f52073 and f55106 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f66306 and f66308 have the same vertices (skip 2, skip 2) and same horizon ridges to f52073 and f55106 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f66306 and f66308 have the same vertices (skip 4, skip 4) and same horizon ridges to f52073 and f55106 QH7084 qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f66306 and f66308 have the same vertices (skip 5, skip 5) and same horizon ridges to f52073 and f55106 QH6155 qhull topology error (qh_matchdupridge): missing qh_DUPLICATEridge at f66308 skip 4 for new f66306 skip 4 hash 3265 ismatch 1. Set by qh_matchneighbor Maximum distance of point above facet: 3.7e-13 (15.0x) Testing -- rbox 100 C3,2e-13 D6 t619894 | qhull Q14 d Qbb Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-619894.log Test -- t619894 QH6425 Qhull topology error (qh_partitioncoplanar): can not repartition coplanar point p360 from f389002 as outside point above f503604. It previously failed to form a cone of facets, dist 0.00014, nearest vertices 3.3e-13 Maximum distance of point above facet: 5.3e-13 (15.3x) ==================== == Delaunay triangulation of fuzzy circle with pairs (large, narrow disk) == Highly degenerate due to narrow disk of two cospherical sets of point pairs == Worse with Qbb since it stretches out the paraboloid, doubling _one-merge ==================== Testing -- rbox 10000 s W1e-13 C1,1e-13 D2 t753802 | qhull Q14 d Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-753802.log Test -- t753802 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH7085 Qhull precision warning: repartition coplanar point p13605 from f33398 as an outside point above twisted facet f33398 dist 1.5e-08 nearest vertices 8.5e-14 QH7085 Qhull precision warning: repartition coplanar point p3161 from f46136 as an outside point above twisted facet f46131 dist 1.7e-09 nearest vertices 1.5e-13 QH7085 Qhull precision warning: repartition coplanar point p13717 from f34469 as an outside point above twisted facet f59096 dist 1.9e-09 nearest vertices 5.3e-14 CPU seconds to compute hull (after input): 0.161 Maximum distance of point above facet: 5.8e-14 (10.4x) Testing -- rbox 5000 s W1e-13 C1,1e-13 D3 t488141 | qhull Q14 d Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-488141.log Test -- t488141 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.606 Testing -- rbox 500 s W1e-13 C1,1e-13 D4 t155526 | qhull Q14 d Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-155526.log Test -- t155526 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower CPU seconds to compute hull (after input): 0.318 Testing -- rbox 200 s W1e-13 C1,1e-13 D5 t222480 | qhull Q14 d Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-222480.log Test -- t222480 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r81322 and r81457. Nearest v137 and v201 dist 0.21 (9398058245899.0x) Testing -- rbox 100 s W1e-13 C1,1e-13 D6 t289434 | qhull Q14 d Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-289434.log Test -- t289434 QH7089 qhull precision warning: The initial hull is narrow. Is the input lower QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r41099 and r40865. Nearest v8 and v45 dist 0.22 (7248633393770.0x) ==================== == Voronoi diagram of rotated mesh with wide, 1e-8 pairs == All fail at C1,1e-12 ==================== Testing -- rbox 10000 M3,4 C1,1e-8 D2 t822911 | qhull QR3 Q14 v Qbb Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-822911.log Test -- t822911 CPU seconds to compute hull (after input): 0.152 Testing -- rbox 2000 M3,4,5 C1,1e-8 D3 t157681 | qhull QR3 Q14 v Qbb Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-157681.log Test -- t157681 QH7081 qhull precision warning (qh_getpinchedmerges): pinched vertices v910 and v456 (dist 8.1e-09, 3294x) would produce a wide merge for f40800 and f40814. Will merge dupridge instead QH6271 qhull topology error (qh_check_dupridge): wide merge (417465268.1x wider) due to dupridge between f40800 and f40814 (vertex dist 8.1e-09), merge dist 0.001, while processing p3608 Testing -- rbox 600 M3,4,5 C1,1e-8 D4 t691158 | qhull QR3 Q14 v Qbb Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-691158.log Test -- t691158 CPU seconds to compute hull (after input): 0.258 Testing -- rbox 300 M3,4,5 C1,1e-8 D5 t758112 | qhull QR3 Q14 v Qbb Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-758112.log Test -- t758112 CPU seconds to compute hull (after input): 0.902 skip D6, millions of vertices ============================ == Delaunay triangulation of nearly cospherical point pairs with Qbb drum == Qbb makes this the most difficult distribution for Qhull, only 100 points ============================ Testing -- rbox 1000 s C1,1e-13 D3 t358543 | qhull Q14 d Qbb Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-358543.log Test -- t358543 CPU seconds to compute hull (after input): 0.052 Testing -- rbox 100 s C1,1e-13 D4 t425497 | qhull Q14 d Qbb Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-425497.log Test -- t425497 CPU seconds to compute hull (after input): 0.023 Testing -- rbox 50 s C1,1e-13 D5 t958974 | qhull Q14 d Qbb Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-958974.log Test -- t958974 QH7081 qhull precision warning (qh_getpinchedmerges): pinched vertices v65 and v49 (dist 0.0034, 139424997685x) would produce a wide merge for f11052 and f11054. Will merge dupridge instead QH6271 qhull topology error (qh_check_dupridge): wide merge (322371235117.8x wider) due to dupridge between f11052 and f11054 (vertex dist 0.0034), merge dist 0.0078, while processing p50 Testing -- rbox 50 s C1,1e-13 D6 t492451 | qhull Q14 d Qbb Tv >/d/bash/var/tmp/qtest-2020-07-24/qhull-492451.log Test -- t492451 QH6271 qhull topology error (qh_check_dupridge): wide merge (33307682655.3x wider) due to dupridge between f19365 and f19401 (vertex dist 0.011), merge dist 0.001, while processing p18 ============================ == Time for pinched Delaunay triangulation of random point pairs (Q14) with bounding box ============================ Testing -- rbox 50000 C1,2e-13 c G2.0 D2 t559405 | qhull Q14 d Qbb >/d/bash/var/tmp/qtest-2020-07-24/qhull-559405.log Test -- t559405 CPU seconds to compute hull (after input): 0.641 Testing -- rbox 10000 C1,2e-13 c G2.0 D3 t626359 | qhull Q14 d Qbb >/d/bash/var/tmp/qtest-2020-07-24/qhull-626359.log Test -- t626359 CPU seconds to compute hull (after input): 0.456 Testing -- rbox 3000 C1,2e-13 c G2.0 D4 t693313 | qhull Q14 d Qbb >/d/bash/var/tmp/qtest-2020-07-24/qhull-693313.log Test -- t693313 QH7085 Qhull precision warning: repartition coplanar point p5346 from f250733 as an outside point above twisted facet f250738 dist 0.00038 nearest vertices 2.5e-13 CPU seconds to compute hull (after input): 1.179 Testing -- rbox 500 C1,2e-13 c G2.0 D5 t760267 | qhull Q14 d Qbb >/d/bash/var/tmp/qtest-2020-07-24/qhull-760267.log Test -- t760267 CPU seconds to compute hull (after input): 1.176 Testing -- rbox 100 C1,2e-13 c G2.0 D6 t360698 | qhull Q14 d Qbb >/d/bash/var/tmp/qtest-2020-07-24/qhull-360698.log Test -- t360698 QH6381 qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r88304 and r87884. Nearest v82 and v86 dist 0.61 (4668353828614.3x) ============================ == Time for pinched Delaunay triangulation of random point pairs (Q14, Q12) == qh_next_facetmerge, qh_findbesthorizon (qh_distplane) ============================ Testing -- rbox 50000 C1,2e-13 D2 t427652 | qhull Q14 d Qbb >/d/bash/var/tmp/qtest-2020-07-24/qhull-427652.log Test -- t427652 CPU seconds to compute hull (after input): 0.548 Testing -- rbox 5000 C1,2e-13 D3 t494606 | qhull Q14 d Qbb >/d/bash/var/tmp/qtest-2020-07-24/qhull-494606.log Test -- t494606 CPU seconds to compute hull (after input): 0.461 Maximum distance of point above facet: 1.6e-13 (15.6x) Maximum distance of vertex below facet: -1.3e-13 (13.2x) Testing -- rbox 500 C1,2e-13 D4 t561560 | qhull Q12 Q14 d Qbb >/d/bash/var/tmp/qtest-2020-07-24/qhull-561560.log Test -- t561560 QH6271 qhull topology error (qh_check_dupridge): wide merge (231733071381.3x wider) due to dupridge between f76307 and f76302 (vertex dist 2.4e-13), merge dist 0.02, while processing p507 CPU seconds to compute hull (after input): 0.345 Maximum distance of point above facet: 2e-13 (12.3x) Maximum distance of vertex below facet: -2.1e-13 (12.9x) Testing -- rbox 300 C1,2e-13 D5 t95037 | qhull Q12 Q14 d Qbb >/d/bash/var/tmp/qtest-2020-07-24/qhull-95037.log Test -- t95037 QH6271 qhull topology error (qh_check_dupridge): wide merge (80235921958.0x wider) due to dupridge between f243374 and f243379 (vertex dist 2.1e-13), merge dist 0.018, while processing p428 CPU seconds to compute hull (after input): 1.498 Maximum distance of point above facet: 3.3e-13 (13.3x) Maximum distance of vertex below facet: -3.3e-13 (13.5x) Testing -- rbox 100 C1,2e-13 D6 t695468 | qhull Q14 d Qbb >/d/bash/var/tmp/qtest-2020-07-24/qhull-695468.log Test -- t695468 CPU seconds to compute hull (after input): 1.234 =========================== === N_TIMING test cases === =========================== ============================ == Time for random points in a cube ============================ Testing -- rbox 1000000 D2 t295899 | qhull >/d/bash/var/tmp/qtest-2020-07-24/qhull-295899.log Test -- t295899 CPU seconds to compute hull (after input): 0.114 Testing -- rbox 500000 D3 t429807 | qhull >/d/bash/var/tmp/qtest-2020-07-24/qhull-429807.log Test -- t429807 CPU seconds to compute hull (after input): 0.14 Testing -- rbox 200000 D4 t563715 | qhull >/d/bash/var/tmp/qtest-2020-07-24/qhull-563715.log Test -- t563715 CPU seconds to compute hull (after input): 0.192 Testing -- rbox 100000 D5 t630669 | qhull Q12 >/d/bash/var/tmp/qtest-2020-07-24/qhull-630669.log Test -- t630669 CPU seconds to compute hull (after input): 0.774 Testing -- rbox 3000 D6 t231100 | qhull >/d/bash/var/tmp/qtest-2020-07-24/qhull-231100.log Test -- t231100 CPU seconds to compute hull (after input): 1.059 ============================ == Time for random cospherical points ============================ Testing -- rbox 100000 s D2 t298054 | qhull >/d/bash/var/tmp/qtest-2020-07-24/qhull-298054.log Test -- t298054 CPU seconds to compute hull (after input): 0.287 Testing -- rbox 100000 s D3 t365008 | qhull >/d/bash/var/tmp/qtest-2020-07-24/qhull-365008.log Test -- t365008 CPU seconds to compute hull (after input): 0.521 Testing -- rbox 50000 s D4 t431962 | qhull >/d/bash/var/tmp/qtest-2020-07-24/qhull-431962.log Test -- t431962 CPU seconds to compute hull (after input): 1.199 == Repeat with qconvex, bin/qconvex is built with libqhull instead of libqhull_r Testing -- rbox 50000 s D4 t32393 | qconvex >/d/bash/var/tmp/qtest-2020-07-24/qhull-32393.log Test -- t32393 CPU seconds to compute hull (after input): 1.251 Testing -- rbox 10000 s D5 t632824 | qhull >/d/bash/var/tmp/qtest-2020-07-24/qhull-632824.log Test -- t632824 CPU seconds to compute hull (after input): 1.498 Testing -- rbox 1000 s D6 t233255 | qhull >/d/bash/var/tmp/qtest-2020-07-24/qhull-233255.log Test -- t233255 CPU seconds to compute hull (after input): 0.747 ============================ == Time for extreme post-merge of random cospherical points ============================ Testing -- rbox 100000 s D2 t833686 | qhull C0.01 >/d/bash/var/tmp/qtest-2020-07-24/qhull-833686.log Test -- t833686 CPU seconds to compute hull (after input): 0.657 Testing -- rbox 10000 s D3 t900640 | qhull C0.01 >/d/bash/var/tmp/qtest-2020-07-24/qhull-900640.log Test -- t900640 CPU seconds to compute hull (after input): 0.185 Testing -- rbox 5000 s D4 t967594 | qhull C0.01 >/d/bash/var/tmp/qtest-2020-07-24/qhull-967594.log Test -- t967594 CPU seconds to compute hull (after input): 0.422 == Repeat with qconvex, bin/qconvex is built with libqhull instead of libqhull_r Testing -- rbox 5000 s D4 t34548 | qconvex C0.01 >/d/bash/var/tmp/qtest-2020-07-24/qhull-34548.log Test -- t34548 CPU seconds to compute hull (after input): 0.438 Testing -- rbox 2000 s D5 t568025 | qhull C0.01 >/d/bash/var/tmp/qtest-2020-07-24/qhull-568025.log Test -- t568025 CPU seconds to compute hull (after input): 0.989 Testing -- rbox 500 s D6 t168456 | qhull C0.01 >/d/bash/var/tmp/qtest-2020-07-24/qhull-168456.log Test -- t168456 CPU seconds to compute hull (after input): 1.015 ============================ == Time for rotated cubical points with large merged facets ============================ Testing -- rbox 5000000 W0 D2 t235410 | qhull QR3 >/d/bash/var/tmp/qtest-2020-07-24/qhull-235410.log Test -- t235410 CPU seconds to compute hull (after input): 0.879 Testing -- rbox 1000000 W0 D3 t103657 | qhull QR3 >/d/bash/var/tmp/qtest-2020-07-24/qhull-103657.log Test -- t103657 CPU seconds to compute hull (after input): 0.686 Testing -- rbox 100000 W0 D4 t771042 | qhull QR3 >/d/bash/var/tmp/qtest-2020-07-24/qhull-771042.log Test -- t771042 CPU seconds to compute hull (after input): 0.477 Testing -- rbox 10000 W0 D5 t837996 | qhull QR3 >/d/bash/var/tmp/qtest-2020-07-24/qhull-837996.log Test -- t837996 CPU seconds to compute hull (after input): 0.742 Testing -- rbox 1000 W0 D6 t371473 | qhull QR3 >/d/bash/var/tmp/qtest-2020-07-24/qhull-371473.log Test -- t371473 CPU seconds to compute hull (after input): 0.941 ============================ == Time for joggled, rotated cubical points with multiple retries ============================ Testing -- rbox 5000000 W0 D2 t971904 | qhull QR3 QJ >/d/bash/var/tmp/qtest-2020-07-24/qhull-971904.log Test -- t971904 CPU seconds to compute hull (after input): 0.808 Testing -- rbox 1000000 W0 D3 t840151 | qhull QR3 QJ >/d/bash/var/tmp/qtest-2020-07-24/qhull-840151.log Test -- t840151 CPU seconds to compute hull (after input): 1.002 After 1 retries, input joggled by: 3.5e-11 Testing -- rbox 100000 W0 D4 t507536 | qhull QR3 QJ >/d/bash/var/tmp/qtest-2020-07-24/qhull-507536.log Test -- t507536 CPU seconds to compute hull (after input): 0.458 After 3 retries, input joggled by: 5.7e-09 Testing -- rbox 10000 W0 D5 t574490 | qhull QR3 QJ >/d/bash/var/tmp/qtest-2020-07-24/qhull-574490.log Test -- t574490 CPU seconds to compute hull (after input): 0.651 After 3 retries, input joggled by: 8.2e-09 Testing -- rbox 1000 W0 D6 t641444 | qhull QR3 QJ >/d/bash/var/tmp/qtest-2020-07-24/qhull-641444.log Test -- t641444 CPU seconds to compute hull (after input): 1.17 After 2 retries, input joggled by: 1.1e-09 ============================ == Time for joggled, nearly cubical points ============================ Testing -- rbox 1000000 W1e-13 D2 t708398 | qhull QJ >/d/bash/var/tmp/qtest-2020-07-24/qhull-708398.log Test -- t708398 CPU seconds to compute hull (after input): 0.166 Testing -- rbox 500000 W1e-13 D3 t308829 | qhull QJ >/d/bash/var/tmp/qtest-2020-07-24/qhull-308829.log Test -- t308829 CPU seconds to compute hull (after input): 1.447 After 4 retries, input joggled by: 2.1e-08 Testing -- rbox 100000 W1e-13 D4 t976214 | qhull QJ >/d/bash/var/tmp/qtest-2020-07-24/qhull-976214.log Test -- t976214 CPU seconds to compute hull (after input): 0.483 After 3 retries, input joggled by: 3e-09 Testing -- rbox 10000 W1e-13 D5 t43168 | qhull QJ >/d/bash/var/tmp/qtest-2020-07-24/qhull-43168.log Test -- t43168 CPU seconds to compute hull (after input): 0.635 After 3 retries, input joggled by: 4.1e-09 Testing -- rbox 1000 W1e-13 D6 t576645 | qhull QJ >/d/bash/var/tmp/qtest-2020-07-24/qhull-576645.log Test -- t576645 CPU seconds to compute hull (after input): 1.025 After 3 retries, input joggled by: 5.3e-09 ============================ == Time for merging nearly cubical points ============================ Testing -- rbox 1000000 W1e-13 D2 t177076 | qhull >/d/bash/var/tmp/qtest-2020-07-24/qhull-177076.log Test -- t177076 CPU seconds to compute hull (after input): 0.21 Testing -- rbox 1000000 W1e-13 D3 t310984 | qhull >/d/bash/var/tmp/qtest-2020-07-24/qhull-310984.log Test -- t310984 CPU seconds to compute hull (after input): 1.573 Testing -- rbox 100000 W1e-13 D4 t511846 | qhull Q12 >/d/bash/var/tmp/qtest-2020-07-24/qhull-511846.log Test -- t511846 CPU seconds to compute hull (after input): 1.446 Testing -- rbox 2000 W1e-13 D5 t112277 | qhull Q12 >/d/bash/var/tmp/qtest-2020-07-24/qhull-112277.log Test -- t112277 CPU seconds to compute hull (after input): 0.652 Testing -- rbox 500 W1e-13 D6 t179231 | qhull >/d/bash/var/tmp/qtest-2020-07-24/qhull-179231.log Test -- t179231 CPU seconds to compute hull (after input): 0.52 ============================ == Time for Delaunay triangulation of random points == qh_findbesthorizon, qh_distplane, qh_update_vertexneighbors_cone, qh_makenew_simplicial ============================ Testing -- rbox 100000 D2 t246185 | qhull d Qbb Qz >/d/bash/var/tmp/qtest-2020-07-24/qhull-246185.log Test -- t246185 CPU seconds to compute hull (after input): 0.791 Testing -- rbox 50000 D3 t846616 | qhull d Qbb Qz >/d/bash/var/tmp/qtest-2020-07-24/qhull-846616.log Test -- t846616 CPU seconds to compute hull (after input): 1.818 Testing -- rbox 10000 D4 t447047 | qhull d Qbb Qz >/d/bash/var/tmp/qtest-2020-07-24/qhull-447047.log Test -- t447047 CPU seconds to compute hull (after input): 1.502 Testing -- rbox 1000 D5 t580955 | qhull d Qbb Qz >/d/bash/var/tmp/qtest-2020-07-24/qhull-580955.log Test -- t580955 CPU seconds to compute hull (after input): 0.68 Testing -- rbox 200 D6 t647909 | qhull d Qbb Qz >/d/bash/var/tmp/qtest-2020-07-24/qhull-647909.log Test -- t647909 CPU seconds to compute hull (after input): 0.471 ==================== == Time for Delaunay triangulation of regular mesh, integer coordinates ==================== Testing -- rbox 100000 M3,4 z D2 t714863 | qhull QR3 d Qt Qbb >/d/bash/var/tmp/qtest-2020-07-24/qhull-714863.log Test -- t714863 CPU seconds to compute hull (after input): 0.937 Testing -- rbox 20000 M3,4,5 z D3 t315294 | qhull QR3 d Qt Qbb >/d/bash/var/tmp/qtest-2020-07-24/qhull-315294.log Test -- t315294 CPU seconds to compute hull (after input): 1.055 Testing -- rbox 5000 M3,4,5 z D4 t382248 | qhull QR3 d Qt Qbb >/d/bash/var/tmp/qtest-2020-07-24/qhull-382248.log Test -- t382248 CPU seconds to compute hull (after input): 1.095 Testing -- rbox 1500 M3,4,5 z D5 t982679 | qhull QR3 d Qt Qbb >/d/bash/var/tmp/qtest-2020-07-24/qhull-982679.log Test -- t982679 CPU seconds to compute hull (after input): 1.073 Testing -- rbox 500 M3,4,5 z D6 t49633 | qhull QR3 d Qt Qbb >/d/bash/var/tmp/qtest-2020-07-24/qhull-49633.log Test -- t49633 CPU seconds to compute hull (after input): 0.857 ==================== == Time for Voronoi diagram of regular mesh ==================== Testing -- rbox 100000 M3,4 z D2 | qhull v Qbb >/d/bash/var/tmp/qtest-2020-07-24/qhull-650064.log Test -- QR650064 CPU seconds to compute hull (after input): 0.942 Testing -- rbox 20000 M3,4,5 z | qhull v Qbb >/d/bash/var/tmp/qtest-2020-07-24/qhull-250495.log Test -- QR250495 CPU seconds to compute hull (after input): 0.9 Testing -- rbox 5000 M3,4,5 z D4 | qhull v Qbb >/d/bash/var/tmp/qtest-2020-07-24/qhull-317449.log Test -- QR317449 CPU seconds to compute hull (after input): 1.037 Testing -- rbox 1500 M3,4,5 z D5 | qhull v Qbb >/d/bash/var/tmp/qtest-2020-07-24/qhull-384403.log Test -- QR384403 CPU seconds to compute hull (after input): 1.256 Testing -- rbox 500 M3,4,5 z D6 | qhull v Qbb >/d/bash/var/tmp/qtest-2020-07-24/qhull-451357.log Test -- QR451357 CPU seconds to compute hull (after input): 0.955 qhull-2020.2/eg/q_test.bat0000644060175106010010000007061013664610456013567 0ustar bbarberecho off echo q_test.bat -- writes output to q_test.x for comparison with eg/q_test-ok.txt echo echo Instructions: echo echo Launch QHULL-GO.bat echo " ..\eg\q_test.bat >q_test.x 2>&1 " echo echo Compare bin\q_test.x with ..\eg\q_test-ok.txt echo "========================" >q_test.x echo "== Run q_test.bat for Windows from the bin/ directory." echo "== Skips 'make test' and 'make qtest'" echo "== Align the next block with 'eg/q_test'" echo "========================" echo echo "==============================" echo "========= eg/q_test ==========" echo "== Check qhull programs ======" echo "==============================" echo echo "==============================" echo "== check user_eg, user_eg2, and user_eg3" echo "== errors if 'user_eg' and 'user_eg2' not found" echo "==============================" echo user_eg user_eg echo "user_eg 'QR1 p n Qt' 'v p' Fp" user_eg "QR1 p n Qt" "v p" Fp echo user_eg2 user_eg2 echo "user_eg2 'QR1 p' 'v p' Fp" user_eg2 "QR1 p" "v p" Fp echo user_eg3 user_eg3 echo user_eg3 eg-100 user_eg3 eg-100 echo user_eg3 eg-convex user_eg3 eg-convex echo user_eg3 eg-delaunay user_eg3 eg-delaunay echo user_eg3 eg-voronoi user_eg3 eg-voronoi echo user_eg3 eg-fifo user_eg3 eg-fifo echo user_eg3 rbox qhull user_eg3 rbox qhull echo user_eg3 rbox qhull T1 user_eg3 rbox qhull T1 echo user_eg3 rbox qhull d user_eg3 rbox qhull d echo user_eg3 rbox y c user_eg3 rbox y c echo 'user_eg3 rbox D2 10 2 "s r 5" qhull 's p' facets' user_eg3 rbox D2 10 2 "s r 5" qhull 's p' facets echo user_eg3 rbox "10 D2" eg-convex user_eg3 rbox "10 D2" eg-convex echo 'user_eg3 rbox "10 D2" qhull s eg-convex' user_eg3 rbox "10 D2" qhull s eg-convex echo 'user_eg3 rbox 10 eg-delaunay qhull "d o"' user_eg3 rbox 10 eg-delaunay qhull "d o" echo user_eg3 rbox D5 c P2 qhull d eg-delaunay user_eg3 rbox D5 c P2 qhull d eg-delaunay echo user_eg3 rbox "10 D2" eg-voronoi user_eg3 rbox "10 D2" eg-voronoi echo user_eg3 rbox "D5 c P2" qhull v eg-voronoi o user_eg3 rbox "D5 c P2" qhull v eg-voronoi o echo user_eg3 rbox "10 D2" eg-fifo user_eg3 rbox "10 D2" eg-fifo echo user_eg3 rbox "10 D2" qhull v eg-fifo p Fi Fo user_eg3 rbox "10 D2" qhull v eg-fifo p Fi Fo echo === check front ends ========================================================== echo "qconvex -" qconvex - echo "qconvex ." qconvex . echo "qconvex -?" qconvex -? # [mar'19] isatty does not work for Git for Windows echo "rbox c D3 | qconvex s n Qt" rbox c D3 | qconvex s n Qt echo "rbox c D2 | qconvex s i" rbox c D2 | qconvex s i echo "rbox c D2 | qconvex s n" rbox c D2 | qconvex s n echo "rbox c D2 | qconvex o" rbox c D2 | qconvex o echo "rbox 1000 s | qconvex s Tv FA" rbox 1000 s | qconvex s Tv FA echo "rbox c d D2 | qconvex s Qc Fx" rbox c d D2 | qconvex s Qc Fx echo "rbox y 1000 W0 | qconvex Qc s n" rbox y 1000 W0 | qconvex Qc s n echo "rbox y 1000 W0 | qconvex s QJ" rbox y 1000 W0 | qconvex s QJ echo "rbox d G1 D12 | qconvex QR0 FA" rbox d G1 D12 | qconvex QR0 FA echo "rbox c D6 | qconvex s FA TF500" rbox c D6 | qconvex s FA TF500 echo "rbox c D7 | qconvex s FA TF1000" rbox c D7 | qconvex s FA TF1000 echo "rbox d G1 D12 | qconvex QR0 FA Pp" rbox d G1 D12 | qconvex QR0 FA Pp echo "rbox c P0 d D2 | qconvex p Fa Fc FP FI Fn FN FS Fv Fx" rbox c P0 d D2 | qconvex p Fa Fc FP FI Fn FN FS Fv Fx echo "rbox c d D2 | qconvex s i QV0" rbox c d D2 | qconvex s i QV0 echo "rbox c | qconvex Q0" rbox c | qconvex Q0 echo "qvoronoi -" qvoronoi - echo "qvoronoi ." qvoronoi . echo "qvoronoi -?" qvoronoi -? # [mar'19] isatty does not work for Git for Windows echo "rbox c P0 D2 | qvoronoi s o" rbox c P0 D2 | qvoronoi s o echo "rbox c P0 D2 | qvoronoi Fi Tv" rbox c P0 D2 | qvoronoi Fi Tv echo "rbox c P0 D2 | qvoronoi Fo Tv" rbox c P0 D2 | qvoronoi Fo Tv echo "rbox c P0 D2 | qvoronoi Fv" rbox c P0 D2 | qvoronoi Fv echo "rbox c P0 D2 | qvoronoi s Qu Fv" rbox c P0 D2 | qvoronoi s Qu Fv echo "rbox c P0 D2 | qvoronoi s Qu Qt Fv" rbox c P0 D2 | qvoronoi s Qu Qt Fv echo "rbox c P0 D2 | qvoronoi Qu Fo" rbox c P0 D2 | qvoronoi Qu Fo echo "rbox c G1 d D2 | qvoronoi s p" rbox c G1 d D2 | qvoronoi s p echo "rbox c G1 d D2 | qvoronoi QJ p" rbox c G1 d D2 | qvoronoi QJ p echo "rbox c P-0.1 P+0.1 P+0.1 D2 | qvoronoi s Fc FP FQ Fn FN" rbox c P-0.1 P+0.1 P+0.1 D2 | qvoronoi s Fc FP FQ Fn FN echo "rbox P0 c D2 | qvoronoi s Fv QV0" rbox P0 c D2 | qvoronoi s Fv QV0 echo "qdelaunay -" qdelaunay - echo "qdelaunay ." qdelaunay . echo "qdelaunay -?" qdelaunay -? # [mar'19] isatty does not work for Git for Windows echo "rbox c P0 D2 | qdelaunay s o" rbox c P0 D2 | qdelaunay s o echo "rbox c P0 D2 | qdelaunay i" rbox c P0 D2 | qdelaunay i echo "rbox c P0 D2 | qdelaunay Fv" rbox c P0 D2 | qdelaunay Fv echo "rbox c P0 D2 | qdelaunay s Qu Qt Fv" rbox c P0 D2 | qdelaunay s Qu Qt Fv echo "rbox c G1 d D2 | qdelaunay s i" rbox c G1 d D2 | qdelaunay s i echo "rbox c G1 d D2 | qhull d Qbb Ft" rbox c G1 d D2 | qhull d Qbb Ft echo "rbox c G1 d D2 | qhull d Qbb QJ s Ft" rbox c G1 d D2 | qhull d Qbb QJ s Ft echo "rbox M3,4 z 100 D2 | qdelaunay s" rbox M3,4 z 100 D2 | qdelaunay s echo "rbox c P-0.1 P+0.1 P+0.1 D2 | qdelaunay s Fx Fa Fc FP FQ Fn FN" rbox c P-0.1 P+0.1 P+0.1 D2 | qdelaunay s Fx Fa Fc FP FQ Fn FN echo "rbox P0 P0 c D2 | qdelaunay s FP QV0" rbox P0 P0 c D2 | qdelaunay s FP QV0 echo "qhalf -" qhalf - echo "qhalf ." qhalf . echo "qhalf -?" qhalf -? # [mar'19] isatty does not work for Git for Windows echo "rbox d | qhull FQ n | qhalf s Qt H0,0,0 Fp" rbox d | qhull FQ n | qhalf s Qt H0,0,0 Fp echo "rbox c | qhull FQ FV n | qhalf s i" rbox c | qhull FQ FV n | qhalf s i echo "rbox c | qhull FQ FV n | qhalf o" rbox c | qhull FQ FV n | qhalf o echo "rbox d D2 | qhull FQ n | qhalf s H0 Fc FP Fn FN FQ Fv Fx" rbox d D2 | qhull FQ n | qhalf s H0 Fc FP Fn FN FQ Fv Fx echo "qhull - printed at end" echo "qhull ." qhull . echo "qhull -?" qhull -? # [mar'19] isatty does not work for Git for Windows echo "rbox 1000 s | qhull Tv s FA" rbox 1000 s | qhull Tv s FA echo "rbox 10 D2 | qhull d QJ s i TO q_test.log.1" rbox 10 D2 | qhull d QJ s i TO q_test.log.1 echo "type q_test.log.1" type q_test.log.1 echo "rbox 10 D2 | qhull v Qbb Qt p" rbox 10 D2 | qhull v Qbb Qt p echo "rbox 10 D2 | qhull d Qu QJ m" rbox 10 D2 | qhull d Qu QJ m echo "rbox 10 D2 | qhull v Qu QJ o" rbox 10 D2 | qhull v Qu QJ o echo "rbox c d D2 | qhull Qc s f Fx" rbox c d D2 | qhull Qc s f Fx echo "rbox c | qhull FV n | qhull H Fp" rbox c | qhull FV n | qhull H Fp echo "rbox d D12 | qhull QR0 FA" rbox d D12 | qhull QR0 FA echo "rbox c D7 | qhull FA TF1000" rbox c D7 | qhull FA TF1000 echo "rbox y 1000 W0 | qhull Qc" rbox y 1000 W0 | qhull Qc echo "rbox c | qhull n" rbox c | qhull n echo "rbox c | qhull TA1" rbox c | qhull TA1 echo "rbox 10 s | qhull C1e-5 T1P-1f" rbox 10 s | qhull C1e-5 T1P-1f echo === check quality of Qhull for ${d:-`hostname`} ${d:-`date`} echo "rbox 1000 W0 | qhull QR2 QJ s Fs Tv" rbox 1000 W0 | qhull QR2 QJ s Fs Tv echo "rbox 1000 W0 | qhull QR2 s Fs Tv" rbox 1000 W0 | qhull QR2 s Fs Tv echo "rbox 1000 s | qhull C0.02 Qc Tv" rbox 1000 s | qhull C0.02 Qc Tv echo "rbox 500 s D4 | qhull C0.01 Qc Tv" rbox 500 s D4 | qhull C0.01 Qc Tv echo "rbox 1000 s | qhull C-0.02 Qc Tv" rbox 1000 s | qhull C-0.02 Qc Tv echo "rbox 1000 s D4 | qhull C-0.01 Qc Tv" rbox 1000 s D4 | qhull C-0.01 Qc Tv echo "rbox 200 s D5 | qhull C-0.01 Qx Qc Tv" rbox 200 s D5 | qhull C-0.01 Qx Qc Tv echo "rbox 100 s D6 | qhull C-0.001 Qx Qc Tv" rbox 100 s D6 | qhull C-0.001 Qx Qc Tv echo "rbox 1000 W1e-4 | qhull C-1e-6 Qc Tv" rbox 1000 W1e-4 | qhull C-1e-6 Qc Tv echo "rbox 1000 W5e-4 D4 | qhull C-1e-5 Qc Tv" rbox 1000 W5e-4 D4 | qhull C-1e-5 Qc Tv echo "rbox 400 W1e-3 D5 | qhull C-1e-5 Qx Qc Tv" rbox 400 W1e-3 D5 | qhull C-1e-5 Qx Qc Tv echo === check input format etc. ${d:-`date`} echo "=== test long and short input to Qhull by hand, see eg/q_test ===" echo "rbox d h | qhull Fd FV n FD Tcv | qhull Fd H Fp Tcv" rbox d h | qhull Fd FV n FD Tcv | qhull Fd H Fp Tcv echo "rbox 10 h | qhull Fd FD p Tcv | qhull Fd d Tcv" rbox 10 h | qhull Fd FD p Tcv | qhull Fd d Tcv echo === check rbox ${d:-`date`} echo "rbox 3 n D2" rbox 3 n D2 echo "rbox 3 D2" rbox 3 D2 echo "rbox 3 h D2" rbox 3 h D2 echo "rbox 3 z D2" rbox 3 z D2 echo "rbox 3 z h D2" rbox 3 z h D2 echo "rbox 3 B10 D2" rbox 3 B10 D2 echo "rbox 3 B10 D2 C2,1E-13,1" rbox 3 B10 D2 C2,1E-13,1 echo "rbox 3 z B10 D2" rbox 3 z B10 D2 echo "rbox 4 L2 r D2" rbox 4 L2 r D2 echo "rbox 8 L2 r D2" rbox 8 L2 r D2 echo "rbox 8 L2 D2 C1,1E-13,2" rbox 8 L2 D2 C1,1E-13,2 echo "rbox 4 L4 r D3" rbox 4 L4 r D3 echo "rbox 4 L4 s D5 W1e-3" rbox 4 L4 s D5 W1e-3 echo "rbox 4 L4 s D5 W1e-3 C1,1E-12" rbox 4 L4 s D5 W1e-3 C1,1E-12 echo "rbox y" rbox y echo "rbox 10 M3,4" rbox 10 M3,4 echo "rbox 10 M3,4 C1,1E-14" rbox 10 M3,4 C1,1E-14 echo "rbox 27 M1,0,1" rbox 27 M1,0,1 echo "rbox 10 L4 r D3 | qhull Tcv" rbox 10 L4 r D3 | qhull Tcv echo "rbox 10 L4 s D5 W1e-3 | qhull Tcv" rbox 10 L4 s D5 W1e-3 | qhull Tcv echo "rbox 10 L4 s D5 W1e-3 C1,1E-12 | qhull Tcv" rbox 10 L4 s D5 W1e-3 C1,1E-12 | qhull Tcv echo "rbox 10 L6 D3 | qhull Tcv" rbox 10 L6 D3 | qhull Tcv echo "rbox 10 L1.1 s D4 | qhull Tcv" rbox 10 L1.1 s D4 | qhull Tcv echo "rbox y r 100 W0 O0.5 | qhull s p Tcv" rbox y r 100 W0 O0.5 | qhull s p Tcv echo "rbox x r 100 W0 O0.5 | qhull s Tcv" rbox x r 100 W0 O0.5 | qhull s Tcv echo "rbox 12 D8 | qhull Tcv" rbox 12 D8 | qhull Tcv echo "rbox 12 D9 | qhull Tcv" rbox 12 D9 | qhull Tcv echo "rbox 1000 D4 | qhull s i A-0.97 C0.2 A0.7 Tcv" rbox 1000 D4 | qhull s i A-0.97 C0.2 A0.7 Tcv echo "rbox 3 D2 | qhull Qb0B1:-2 p" rbox 3 D2 | qhull Qb0B1:-2 p echo "rbox 100 r D2 | qhull Pd0:0.7 PD0:0.8 Pg n Tcv" rbox 100 r D2 | qhull Pd0:0.7 PD0:0.8 Pg n Tcv echo "rbox 1000 s | qhull C0.05 Tcv" rbox 1000 s | qhull C0.05 Tcv echo "rbox 1000 s t | qhull Qm C0.05 Tcv" rbox 1000 s t | qhull Qm C0.05 Tcv echo "rbox 500 D2 | qhull n A-0.95 C0.1 Tcv" rbox 500 D2 | qhull n A-0.95 C0.1 Tcv echo "rbox 500 s P1,1,1 | qhull QgG0 Pp Tcv" rbox 500 s P1,1,1 | qhull QgG0 Pp Tcv echo "rbox d | qhull m" rbox d | qhull m echo "rbox d | qhull FM" rbox d | qhull FM echo "rbox c D2 | qhull Tcv Q0" rbox c D2 | qhull Tcv Q0 echo "rbox d D2 | qhull Tcv" rbox d D2 | qhull Tcv echo "rbox c D3 | qhull Tcv Q0" rbox c D3 | qhull Tcv Q0 echo "rbox d D3 | qhull Tcv" rbox d D3 | qhull Tcv echo "rbox c D4 | qhull Tcv Q0" rbox c D4 | qhull Tcv Q0 echo "rbox d D4 | qhull Tcv" rbox d D4 | qhull Tcv echo "rbox c D5 | qhull Tcv Q0" rbox c D5 | qhull Tcv Q0 echo "rbox d D5 | qhull Tcv" rbox d D5 | qhull Tcv echo "rbox c D6 | qhull Tcv Q0" rbox c D6 | qhull Tcv Q0 echo "rbox d D6 | qhull Tcv" rbox d D6 | qhull Tcv echo "rbox d D7 | qhull Tcv" rbox d D7 | qhull Tcv echo "rbox c D2 | qhull Tcv C-0" rbox c D2 | qhull Tcv C-0 echo "rbox c D3 | qhull Tcv C-0" rbox c D3 | qhull Tcv C-0 echo "rbox c D4 | qhull Tcv C-0" rbox c D4 | qhull Tcv C-0 echo "rbox c D5 | qhull Tcv C-0" rbox c D5 | qhull Tcv C-0 echo "rbox c D6 | qhull Tcv C-0" rbox c D6 | qhull Tcv C-0 echo "rbox c D7 | qhull Tv C-0" rbox c D7 | qhull Tv C-0 echo "rbox 20 l D3 | qhull Tcv" rbox 20 l D3 | qhull Tcv echo "rbox 100 s D2 | qhull Tcv" rbox 100 s D2 | qhull Tcv echo "rbox 100 s D3 | qhull Tcv" rbox 100 s D3 | qhull Tcv echo "rbox 100 s D4 | qhull Tcv" rbox 100 s D4 | qhull Tcv echo "rbox 100 s c D4 | qhull Tcv" rbox 100 s c D4 | qhull Tcv echo "rbox 100 s d G1.5 D4 | qhull Tcv" rbox 100 s d G1.5 D4 | qhull Tcv echo "rbox 100 s W1e-2 | qhull Tcv" rbox 100 s W1e-2 | qhull Tcv echo "rbox 100 | qhull Tcv" rbox 100 | qhull Tcv echo "rbox 100 W1e-3 | qhull Tcv" rbox 100 W1e-3 | qhull Tcv echo "rbox 100 r D2 | qhull Tcv" rbox 100 r D2 | qhull Tcv echo "rbox 100 r s Z1 | qhull Tcv" rbox 100 r s Z1 | qhull Tcv echo "rbox 100 r s Z1 G0.1 | qhull Tcv C-0" rbox 100 r s Z1 G0.1 | qhull Tcv C-0 echo "rbox 100 s Z1 G0.1 | qhull Tcv" rbox 100 s Z1 G0.1 | qhull Tcv echo "rbox 100 s Z1e-5 G0.1 | qhull Tc Pp" rbox 100 s Z1e-5 G0.1 | qhull Tc Pp echo === check qhull option errors ${d:-`date`} echo "rbox 10 | qhull d H0" rbox 10 | qhull d H0 echo "rbox 10 | qhull Zza" rbox 10 | qhull Zza echo "rbox 10 | qhull Zza Qw" rbox 10 | qhull Zza Qw echo "rbox 10 | qhull Q999" rbox 10 | qhull Q999 echo "rbox 10 | qhull Q999 Qw" rbox 10 | qhull Q999 Qw echo "qhull TIxyzlkajdfhwh" qhull TIxyzlkajdfhwh echo "rbox 10 >r.x" rbox 10 >r.x echo "qhull TIr.x" qhull TIr.x echo "qhull p TI r.x TO x.x" qhull p TI r.x TO x.x echo "type x.x" type x.x echo === check qhull output formats ${d:-`date`} echo "rbox 5 r s D2 | qhull Tcv" rbox 5 r s D2 | qhull Tcv echo "rbox 5 r s D2 | qhull s " rbox 5 r s D2 | qhull s echo "rbox 5 r s D2 | qhull s o " rbox 5 r s D2 | qhull s o echo "rbox 5 r s D2 | qhull f" rbox 5 r s D2 | qhull f echo "rbox 5 r s D2 | qhull i " rbox 5 r s D2 | qhull i echo "rbox 5 r s D2 | qhull m " rbox 5 r s D2 | qhull m echo "rbox 5 r s D2 | qhull FM " rbox 5 r s D2 | qhull FM echo "rbox 5 r s D2 | qhull n " rbox 5 r s D2 | qhull n echo "rbox 5 r s D2 | qhull p " rbox 5 r s D2 | qhull p echo "rbox 5 r s D2 | qhull o " rbox 5 r s D2 | qhull o echo "rbox 5 r s D2 | qhull Ft" rbox 5 r s D2 | qhull Ft echo "rbox 5 r s D2 | qhull Fx" rbox 5 r s D2 | qhull Fx echo "rbox 5 r s D2 | qhull p n i p p" rbox 5 r s D2 | qhull p n i p p echo "rbox 10 D3 | qhull f Tcv" rbox 10 D3 | qhull f Tcv echo "rbox 10 D3 | qhull i" rbox 10 D3 | qhull i echo "rbox 10 D3 | qhull p " rbox 10 D3 | qhull p echo "rbox 10 D3 | qhull o " rbox 10 D3 | qhull o echo "rbox 10 D3 | qhull Fx" rbox 10 D3 | qhull Fx echo "rbox 27 M1,0,1 | qhull Qc" rbox 27 M1,0,1 | qhull Qc echo "rbox 50 D3 s | qhull C0.1 Qc Pd0d1d2 Pg s p Tcv" rbox 50 D3 s | qhull C0.1 Qc Pd0d1d2 Pg s p Tcv echo "rbox 10 D2 P0 P1e-15 | qhull d Qc FP s Tcv" rbox 10 D2 P0 P1e-15 | qhull d Qc FP s Tcv echo "rbox 100 s | qhull C-0.003 Qc FP s" rbox 100 s | qhull C-0.003 Qc FP s echo "rbox 100 s D2 | qhull C0.1 i Fx Tcv" rbox 100 s D2 | qhull C0.1 i Fx Tcv echo "rbox 4 s D3 | qhull Qc Ghipv Tcv " rbox 4 s D3 | qhull Qc Ghipv Tcv echo "rbox 6 D4 | qhull f Tcv" rbox 6 D4 | qhull f Tcv echo "rbox 6 D4 | qhull i" rbox 6 D4 | qhull i echo "rbox 6 D4 | qhull p " rbox 6 D4 | qhull p echo "rbox 6 D4 | qhull o" rbox 6 D4 | qhull o echo "rbox 1000 s D2 | qhull FA Tcv" rbox 1000 s D2 | qhull FA Tcv echo "rbox 1000 s | qhull FA Tcv" rbox 1000 s | qhull FA Tcv echo "rbox c D4 | qhull FA Tcv" rbox c D4 | qhull FA Tcv echo "rbox c D5 | qhull FA Tcv" rbox c D5 | qhull FA Tcv echo "rbox c D5 | qhull FA Qt Tcv" rbox c D5 | qhull FA Qt Tcv echo "rbox 10 D2 | qhull d FA Tcv" rbox 10 D2 | qhull d FA Tcv echo "rbox 10 D2 | qhull d Qu FA Tcv" rbox 10 D2 | qhull d Qu FA Tcv echo "rbox 10 D2 | qhull FA Tcv" rbox 10 D2 | qhull FA Tcv echo "rbox 10 c D2 | qhull Fx Tcv" rbox 10 c D2 | qhull Fx Tcv echo "rbox 1000 s | qhull FS Tcv" rbox 1000 s | qhull FS Tcv echo "rbox 10 W0 D2 | qhull p Qc FcC Tcv" rbox 10 W0 D2 | qhull p Qc FcC Tcv echo "rbox 4 z h s D2 | qhull Fd s n FD Tcv" rbox 4 z h s D2 | qhull Fd s n FD Tcv echo "rbox 6 s D3 | qhull C-0.1 Qc FF s FQ Fi n Fo FQ FI Fm Fn FN FO FO FQ Fs FS FV Fv Tcv" rbox 6 s D3 | qhull C-0.1 Qc FF s FQ Fi n Fo FQ FI Fm Fn FN FO FO FQ Fs FS FV Fv Tcv echo "rbox P0.5,0.5 P0.5,0.5 W0 5 D2 | qhull d FN Qc" rbox P0.5,0.5 P0.5,0.5 W0 5 D2 | qhull d FN Qc echo "rbox 10 D3 | qhull Fa PA5" rbox 10 D3 | qhull Fa PA5 echo "rbox 10 D3 | qhull Fa PF0.4" rbox 10 D3 | qhull Fa PF0.4 echo === test Qt ${d:-`date`} echo "rbox c | qhull Qt s o Tcv" rbox c | qhull Qt s o Tcv echo "rbox c | qhull Qt f i" rbox c | qhull Qt f i echo "rbox c | qhull Qt m FM n" rbox c | qhull Qt m FM n echo "rbox c | qhull Qt p o" rbox c | qhull Qt p o echo "rbox c | qhull Qt Fx" rbox c | qhull Qt Fx echo "rbox c | qhull Qt FA s Fa" rbox c | qhull Qt FA s Fa echo "rbox 6 r s c G0.1 D2 | qhull Qt d FA Tcv" rbox 6 r s c G0.1 D2 | qhull Qt d FA Tcv echo "rbox 6 r s c G0.1 D2 | qhull d FA Tcv" rbox 6 r s c G0.1 D2 | qhull d FA Tcv echo "rbox 6 r s c G0.1 D2 | qhull Qt v p Tcv" rbox 6 r s c G0.1 D2 | qhull Qt v p Tcv echo "rbox c | qhull Qt C-0.1 Qc FF s FQ Fi n Fo FQ FI Fm Fn FN FO FO FQ Fs FS FV Fv Tcv" rbox c | qhull Qt C-0.1 Qc FF s FQ Fi n Fo FQ FI Fm Fn FN FO FO FQ Fs FS FV Fv Tcv echo "rbox 6 r s c G0.1 D2 P0.1,0.1 | qhull s FP d FO Qt" rbox 6 r s c G0.1 D2 P0.1,0.1 | qhull s FP d FO Qt echo "rbox 100 W0 | qhull Tv Q11 FO" rbox 100 W0 | qhull Tv Q11 FO echo === test unbounded intersection echo "rbox c | qhull PD0:0.5 n | qhull H0 Fp Tcv" rbox c | qhull PD0:0.5 n | qhull H0 Fp Tcv echo "rbox 1000 W1e-3 D3 | qhull PA8 Fa FS s n Tcv" rbox 1000 W1e-3 D3 | qhull PA8 Fa FS s n Tcv echo "rbox 1000 W1e-3 D3 | qhull C-0.01 PM10 Fm n Tcv Qc" rbox 1000 W1e-3 D3 | qhull C-0.01 PM10 Fm n Tcv Qc echo "rbox 1000 W1e-3 D3 | qhull C-0.01 PA8 PG n Tcv Qc" rbox 1000 W1e-3 D3 | qhull C-0.01 PA8 PG n Tcv Qc echo "rbox 10 | qhull FO Tz TO q_test.log.1" rbox 10 | qhull FO Tz TO q_test.log.1 echo "type q_test.log.1" type q_test.log.1 echo === check Delaunay/Voronoi ${d:-`date`} echo "rbox 10 D2 | qhull d Tcv" rbox 10 D2 | qhull d Tcv echo "rbox 10 D2 | qhull d Qz Tcv" rbox 10 D2 | qhull d Qz Tcv echo "rbox 10 D3 | qhull d Tcv" rbox 10 D3 | qhull d Tcv echo "rbox c | qhull d Qz Ft Tcv" rbox c | qhull d Qz Ft Tcv echo "rbox 10 s D2 c | qhull d Tcv" rbox 10 s D2 c | qhull d Tcv echo "rbox 10 s D2 | qhull d Tcv Qz Q8" rbox 10 s D2 | qhull d Tcv Qz Q8 echo "rbox 10 D2 | qhull d Tcv p" rbox 10 D2 | qhull d Tcv p echo "rbox 10 D2 | qhull d Tcv i" rbox 10 D2 | qhull d Tcv i echo "rbox 10 D2 | qhull d Tcv o" rbox 10 D2 | qhull d Tcv o echo "rbox 10 D2 | qhull v Tcv o" rbox 10 D2 | qhull v Tcv o echo "rbox 10 D2 | qhull v Tcv p" rbox 10 D2 | qhull v Tcv p echo "rbox 10 D2 | qhull v Tcv G" rbox 10 D2 | qhull v Tcv G echo "rbox 10 D2 | qhull v Tcv Fv" rbox 10 D2 | qhull v Tcv Fv echo "rbox 10 D2 | qhull v Tcv Fi" rbox 10 D2 | qhull v Tcv Fi echo "rbox 10 D2 | qhull v Tcv Fo" rbox 10 D2 | qhull v Tcv Fo echo "rbox 10 D2 | qhull v Qu o Fv Fi Fo Tcv" rbox 10 D2 | qhull v Qu o Fv Fi Fo Tcv echo "rbox 10 D3 | qhull v Fv Tcv" rbox 10 D3 | qhull v Fv Tcv echo "rbox 10 D3 | qhull v fi Tcv" rbox 10 D3 | qhull v Fi Tcv echo "rbox 10 D3 | qhull v Fo Tcv" rbox 10 D3 | qhull v Fo Tcv echo "rbox 10 D3 | qhull v Qu o Fv Fi Fo Tcv" rbox 10 D3 | qhull v Qu o Fv Fi Fo Tcv echo "rbox 5 D2 | qhull v f FnN o" rbox 5 D2 | qhull v f FnN o echo === check Halfspace, showing the input ${d:-`date`} echo === the Qhull pipeline recreates 100 4-D cospherical points with the same area and volume echo "rbox 100 s D4 | qhull FA FV s" rbox 100 s D4 | qhull FA FV s echo "rbox 100 s D4 | qhull FQ FA FV n | qhull s H" rbox 100 s D4 | qhull FQ FA FV n s | qhull s H echo "rbox 100 s D4 | qhull FQ FA FV n s Tcv | qhull FQ s H Fp Tcv | qhull FA Tcv" rbox 100 s D4 | qhull FQ FA FV n s Tcv | qhull FQ s H Fp Tcv | qhull FA Tcv echo === the Qhull pipeline recreates a 3-D tetrahedron echo "rbox d D3 | qhull n FD" rbox d D3 | qhull n FD echo "rbox d D3 | qhull s n FD Tcv | qhull s Fd H0.1,0.1 Fp Tcv" rbox d D3 | qhull s n FD Tcv | qhull s Fd H0.1,0.1 Fp Tcv echo "rbox 5 r D2 | qhull s n Tcv" echo === the Qhull pipeline recreates a regular 2-D pentagon rbox 5 r D2 | qhull FQ n echo "rbox 5 r D2 | qhull s FQ n Tcv | qhull s H0 Fp Tcv" rbox 5 r D2 | qhull s FQ n Tcv | qhull s H0 Fp Tcv echo === check qhull ${d:-`date`} echo "rbox 10 s D3 | qhull Tcv" rbox 10 s D3 | qhull Tcv echo "rbox 10 s D3 | qhull f Pd0:0.5 Pd2 Pg Tcv" rbox 10 s D3 | qhull f Pd0:0.5 Pd2 Pg Tcv echo "rbox 10 s D3 | qhull f Tcv PD2:-0.5 Pg" rbox 10 s D3 | qhull f Tcv PD2:-0.5 Pg echo "rbox 10 s D3 | qhull QR-1" rbox 10 s D3 | qhull QR-1 echo "rbox 10 s D3 | qhull QR-40" rbox 10 s D3 | qhull QR-40 echo "rbox 1000 D3 | qhull Tcvs" rbox 1000 D3 | qhull Tcvs echo "Test tracing 'Tn', combine stderr/stdout 'Tz', flush fprintf 'Tf'" echo "rbox 100 D3 | qhull T1 Tz Tf TA1 TO q_test.log.1" rbox 100 D3 | qhull T1 Tz Tf TA1 TO q_test.log.1 echo "type q_test.log.1" type q_test.log.1 echo "del q_test.log.1" del q_test.log.1 echo "rbox 100 s D3 | qhull TcvA10" rbox 100 s D3 | qhull TcvA10 echo "rbox 100 s D3 | qhull TcvV-2" rbox 100 s D3 | qhull TcvV-2 echo "rbox 100 s D3 | qhull TcvC2" rbox 100 s D3 | qhull TcvC2 echo "rbox 100 s D3 | qhull TcvV2" rbox 100 s D3 | qhull TcvV2 echo "rbox 100 s D3 | qhull T1cvV2P2" rbox 100 s D3 | qhull T1cvV2P2 echo "rbox 100 s D3 | qhull TcvF100" rbox 100 s D3 | qhull TcvF100 echo "rbox 100 s D3 | qhull Qf Tcv" rbox 100 s D3 | qhull Qf Tcv echo "rbox 100 D3 | qhull Tcv" rbox 100 D3 | qhull Tcv echo "rbox 100 D3 | qhull Qs Tcv" rbox 100 D3 | qhull Qs Tcv echo "rbox 100 D5 | qhull Qs Tcv" rbox 100 D5 | qhull Qs Tcv echo "rbox 100 D3 | qhull Qr Tcv" rbox 100 D3 | qhull Qr Tcv echo "rbox 100 D3 | qhull Qxv Tcv" rbox 100 D3 | qhull Qxv Tcv echo "rbox 100 D3 | qhull Qi f Pd0 Pd1 Pd2 Pg Tcv" rbox 100 D3 | qhull Qi f Pd0 Pd1 Pd2 Pg Tcv echo "rbox c d | qhull Qc f Tcv" rbox c d | qhull Qc f Tcv echo "rbox c d | qhull Qc p Tcv" rbox c d | qhull Qc p Tcv echo "rbox 100 D3 | qhull QbB FO Tcv" rbox 100 D3 | qhull QbB FO Tcv echo "rbox 1000 D2 B1e6 | qhull d Qbb FO Tcv" rbox 1000 D2 B1e6 | qhull d Qbb FO Tcv echo "rbox 10 D3 | qhull QbB p Tcv" rbox 10 D3 | qhull QbB p Tcv echo "rbox 10 D3 | qhull Qbb p Tcv" rbox 10 D3 | qhull Qbb p Tcv echo "rbox 10 D3 | qhull Qb0:-10B2:20 p Tcv" rbox 10 D3 | qhull Qb0:-10B2:20 p Tcv echo "rbox 10 D3 | qhull Qb0:-10B2:20 p Tcv | qhull QbB p Tcv" rbox 10 D3 | qhull Qb0:-10B2:20 p Tcv | qhull QbB p Tcv echo "rbox 10 D3 | qhull Qb1:0B1:0 d Tcv Q8" rbox 10 D3 | qhull Qb1:0B1:0 d Tcv Q8 echo "rbox 10 D3 | qhull Qb1:0B1:0B2:0 d Tcv Q8" rbox 10 D3 | qhull Qb1:0B1:0B2:0 d Tcv Q8 echo "rbox 10 D3 | qhull Qb1:0 d Tcv" rbox 10 D3 | qhull Qb1:0 d Tcv echo "rbox 10 D3 | qhull Qb1:0B1:0 Tcv" rbox 10 D3 | qhull Qb1:0B1:0 Tcv echo "== next command will error ${d:-`date`} ==" echo "rbox 10 D2 | qhull Qb1:1B1:1 Tcv" rbox 10 D2 | qhull Qb1:1B1:1 Tcv echo "rbox 200 L20 D2 t | qhull FO Tcv C-0" rbox 200 L20 D2 t | qhull FO Tcv C-0 echo "rbox 1000 L20 t | qhull FO Tcv C-0" rbox 1000 L20 t | qhull FO Tcv C-0 echo "rbox 200 L20 D4 t | qhull FO Tcv C-0" rbox 200 L20 D4 t | qhull FO Tcv C-0 echo "rbox 200 L20 D5 t | qhull FO Tcv Qx" rbox 200 L20 D5 t | qhull FO Tcv Qx echo "rbox 1000 W1e-3 s D2 t | qhull d FO Tcv Qu Q0" rbox 1000 W1e-3 s D2 t | qhull d FO Tcv Qu Q0 echo "rbox 1000 W1e-3 s D2 t | qhull d FO Tcv Qu C-0" rbox 1000 W1e-3 s D2 t | qhull d FO Tcv Qu C-0 echo === check joggle and TRn ${d:-`date`} echo "rbox 100 W0 | qhull QJ1e-14 Qc TR100 Tv" rbox 100 W0 | qhull QJ1e-14 Qc TR100 Tv echo "rbox 100 W0 | qhull QJ1e-13 Qc TR100 Tv" rbox 100 W0 | qhull QJ1e-13 Qc TR100 Tv echo "rbox 100 W0 | qhull QJ1e-12 Qc TR100 Tv" rbox 100 W0 | qhull QJ1e-12 Qc TR100 Tv echo "rbox 100 W0 | qhull QJ1e-11 Qc TR100 Tv" rbox 100 W0 | qhull QJ1e-11 Qc TR100 Tv echo "rbox 100 W0 | qhull QJ1e-10 Qc TR100 Tv" rbox 100 W0 | qhull QJ1e-10 Qc TR100 Tv echo "rbox 100 | qhull d QJ Qb0:1e4 QB0:1e5 Qb1:1e4 QB1:1e6 Qb2:1e5 QB2:1e7 FO Tv" rbox 100 | qhull d QJ Qb0:1e4 QB0:1e5 Qb1:1e4 QB1:1e6 Qb2:1e5 QB2:1e7 FO Tv echo === check precision options ${d:-`date`} echo "rbox 100 D3 s | qhull E0.01 Qx Tcv FO" rbox 100 D3 s | qhull E0.01 Qx Tcv FO echo "rbox 100 D3 W1e-1 | qhull W1e-3 Tcv" rbox 100 D3 W1e-1 | qhull W1e-3 Tcv echo "rbox 100 D3 W1e-1 | qhull W1e-2 Tcv Q0" rbox 100 D3 W1e-1 | qhull W1e-2 Tcv Q0 echo "rbox 100 D3 W1e-1 | qhull W1e-2 Tcv" rbox 100 D3 W1e-1 | qhull W1e-2 Tcv echo "rbox 100 D3 W1e-1 | qhull W1e-1 Tcv" rbox 100 D3 W1e-1 | qhull W1e-1 Tcv echo "rbox 15 D2 P0 P1e-14,1e-14 | qhull d Quc Tcv" rbox 15 D2 P0 P1e-14,1e-14 | qhull d Quc Tcv echo "rbox 15 D3 P0 P1e-12,1e-14,1e-14 | qhull d Qcu Tcv" rbox 15 D3 P0 P1e-12,1e-14,1e-14 | qhull d Qcu Tcv echo "rbox 1000 s D3 | qhull C-0.01 Tcv Qc" rbox 1000 s D3 | qhull C-0.01 Tcv Qc echo "rbox 1000 s D3 | qhull C-0.01 V0 Qc Tcv" rbox 1000 s D3 | qhull C-0.01 V0 Qc Tcv echo "rbox 1000 s D3 | qhull C-0.01 U0 Qc Tcv" rbox 1000 s D3 | qhull C-0.01 U0 Qc Tcv echo "rbox 1000 s D3 | qhull C-0.01 V0 Qcm Tcv" rbox 1000 s D3 | qhull C-0.01 V0 Qcm Tcv echo "rbox 1000 s D3 | qhull C-0.01 Qcm Tcv" rbox 1000 s D3 | qhull C-0.01 Qcm Tcv echo "rbox 1000 s D3 | qhull C-0.01 Q1 FO Tcv Qc" rbox 1000 s D3 | qhull C-0.01 Q1 FO Tcv Qc echo "rbox 1000 s D3 | qhull C-0.01 Q2 FO Tcv Qc" rbox 1000 s D3 | qhull C-0.01 Q2 FO Tcv Qc echo "rbox 1000 s D3 | qhull C-0.01 Q3 FO Tcv Qc" rbox 1000 s D3 | qhull C-0.01 Q3 FO Tcv Qc echo "rbox 1000 s D3 | qhull C-0.01 Q4 FO Tcv Qc" rbox 1000 s D3 | qhull C-0.01 Q4 FO Tcv Qc echo === this may generate an error ${d:-`date`} echo "rbox 1000 s D3 | qhull C-0.01 Q5 FO Tcv" rbox 1000 s D3 | qhull C-0.01 Q5 FO Tcv echo === this should generate an error ${d:-`date`} echo "rbox 1000 s D3 | qhull C-0.01 Q6 FO Po Tcv Qc" rbox 1000 s D3 | qhull C-0.01 Q6 FO Po Tcv Qc echo "rbox 1000 s D3 | qhull C-0.01 Q7 FO Tcv Qc" rbox 1000 s D3 | qhull C-0.01 Q7 FO Tcv Qc echo "rbox 1000 s D3 | qhull C-0.01 Qx Tcv Qc" rbox 1000 s D3 | qhull C-0.01 Qx Tcv Qc echo "=== this may generate an error e.g., t1263080158 ${d:-`date`}" echo "rbox 100 s D3 t | qhull R1e-3 Tcv Qc" rbox 100 s D3 t | qhull R1e-3 Tcv Qc echo "rbox 100 s D3 t | qhull R1e-2 Tcv Qc" rbox 100 s D3 t | qhull R1e-2 Tcv Qc echo "rbox 500 s D3 t | qhull R0.05 A-1 Tcv Qc" rbox 500 s D3 t | qhull R0.05 A-1 Tcv Qc echo "rbox 100 W0 D3 t | qhull R1e-3 Tcv Qc" rbox 100 W0 D3 t | qhull R1e-3 Tcv Qc echo "rbox 100 W0 D3 t | qhull R1e-3 Qx Tcv Qc" rbox 100 W0 D3 t | qhull R1e-3 Qx Tcv Qc echo "rbox 100 W0 D3 t | qhull R1e-2 Tcv Qc" rbox 100 W0 D3 t | qhull R1e-2 Tcv Qc echo "rbox 100 W0 D3 t | qhull R1e-2 Qx Tcv Qc" rbox 100 W0 D3 t | qhull R1e-2 Qx Tcv Qc echo "rbox 500 W0 D3 t | qhull R0.05 A-1 Tcv Qc" rbox 500 W0 D3 t | qhull R0.05 A-1 Tcv Qc echo "rbox 500 W0 D3 t | qhull R0.05 Qx Tcv Qc" rbox 500 W0 D3 t | qhull R0.05 Qx Tcv Qc echo "rbox 1000 W1e-20 t | qhull Tcv Qc" rbox 1000 W1e-20 t | qhull Tcv Qc echo "rbox 1000 W1e-20 D4 t | qhull Tcv Qc" rbox 1000 W1e-20 D4 t | qhull Tcv Qc echo "rbox 500 W1e-20 D5 t | qhull Tv Qc" rbox 500 W1e-20 D5 t | qhull Tv Qc echo "rbox 100 W1e-20 D6 t | qhull Tv Qc" rbox 100 W1e-20 D6 t | qhull Tv Qc echo "rbox 50 W1e-20 D6 t | qhull Qv Tv Qc" rbox 50 W1e-20 D6 t | qhull Qv Tv Qc echo "rbox 10000 D4 t | qhull QR0 Qc C-0.01 A0.3 Tv" rbox 10000 D4 t | qhull QR0 Qc C-0.01 A0.3 Tv echo "rbox 1000 D2 t | qhull d QR0 Qc C-1e-8 Qu Tv" rbox 1000 D2 t | qhull d QR0 Qc C-1e-8 Qu Tv echo "rbox 300 D5 t |qhull A-0.999 Qx Qc Tcv" rbox 300 D5 t |qhull A-0.999 Qx Qc Tcv echo "rbox 100 D6 t |qhull A-0.9999 Qx Qc Tcv" rbox 100 D6 t |qhull A-0.9999 Qx Qc Tcv echo "rbox 50 D7 t |qhull A-0.99999 Qx Qc Tcv W0.1" rbox 50 D7 t |qhull A-0.99999 Qx Qc Tcv W0.1 echo === check bad cases for Qhull. May cause errors ${d:-`date`} echo "rbox 1000 L100000 s G1e-6 t | qhull Tv" rbox 1000 L100000 s G1e-6 t | qhull Tv echo "rbox 1000 L100000 s G1e-6 t | qhull Tv Q10" rbox 1000 L100000 s G1e-6 t | qhull Tv Q10 echo "rbox 1000 s Z1 G1e-13 t | qhull Tv" rbox 1000 s Z1 G1e-13 t | qhull Tv echo "rbox 1000 s W1e-13 P0 t | qhull d Qbb Qc Q12 Tv" rbox 1000 s W1e-13 P0 t | qhull d Qbb Qc Q12 Tv echo "rbox 1000 s W1e-13 t | qhull d Q12 Tv" rbox 1000 s W1e-13 t | qhull d Q12 Tv echo "rbox 1000 s W1e-13 t D2 | qhull d Tv" rbox 1000 s W1e-13 t D2 | qhull d Tv echo ======================================================= echo ======================================================= echo === The following commands may cause errors =========== echo ======================================================= echo ======================================================= echo "rbox c D7 | qhull Q0 Tcv" rbox c D7 | qhull Q0 Tcv echo "rbox 100 s D3 | qhull Q0 E1e-3 Tc Po" rbox 100 s D3 | qhull Q0 E1e-3 Tc Po echo "rbox 100 s D3 | qhull Q0 E1e-2 Tc Po" rbox 100 s D3 | qhull Q0 E1e-2 Tc Po echo "rbox 100 s D3 | qhull Q0 E1e-1 Tc Po" rbox 100 s D3 | qhull Q0 E1e-1 Tc Po echo "rbox 100 s D3 | qhull Q0 R1e-3 Tc Po" rbox 100 s D3 | qhull Q0 R1e-3 Tc Po echo "rbox 100 s D3 | qhull Q0 R1e-2 Tc Po" rbox 100 s D3 | qhull Q0 R1e-2 Tc Po echo "rbox 100 s D3 | qhull Q0 R0.05 Tc" rbox 100 s D3 | qhull Q0 R0.05 Tc echo "rbox 100 s D3 | qhull Q0 R0.05 Tc Po" rbox 100 s D3 | qhull Q0 R0.05 Tc Po echo "rbox 1000 W1e-7 | qhull Q0 Tc Po" rbox 1000 W1e-7 | qhull Q0 Tc Po echo "rbox 50 s | qhull Q0 V0.05 W0.01 Tc Po" rbox 50 s | qhull Q0 V0.05 W0.01 Tc Po echo "rbox 100 s D5 | qhull Q0 R1e-2 Tc Po" rbox 100 s D5 | qhull Q0 R1e-2 Tc Po echo "rbox L100 10000 D4 s C1,1e-13 t2 | qhull" rbox L100 10000 D4 s C1,1e-13 t2 | qhull echo "rbox L100 10000 D4 s C1,1e-13 t2 | qhull Q12" rbox L100 10000 D4 s C1,1e-13 t2 | qhull Q12 echo "rbox 50 C1,1E-13 t1447644703 | qhull d" rbox 50 C1,1E-13 t1447644703 | qhull d echo "rbox 50 C1,1E-13 t1447644703 | qhull d Q12" rbox 50 C1,1E-13 t1447644703 | qhull d Q12 echo "rbox 50 C1,1E-13 t1447644703 | qhull d Q14" rbox 50 C1,1E-13 t1447644703 | qhull d Q14 echo "=======================================================" echo "=== Testing done. Print documentation" echo "=======================================================" echo "qhull -" qhull - echo "rbox" rbox echo "# end of q_test" qhull-2020.2/File_id.diz0000644060175106010010000000073013706701027013234 0ustar bbarberQhull 2020.2 - Qhull computes convex hulls, Delaunay triangulations, halfspace inter- sections about a point, Voronoi diagrams, furthest-site Delaunay triangulations, and furthest-site Voronoi diagrams. Qhull works with 2-d, 3-d, 4-d, 5-d, and higher dimensions. It computes volumes, surface areas, and approximations. It runs in a command window under Windows 95/NT/XP/7. www.qhull.org, freeware. qhull-2020.2/html/0000755060175106010010000000000013724321356012140 5ustar bbarberqhull-2020.2/html/index.htm0000644060175106010010000013122313722744733013771 0ustar bbarber Qhull manual

Up: Home page for Qhull (local)
Up: News about Qhull
Up: Qhull Wiki and FAQ (local)
To: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)


[random-fixed] Qhull manual

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

There are six programs. Except for rbox, they use the same code. Each program includes instructions and examples.

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

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

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

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

Brad Barber, Arlington, MA

Copyright © 1995-2020 C.B. Barber


»Qhull manual: contents

»When to use Qhull

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

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

On a 1.7 GHz i7, Qhull computes the 2-d convex hull of 3,000,000 evenly spaced, cocircular points in 4.7 seconds. It computes the 2-d Delaunay triangulation and 3-d convex hull of 600,000 points in 5.9 seconds. It computes the 3-d Delaunay triangulation and 4-d convex hull of 120,000 points in 4.6 seconds. It computes the 4-d Delaunay triangulation and 5-d convex hull of 30,000 points in 5.1 seconds. It computes the 5-d Delaunay triangulation and 6-d convex hull of 6,000 points in 7.8 seconds. It computes the 6-d Delaunay triangulation and 7-d convex hull of 1,000 points in 7.6 seconds. It computes the 7-d Delaunay triangulation and 8-d convex hull of 300 points in 8.6 seconds. It computes the 8-d Delaunay triangulation and 9-d convex hull of 120 points in 5.7 seconds. It computes the 9-d Delaunay triangulation and 10-d convex hull of 70 points in 4.8 seconds. The 10-d convex hull of 70 cospherical points has about 375,000 facets.

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

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

Qhull does not handle all precision problems (Limitations of merged facets). For example, errors may occur for the 4-D Delaunay triangulation of nearly adjacent points in the unit cube. If every input site has a nearly adjacent point within a 10^-13 ball, precision errors and topological errors are likely to occur. A bounding box may alleviate these errors. Nearly adjacent points within substantially smaller or larger balls are OK.

Joggled input, option 'QJn', is an alternative to merged facets (Merged facets or joggled input). It randomly perturbs the input. If precision problems occur, Qhull restarts with a larger, random perturbation. Joggled input is a simple solution without the limitations of merged facets. For example, Qhull constructs a convex hull even if all of the input points are identical.

If you need a short code for convex hull, Delaunay triangulation, or Voronoi volumes consider Clarkson's hull program. If you need 2-d Delaunay triangulations consider Shewchuk's triangle program. It is much faster than Qhull and it allows constraints. Both programs use exact arithmetic. They are in http://www.netlib.org/voronoi/.

If your input is in general position (i.e., no coplanar or colinear points), Tomilov's quickhull.hpp (documentation-ru), or Qhull version 1.0 may meet your needs. Both programs detect precision problems, but do not handle them.

CGAL is a library of efficient and reliable geometric algorithms. It uses C++ templates and the Boost library to produce dimension-specific code. This allows more efficient use of memory than Qhull's general-dimension code. For 64-bit code, CGAL uses significantly less memory than Qhull and runs faster. CGAL simulates arbitrary precision while Qhull handles round-off error with thick facets. Compare the two approaches with Robustness Issues in CGAL, and Imprecision in Qhull.

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

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

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

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

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

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

»Description of Qhull

»definition

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

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

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

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

»input format

The input data on stdin consists of:

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

For example:

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

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

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

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

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

»option format

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

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

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

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

The default options are:

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

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

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

»output format

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

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

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

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

»algorithm

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

»data structures

Qhull produces the following data structures for dimension d:

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

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

»Imprecision in Qhull

See Imprecision in Qhull and Merged facets or joggled input

»Examples of Qhull

See Examples of Qhull. Most of these examples require Geomview. Some of the examples have pictures .

»Options for using Qhull

See Qhull options.

»Qhull code and internals

See Qhull code.

»Geomview, Qhull's graphical viewer

Geomview is an interactive geometry viewing program. Geomview provides a good visualization of Qhull's 2-d and 3-d results.

Qhull includes Examples of Qhull that may be viewed with Geomview.

Geomview can help visulalize a 3-d Delaunay triangulation or the surface of a 4-d convex hull, Use option 'QVn' to select the 3-D facets adjacent to a vertex.

You may use Geomview to create movies that animate your objects (c.f., How can I create a video animation?). Geomview helped create the mathematical videos "Not Knot", "Outside In", and "The Shape of Space" from the Geometry Center.

»Installing Geomview

Geomview is an open source project under SourceForge.

For build instructions see Downloading Geomview. Geomview builds under Linux, Unix, Macintosh OS X, and Windows.

Geomview has installable packages for Debian and Ubuntu. The OS X build needs Xcode, an X11 SDK, and Lesstif or Motif. The Windows build uses Cygwin (see Building Geomview below for instructions).

If using Xforms (e.g., for Geomview's External Modules), install the 'libXpm-devel' package from cygwin and move the xforms directory into your geomview directory, e.g.,
mv xforms-1.2.4 geomview-1.9.5/xforms

Geomview's ndview provides multiple views into 4-d and higher objects. This module is out-of-date (geomview-users: 4dview). Download NDview-sgi.tar.Z at newpieces and 4dview at Geomview/modules.

»Using Geomview

Use Geomview to view Examples of Qhull. You can spin the convex hull, fly a camera through its facets, and see how Qhull produces thick facets in response to round-off error.

Follow these instructions to view 'eg,01.cube' from Examples of Qhull

  1. Launch an XTerm command shell
    • If needed, start the X terminal server, Use 'xinit' or 'startx' in /usr/X11R6/bin
      xinit -- -multiwindow -clipboard
      startx
    • Start an XTerm command shell. In Windows, click the Cygwin/bash icon on your desktop.
    • Set the DISPLAY variable, e.g.,
      export DISPLAY=:0
      export DISPLAY=:0 >>~/.bashenv
  2. Use Qhull's Geomview options to create a geomview object
    • rbox c D3 | qconvex G >eg.01.cube
    • On windows, convert the output to Unix text format with 'd2u'
      rbox c D3 | qconvex G | d2u >eg.01.cube
      d2u eg.*
  3. Run Geomview
    • Start Geomview with your example
      ./geomview eg.01.cube
    • Follow the instructions in Gemoview Tutorial
    • Geomview creates the Geomview control panel with Targets and External Module, the Geomview toolbar with buttons for controlling Geomview, and the Geomview camera window showing a cube.
    • Clear the camera window by selecting your object in the Targets list and 'Edit > Delete' or 'dd'
    • Load the Geomview files panel. Select 'Open' in the 'File' menu.
    • Set 'Filter' in the files panel to your example directory followed by '/*' (e.g., '/usr/local/qhull-2015.2/eg/*')
    • Click 'Filter' in the files panel to view your examples in the 'Files' list.
    • Load another example into the camera window by selecting it and clicking 'OK'.
    • Review the instructions for Interacting with Geomview
    • When viewing multiple objects at once, you may want to turn off normalization. In the 'Inspect > Apperance' control panel, set 'Normalize' to 'None'.

Geomview defines GCL (a textual API for controlling Geomview) and OOGL (a textual file format for defining objects).

  • To control Geomview, you may use any program that reads and writes from stdin and stdout. For example, it could report Qhull's information about a vertex identified by a double-click 'pick' event.
  • GCL command language for controlling Geomview
  • OOGL file format for defining objects (tutorial).
  • External Modules for interacting with Geomview via GCL
  • Interact with your objects via pick commands in response to right-mouse double clicks. Enable pick events with the interest command.

»Building Geomview for Windows

Compile Geomview under Cygwin. For detailed instructions, see Building Savi and Geomview under Windows. These instructions are somewhat out-of-date. Updated instructions follow.

How to compile Geomview under 32-bit Cygwin (October 2015)

  1. Note: L. Wood has run into multiple issues with Geomview on Cygwin. He recommends Virtualbox/Ubuntu and a one-click install of geomview via the Ubuntu package. See his Savi/Geomview link above.
  2. Install 32-bit Cygwin as follows. For additional guidance, see Cygwin's Installing and Updating Cygwin Packages and Setup cygwin.
    • Launch the cygwin installer.
    • Select a mirror from Cygwin mirrors (e.g., http://mirrors.kernel.org/sourceware/cygwin/ in California).
    • Select the packages to install. Besides the cygwin packages listed in the Savi/Windows instructions consider adding
      • Default -- libXm-devel (required for /usr/include/Xm/Xm.h)
      • Devel -- bashdb, gcc-core (in place of gcc), gdb
      • Lib -- libGL-devel, libGLU1 (required, obsolete), libGLU-devel (required, obsolete), libjpeg-devel(XForms), libXext-devel (required), libXpm-devel (Xforms) libGL and lib
      • Math -- bc
      • Net -- autossh, inetutils, openssh
      • System -- chere
      • Utils -- dos2unix (required for qhull), keychain
      • If installing perl, ActiveState Perl may be a better choice than cygwin's perl. Perl is not used by Geomview or Qhull.
      • Cygwin Package Search -- Search for cygwin programs and packages
    • Click 'Next' to download and install the packages.
    • If the download is incomplete, try again.
    • If you try again after a successful install, cygwin will uninstall and reinstall all modules..
    • Click on the 'Cywin Terminal' icon on the Desktop. It sets up a user directory in /home from /etc/skel/...
    • Mount your disk drives
      mount c: /c # Ignore the warning /c does not exist
  3. Consider installing the Road Bash scripts (/etc/road-*) from Road. They define aliases and functions for Unix command shells (Unix, Linux, Mac OS X, Windows),
    • Download Road Bash and unzip the downloaded file
    • Copy .../bash/etc/road-* to the Cywin /etc directory (by default, C:\cygwin\etc).
    • Using the cygwin terminal, convert the road scripts to Unix format
      d2u /etc/road-*
    • Try it
      source /etc/road-home.bashrc
    • Install it
      cp /etc/road-home.bashrc ~/.bashrc
  4. Launch the X terminal server from 'Start > All programs > Cygwin-X > Xwin Server'. Alternatively, run 'startx'
  5. Launch an XTerm shell
    • Right click the Cywin icon on the system tray in the Windows taskbar.
    • Select 'System Tools > XTerm'
  6. Download and extract Geomview -- Downloading Geomview
  7. Compile Geomview
    • ./configure
    • make
  8. If './configure' fails, check 'config.log' at the failing step. Look carefully for missing libraries, etc. The Geomview FAQ contains suggestions (e.g., "configure claims it can't find OpenGl").
  9. If 'make' fails, read the output carefully for error messages. Usually it is a missing include file or package. Locate and install the missing cygwin packages (Cygwin Package Search).

»What to do if something goes wrong

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

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

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

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

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

Qhull resolves most precision issues. It reports a precision error for lower dimensional inputs. It may report a precision error for non-simplicial facets with multiple merges or nearly adjacent vertices. See Limitations of merged facets for more information.

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

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

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

»Email

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

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

»Authors

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

»Acknowledgments

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

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

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

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

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

»References

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

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

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

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

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

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

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

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

Golub, G.H. and van Loan, C.F., Matric Computations, Baltimore, Maryland, USA: John Hopkins Press, 1983

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

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

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

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

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

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


Up: Home page for Qhull (local)
Up:News about Qhull
Up: Qhull Wiki and FAQ (local)
To: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Dn: Imprecision in Qhull
Dn: Description of Qhull examples
Dn: Qhull code


The Geometry Center Home Page

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

qhull-2020.2/html/normal_voronoi_knauss_oesterle.jpg0000644060175106010010000005656410530736247021214 0ustar bbarberJFIF;CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 80 C   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((8" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?9dyLV 4dv(7'ϩbܟSFOb}Mv1@ 4dv1@ iqFnO'ӶѶshӱFo>}M;mh2}M;mh2N1F4v4Q?U|nS@EhӶѶ iqFnOSN@}M9ih7SFObPr}Mv1@ 4\QN}M&Omm'>SN2}M;mh>}M;b:^}M.(7SG>1@ 49]r(rhb I1@\S=(3SF(QePE?bEIIe(IFq܏ktK$9>*qnlSgOBblYtg,q{N^/̂:,o$$~d=HA"GIEX8W*"cOpj,U2QO.G1OQ~)p=(:)E?b*LJ0(^m)e7Xs>#ծ;BB{䏩4Ԯ:.r"URKȢB$@O#SexNm5ppLB F?K{QLi,nC HM;,Qb"qF(bTXF*]b(K6`".*LQ,X&)qEr*MQ`%#M1^M&mj]mѶFmvѶ"Fڗmh-mvѶ"j]mъmh-mH:+-k{hۉ`0T)Ǒ)7a؃mR[F@rXo[i(Rm#u's7דhV׭ԟe.?xywk)nE;WMدmNTcSϔ؏Op+6*109vL[+Z*c\! )t0Aֽ3á|Ñ7JeuӒWe-q㇑yLwb&[bvnb[8$AݽX#ux<}C6XVtoņ=od8Ysx^a飶=`?U\5:6[c`{q}Zk+Io C$ȱƣԞLW2V[hIqKQ;'Q=?yCY;Gf؝폠E*'<);s$L9l~k gў6"ƺ D^yi26ԻhZE:UK1ɦ\4V၇UoP2=mkZty\\{T-?Tf-zFJm* ($–t*HgOO\8!%U=V,D:vqLk;F$cPy+m[N[!l~x &~fBǀ ZhnuP5? :vf;f>rM&vKK ȢH ;U23G66dWn'U-E.6Pm(^EJWI+&E.6[hRmE.6[hRmE.6[hRmE.&9`̬;O_.>Z߽(tm%gk,ߪ(P_$`7XH;Uγ˷C+O.bx5[h[GҼK Wa6wo9,E7B?\LHW2Ў E}7|Ag;%Ȓ+nx#q\ׇK6Z4Bܫ qߨn~g.H*ø# nEwd1ʌUS >C07IH3,_'WA(mS2Q {ޣZ?#RƎRnOwmбs5m9uOirq /}#Ɔ{ibiaY^6*WS]zi~dy, sЄsޱ.[T5(_I~X^)Br/p0~?QTn`y`9bHO$`7!fVCцOl;76ZZ Q>#`sp: H4[zFړw?aY8='hHŞ9H4˶; e<,l|S*ˢk#x\3.fϨL#BFF=X &}Z6G ȧ搑daֺ^B4x5;_[l8o9t:K5-Jq A4TFtϥm\Fe FzԞk˵ ۭFowQSeM>3$olr?6b%^{eB)O#oo#l㵏1T"Υ}rgEm+U5P ¤c1F*Օmbi$ER^A?Ϸ˯42A 2 w=6u8 He='r.V܀?>fMJ诇3 ^X8) i[ٖowpFGݕSKI Dp2}QCXm*a}AM<-*@eKRm3'01qFSsҔ:Ndg&h`9zedq3Jv^M2 x yVV =n%ZYwOݩcM?²i2eFPm;<%}yu CZrL1=wsݏ$3XXmvH(9VF W6.pKT*#TPKzǒiy:fK q) vp;.6եbHF*]m",RFr*MPb#F(Qf(?F*LRbLT)qRbRbbMofZhVxW8D5qi7:vs"&"UvR`N ֦MlR]O<>ttEGr>U隥ޚX[8܏{=p+LM)8Z[Ov׽s(}v[mo>>Me N(q1V/t}< uSnWMCi 5j~/5 ,dK LDQ ['=] $AV?F1M)Vf9bWHq%;Ers.I!PI;#V>s`cHҺm{Iγᘖ+]*0L{CƦRC$2*0J랇5oC兼(|d$bpIRON;T?z1xզ]s?Ss]Kݣ"I-ڮMaH#8~< GWmyVeT"`&рVd&.xvhګj$ZH7 wwֳ^Q ?UPsTr};/ޮm{g}My|HN20TdE )"#QI}NO~+G2 㟭ex2jַ5E*֩X'7ed7CYlv(AkQk?iYGh-r9Sk'pj1@~(b$ɣ94`Qn(;b1NbQf\SF( X. rE4FdRzҷ5J ?Z򟈷 &g_DBaꚝqWs\:;GVxs0taف?>^grz=II-00,NF_p 1MkDi:ʗOb ;a5ڵ?1J>T>v}UEŁnܮv3S\$k&z,aL2t+H΋6#O?j$u r[Iln^|=KOunEra,OMK~1\o立 ߺg2h2i3{ ,G?]zi_t98Mwn3!?]\ޙ_kW-3?d^c3C-kWzu5Cio&¨4I 3LmID?iF*0Rx5v}#^ C8|SPԵ˷Ү&n_ 9,}Ip59#1+g8~# -qdxl$cצ9|V$ikğ=;+ `EBJO9wzMxS7Fn\#\:(Ŀ. N5)DGQXl1nu@S~O^_gۤ^=n z1d2kY4Km.͏٭cG^;RqgΌs-G9EqB<3p 5vuZ:Ff+Gbvd8ztL,LT{`4;]OE摱RW<|u߄FyfuWb \"8;W?奼 rɖP2Fy ){×g 2&EwC ʯxVHWjor\C=?O߸\LyoECOW|u{\_+Ԯ!#b%6] 9o bd*pu?I-?k/d)0%UF>מΘu Gx_ֻ(u+GUBsobK'No\aA`%9d-5]?g>:fq#M!9%y?:^طꚎev c_?:u%m{n"-?#yZvgh JԊU1v)@欑ъSEQ@(P1EbQEo."{"1RM,V<,RGV={-:4ʱ%CkVi'H4:-pN2qer"O‡Q]| 9t dU/ j39jˑ#YxA%7]Ÿ7$ź8# Mܴu, kŨ9`?_\kH$`t֮cz$JlG3cuAWCMV-fQٸ>jHIG,+Et빭Vs ~'8Z.Ҵtms\Y4B2B+`1rqT/#>#O!q/=EI;/FYF 6H*Frnr >S$m$fkvU9=c[dWNP˝רivl:KvM|>1ҵ<}g=KMg$My8 (`4mEX(s;E_-3;^u&\\]O 93+o^7|2ۡ#L \Ιi-a$v{_R4纷q֨tlpy_\MrZq+`u':=b4F&xO1c\94bM^αRFTg& ]J>k%Ŕl*X}zuVcYO7ogiRܯ촕K}+yN:0;=zכI Zs]"W-sh 1۷:O \%ΒA:?[ahdz(=H5|w{-4Vr2 m Hl+¨ $¿_ʛ3#>3" dWD-xͺUg˛X~!AX1oǏj -.@d׆ޙks$O Csc9uPj?Q%M?s&v2z.# \#v t=4}KDZ[+W/eu` %dHe,} rFpx4yڔ1L>Xp[je`uI<dZ8V8_R]*)bcq\xNPY&-%~I;W>z@h;[dmSwd`O|qu#1W!Լ(å߮{o1K2%{{ }Hc dx>S@ D -)/KiaCMjPk%Z2 =r΂Bٴ;DkG#,¸g_}$z_kj`; owvQpJCD>Q@݁wɐdI+/ =E,!?zwO@jco}GRӚg%=Kp<rzltdWPRdu?B5亵fa# s3YwԒE#8?y yLol>T#v'\uƿjBYnF==wG4?~O5'FX@ʁy.#|qRH9#~ 2\  ǘ#gMʣ0~}i43{tӨIzo5/:Xh' 0GIt _ʏ cIs>":dKR?wb9j6c(ڵm,3ģɑ,pGx}zzֿ]h v2=S u/jI!7\ˎs?+5dWFiXgO|z 1v#i_*sf7$}+5[Z_&Y[E GFjvԿV j8dh?,pMADЩ;$uRs@SejWkWAb + O77iq8"71V )|i+DF6?!__5k0hcrhY:M,~Srk n^S[o*+ƻ.-_pbAmچ.Tb̞c@PSV|K<:fɄb7΀mk"|&O(& `c-]vcu oO+I7c*[lzYOs; <ʸ ޵5{_oa?sxyi? ex<'acY\n\2R9 ypZ=4]\6yY>Vzԭ$QbLE;a󯪞GQi̿jx&zr? 1HBNC/Պ^ՠYﹳt6Wybb_2Nv*WK}N\[uhp;}}˘55͛8v8ߵ[ vkGĐG'ɴ͜p`:V_R gVke_}X&F+=~swg-~yXsE}>YeB $ wA0u,i*31dٿqM2O T@;9l<#s:])Ey %Oa?LsY@sGo=>wY äIW[T 9 7#zVŦ\#1FI1ֹ [W^"ծK[Y~sr_?,hH=7\sm`!{0#2XHjvcV.OL@_wWke$7df NNuIutÚ :?1GQ?wS?#jחzeE_]8.02NA*|?{.G5ky$ȑ:4=x]_ wde8ƲG9'?ˍ?EVR͝|Ԑ y`=tR6=6&{&x'Uh~)_t񥦝qY1жA{= R.ldn'v}J.k6VO_0˞>+^Ǿ'mjo˃ Nnv;W=sÖɩkm"Ν "CXl'ϭ 0u0[# 285 Ɨ)yHqrxfO{ 6ldO,iw#;I&G}=m茿09!Pvx#S^Tm}4}# )g KKn FľcGHt WX?Nȕ`?jpv_ 35uh_*?Ƌ\ ivZlؖQnK)RZּN5OC#Fd00 |\Γ uEѮx&l H|kLfhi~W%m46|O~"9$ 1_wqnI @d!I;){O' wiYRNM5qwQU;=M%QP,fɷqQ܁>]i#޹tЃ~5ZZ܎N3b?CUN2?$c]:K zIkwm{!}wH?YLӴk-,?ј6o4:Ey8jN*th7/.ۇ# ʒɏ|R~Mu!g9*mdBr^v-녦Iw#,+2`>xa 34S[1FN -q<O*TO˪'(?fvyqk!HX[ciΫWQ[X-JK1#WYxN]OMMG_Hє(㆔qaH\ 1A7T5B Mfj ۖK|dy=cޣ]ҝ39m@ 8E$@G%‹c[13Y|%m<5L|cs-W/elnLZf싞~XƓcv1XH(A!Ԯe$#s;k- iʓΕT.#sUtnpἫ䅳봑x&i"PeH=,4KlZI$s cwŜ@* |1DqЌ#gwZj ql) oSahm8S?*+-ZZu a#G_Ju<,W2؊?pme91ïݔ ?,<2\,PKoBOW.]#6;V~ᗆ_ ӌGg=0,>=_g_|P{=,2Qdvk%0Li8f9kS~/T-&EœnZ=s@+d`AN2}9"Dcx" )f̸dG(<}\mYM򤩎D[a++ᔌضPDaԬ2>~|W[ekvSj%2c^o1Xu `lAV͝+wZI<;=rz-K>]l4{k[HՙG{ 5ީ e$ R3i+2ص"Dr@0* wX&d2-;zS`;v6ZXY.o!vWZ:G9"9X_[ ?,VΝ6wɐr^O r^BU [RH,bs8v׸bLorOrwQCH"DGĎhW3 I C}M܎}GW.=o "Ub0N$U#Tm.)Mldo߀ڿӠ#Z0ZXJGBK@\v횻cCw*[HnLkg8@qVb-GnA,as= Oy[HbصuFR2&rz~{$7,mGOOBmjkQ8**G%㳈ŧ Au5$Iɤ$Q@4y4fE3p@oKor諞&[4Ju9m y'$_[fm#>`z ľFz55?Mm7fZZۤ,~ 5~`/QE~FcN4Fx?W::'a0?)X vq\+Ed FqPH<c_lx<ʏMm33zM[1!,9a`mc6_%7<-babXzzV,bK(Ze6f)?V|z>ԯkEe ti [˭3SwE 0>\?_Ynt{#B\C#ذ{;5)N$fUS+ۋ`?l%K uu9fbʨH](}j'&KN8Q񷉆n&]8(bIr9 ~ϋ[rA!h`Ve`yL>aH9څB`3z\k&pH|^=IZ|O RYZ Qm֥zdW#prCLj/yvć;}Os]HF%4P}vj[f.'ߞec'ֺݙ)걢4YA>N?,_< ʑxKKjPDZۂiCi8[?ަt;JK`7G]Ne"Tl8Ì\,p Ӹ, cv>7@D %f~mx TSxQfLUЕ<$$v=>֡y?8imo{igc< D܊Ouoܓ'?8c'{TFNMx0j ι I&3+e [;}::ϥ]jyJ3@,\yJWѯ<ɴUx8{fDh-@IwS48n%g)hPԽ$e>^=9׊um{ė&$V*T:Ptдɮo"̒00*?°c#\gm  lo\EMo!IcӯNX%Yd9fR+ yyPje;KW/Pɴz,_S&iPEkm$nC;&ryՙ#4r6 ߑ2k +Cq`a5|)2_[['rTz 9,,q ,zּalnF HMzQ<7D-\}?fib{ morY?{ d` t5iEXw}C}V[vhGsl7%?盏ukrLu-74f@M(<[Iij."z@3'C?__ƚTM%&ʷZm6>l?FL2:{8?1Q<rs]D yeuhUJNH~W)Q$|d}ZVhg(Қ=lϟ-}?βn˕$RqL?Ydr/ތoQUoNwi]ɶ %cہӣ[ FVۆ6Ԛvjzڗvܪ@ xԴ)W~/pOCsE}b$Kens1[z.faO[ ;͐%E>X GPd˶Bw9+ SX:@c5r"F S=ɮDٲv@dW3iq'Kmui*dEU!l+4==X6+d|8?0 ]{[{-9aL6 " Lih>5>o/^KO"Sްucy6F-`SO±HF 䃕Onx?IjZǵ8 cR8NeUur۷sۺm?{#eHz`'ރo/xd~TX.]BYe ygt+YI)qpzWټ)ũh,d*s׀^7ߕt0ĦKUUUFGx&CLkҦq,zeʉJ HW~Sm;:o|+tMceKk%x\!8!sx'V͡msJ8{(ivp3ހ%ѥ:NH-!pVmw~u^ݫ7>f{km>~z}_úcv9b=Iܿϡ9Py';&۩*̌ː8^W^'J mzlBIjqmq*b 0>ԓۯ!m(^^u]*3V8p';#֏im#B䬇ЧFEuާo41j ivѪ./W08I_P+t;ukЇgt뛛=bO6:n z}y8/0ĶP?9cBo Q.o #C{g;!~y^Xb{u `TV#"~f̋'vGPXF?ҧ6.' X4:[\MEea2+ K'1bB8>WKç3FC~|biBܠ57UJ偠Mf̚d'A!? ЙnZ9b2]Z?Htn'9:V ˦_teʘnc=o!6 p@dq}EF8^(ѥ6k$3K=O8ۑPUId5=ZT`Pyjp<ǓQ֣jcFPmPLG DVHeV-YaL+@Y*&J£e+ Q:U֎cd@µ* cjʱEwsUFI5uo.܃m;ƧWA"@vK"o}kНrcm#6[7n'ҦҤLKH|e^7Y2ȭ9d|-gU@l$e?C<`jl;ᾲuZ\h R2Br0acb{5g.͎E a>J" E{ErU;OԮ#$۠'IeF4B2^*/جLqXbK_&wڅZ,k./a" pH`sm0~bM(Q92#z֬4طOSO(@¹fQ$UsTһiijji0TaD<6{g^r#ZK=Ek[˺[ˈ}}FGruY%ӶʼnGO+Ҽ@𾺿+Bǟ@Ce6:՘$,-İs{jy>/%`k{Gλf_,rvzLgݜ5xX·Ǩ37?'sRY΄K!tjgSp_cU+v HU*uf/oa3I]>ui9!dvQ] iq+/)V@7=Ϯl\KHDUGh!0qҡ{|k\iQI]ڲtcE=}xY~qq0!}GZʸЈɉ49.*'!Ci >$er}a+6<⻟7DVc5Y46,!<=QkiW|S/]O.ձuߕuE5I-a=MOk,77ZQ.aǣ kZ)f;8dxzz;Rm`1da?pilv4a+(=) Q`9fT?<~@ƿtz~ӊ,?XO@z+Y9ơ{9Cja]smKnSiRĝ}*\22};4Lr=G45k4E~3@ I+n rMO³I2/ ~B# qM,8mF9n-م^J?urGy5?ι֑yf<z3}7z P{ -݃\tu<QV,zJȪ2E0`M5#HE1ȦeSJZiZVV )M+V Jr-Z)Ld ijJBB*McZB mR hVRtM<տ..\J<{U.FC]&|PGd_+*ݽ+In5ׄ9 j *ofF+P0 tҘ)FL~_5q+EAmEe O}XKІ#5^]>&V]0XUi-g=`1ڋS$0K%H0UIteO+ZF ߌ׸5IifB֤?v3ɄOgtIfCѢV,R==Kaj!<$2S!Y#bjD*5JxE0jB=PJJB=(4݇Ҋ( JiCQE44PJnE4} PlEl}(e.j(oP!vJO,(a1QEg'EBҘc4QLC qҘP(cZ>:TMJ(6CE Bғ>Q@ivJ(';gP>!B'=)=,~*3J( =e(?qhull-2020.2/html/qconvex.htm0000644060175106010010000006602013716271616014345 0ustar bbarber qconvex -- convex hull Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
To: synopsis • input • outputs • controls • graphics • notes • conventions • options

[cone]qconvex -- convex hull

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

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

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

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

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

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

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

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

Copyright © 1995-2020 C.B. Barber


»qconvex synopsis

qconvex -- compute the convex hull.
    input (stdin): dimension, number of points, point coordinates
    comments start with a non-numeric character

options:
    Qt   - triangulated output
    QJ   - joggled input instead of merged facets
    Tv   - verify result: structure, convexity, and point inclusion
    .    - concise list of all options
    -    - one-line description of each option
    -?   - this message
    -V   - version

output options (subset):
    s    - summary of results (default)
    i    - vertices incident to each facet
    n    - normals with offsets
    p    - vertex coordinates (if 'Qc', includes coplanar points)
    FA   - report total area and volume
    FS   - total area and volume
    Fx   - extreme points (convex hull vertices)
    G    - Geomview output (2-d, 3-d, and 4-d)
    m    - Mathematica output (2-d and 3-d)
    o    - OFF format (dim, n, points, facets)
    QVn  - print facets that include point n, -n if not
    TI file - input file, may be enclosed in single quotes
    TO file - output file, may be enclosed in single quotes

examples:
    rbox c D2 | qconvex s n                    rbox c D2 | qconvex i
    rbox c D2 | qconvex o                      rbox 1000 s | qconvex s Tv FA
    rbox c d D2 | qconvex s Qc Fx              rbox y 1000 W0 | qconvex Qc s n
    rbox y 1000 W0 | qconvex s QJ              rbox d G1 D12 | qconvex QR0 FA Pp
    rbox c D7 | qconvex FA TF1000

»qconvex input

The input data on stdin consists of:

  • dimension
  • number of points
  • point coordinates

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

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

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

rbox c > data

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

qconvex s n < data


Convex hull of 8 points in 3-d:

  Number of vertices: 8
  Number of facets: 6
  Number of non-simplicial facets: 6

Statistics for: RBOX c | QCONVEX s n

  Number of points processed: 8
  Number of hyperplanes created: 11
  Number of distance tests for qhull: 35
  Number of merged facets: 6
  Number of distance tests for merging: 84
  CPU seconds to compute hull (after input): 0.081

4
6
     0      0     -1   -0.5
     0     -1      0   -0.5
     1      0      0   -0.5
    -1      0      0   -0.5
     0      1      0   -0.5
     0      0      1   -0.5

»qconvex outputs

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

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

»qconvex controls

These options provide additional control:

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

»qconvex graphics

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

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

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

»qconvex notes

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

»qconvex conventions

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

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

»qconvex options

qconvex -- compute the convex hull
    http://www.qhull.org

input (stdin):
    first lines: dimension and number of points (or vice-versa).
    other lines: point coordinates, best if one point per line
    comments:    start with a non-numeric character

options:
    Qc   - keep coplanar points with nearest facet
    Qi   - keep interior points with nearest facet
    QJ   - joggled input instead of merged facets
    Qt   - triangulated output

Qhull control options:
    Qa   - allow input with fewer or more points than coordinates
    Qbk:n   - scale coord k so that low bound is n
      QBk:n - scale coord k so that upper bound is n (QBk is 0.5)
    QbB  - scale input to unit cube centered at the origin
    Qbk:0Bk:0 - remove k-th coordinate from input
    QJn  - randomly joggle input in range [-n,n]
    QRn  - random rotation (n=seed, n=0 time, n=-1 time/no rotate)
    Qs   - search all points for the initial simplex

Qhull extra options:
    QGn  - good facet if visible from point n, -n for not visible
    QVn  - good facet if it includes point n, -n if not
    Qw   - allow option warnings
    Q12  - allow wide facets and wide dupridge
    Q14  - merge pinched vertices that create a dupridge

T options:
    TFn  - report summary when n or more facets created
    TI file - input file, may be enclosed in single quotes
    TO file - output file, may be enclosed in single quotes
    Ts   - statistics
    Tv   - verify result: structure, convexity, and in-circle test
    Tz   - send all output to stdout

Trace options:
    T4   - trace at level n, 4=all, 5=mem/gauss, -1= events
    Ta   - annotate output with message codes
    TAn  - stop qhull after adding n vertices
     TCn - stop qhull after building cone for point n
     TVn - stop qhull after adding point n, -n for before
    Tc   - check frequently during execution
    Tf   - flush each qh_fprintf for debugging segfaults
    TPn  - turn on tracing when point n added to hull
     TMn - turn on tracing at merge n
     TWn - trace merge facets when width > n

Precision options:
    Cn   - radius of centrum (roundoff added).  Merge facets if non-convex
     An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex
           C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge
    Rn   - randomly perturb computations by a factor of [1-n,1+n]
    Un   - max distance below plane for a new, coplanar point
    Wn   - min facet width for outside point (before roundoff)

Output formats (may be combined; if none, produces a summary to stdout):
    f    - facet dump
    G    - Geomview output (see below)
    i    - vertices incident to each facet
    m    - Mathematica output (2-d and 3-d)
    n    - normals with offsets
    o    - OFF file format (dim, points and facets)
    p    - point coordinates
    s    - summary (stderr)

More formats:
    Fa   - area for each facet
    FA   - compute total area and volume for option 's'
    Fc   - count plus coplanar points for each facet
           use 'Qc' (default) for coplanar and 'Qi' for interior
    FC   - centrum for each facet
    Fd   - use cdd format for input (homogeneous with offset first)
    FD   - use cdd format for numeric output (offset first)
    FF   - facet dump without ridges
    Fi   - inner plane for each facet
    FI   - ID for each facet
    Fm   - merge count for each facet (511 max)
    FM   - Maple output (2-d and 3-d)
    Fn   - count plus neighboring facets for each facet
    FN   - count plus neighboring facets for each point
    Fo   - outer plane (or max_outside) for each facet
    FO   - options and precision constants
    FP   - nearest vertex for each coplanar point
    FQ   - command used for qconvex
    Fs   - summary: #int (8), dimension, #points, tot vertices, tot facets,
                      output: #vertices, #facets, #coplanars, #nonsimplicial
                    #real (2), max outer plane, min vertex
    FS   - sizes:   #int (0)
                    #real (2) tot area, tot volume
    Ft   - triangulation with centrums for non-simplicial facets (OFF format)
    Fv   - count plus vertices for each facet
    FV   - average of vertices (a feasible point for 'H')
    Fx   - extreme points (in order for 2-d)

Geomview output (2-d, 3-d, and 4-d)
    Ga   - all points as dots
     Gp  -  coplanar points and vertices as radii
     Gv  -  vertices as spheres
    Gc   - centrums
    GDn  - drop dimension n in 3-d and 4-d output
    Gh   - hyperplane intersections
    Gi   - inner planes only
     Gn  -  no planes
     Go  -  outer planes only
    Gr   - ridges

Print options:
    PAn  - keep n largest facets by area
    Pdk:n - drop facet if normal[k] <= n (default 0.0)
    PDk:n - drop facet if normal[k] >= n
    PFn  - keep facets whose area is at least n
    Pg   - print good facets (needs 'QGn' or 'QVn')
    PG   - print neighbors of good facets
    PMn  - keep n facets with most merges
    Po   - force output.  If error, output neighborhood of facet
    Pp   - do not report precision problems

    .    - list of all options
    -    - one line descriptions of all options
    -?   - help with examples
    -V   - version

Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
To: synopsis • input • outputs • controls • graphics • notes • conventions • options


The Geometry Center Home Page

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

qhull-2020.2/html/qdelaun.htm0000644060175106010010000006730613716271251014316 0ustar bbarber qdelaunay -- Delaunay triangulation Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
To: synopsis • input • outputs • controls • graphics • notes • conventions • options

[delaunay]qdelaunay -- Delaunay triangulation

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

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

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

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

See Qhull FAQ (local) - Delaunay and Voronoi diagram questions.

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

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

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

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

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

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

Copyright © 1995-2020 C.B. Barber


»qdelaunay synopsis

qdelaunay -- compute the Delaunay triangulation.
    input (stdin): dimension, number of points, point coordinates
    comments start with a non-numeric character

options:
    Qu   - furthest-site Delaunay triangulation
    Qt   - triangulated output
    QJ   - joggled input instead of merged facets
    Tv   - verify result: structure, convexity, and in-circle test
    .    - concise list of all options
    -    - one-line description of each option
    -?   - this message
    -V   - version

output options (subset):
    s    - summary of results (default)
    i    - vertices incident to each Delaunay region
    Fx   - extreme points (vertices of the convex hull)
    G    - Geomview output (2-d and 3-d points lifted to a paraboloid)
    m    - Mathematica output (2-d inputs lifted to a paraboloid)
    o    - OFF format (shows the points lifted to a paraboloid)
    QVn  - print Delaunay regions that include point n, -n if not
    TI file - input file, may be enclosed in single quotes
    TO file - output file, may be enclosed in single quotes

examples:
    rbox c P0 D2 | qdelaunay s o          rbox c P0 D2 | qdelaunay i
    rbox c P0 D2 | qdelaunay Fv           rbox c P0 D2 | qdelaunay s Qu Fv
    rbox c G1 d D2 | qdelaunay s i        rbox c G1 d D2 | qdelaunay Qt
    rbox M3,4 z 100 D2 | qdelaunay s      rbox M3,4 z 100 D2 | qdelaunay s Qt

»qdelaunay input

The input data on stdin consists of:

  • dimension
  • number of points
  • point coordinates

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

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

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

qdelaunay s i < data


Delaunay triangulation by the convex hull of 8 points in 3-d

  Number of input sites: 8
  Number of Delaunay regions: 9
  Number of non-simplicial Delaunay regions: 1

Statistics for: RBOX s 4 W0 c D2 | QDELAUNAY s i

  Number of points processed: 8
  Number of hyperplanes created: 18
  Number of facets in hull: 10
  Number of distance tests for qhull: 33
  Number of merged facets: 2
  Number of distance tests for merging: 102
  CPU seconds to compute hull (after input): 0.028

9
1 7 5
6 3 4
2 3 6
7 2 6
2 7 1
0 5 4
3 0 4
0 1 5
1 0 3 2

»qdelaunay outputs

These options control the output of Delaunay triangulations:

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

»qdelaunay controls

These options provide additional control:

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

»qdelaunay graphics

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

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

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

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

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

»qdelaunay notes

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

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

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

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

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

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

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

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

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

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

»qdelaunay conventions

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

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

»qdelaunay options

qdelaunay -- compute the Delaunay triangulation
    http://www.qhull.org

input (stdin):
    first lines: dimension and number of points (or vice-versa).
    other lines: point coordinates, best if one point per line
    comments:    start with a non-numeric character

options:
    QJ   - joggled input instead of merged facets
    Qt   - triangulated output
    Qu   - compute furthest-site Delaunay triangulation

Qhull control options:
    Qa   - allow input with fewer or more points than coordinates
    QJn  - randomly joggle input in range [-n,n]
    QRn  - random rotation (n=seed, n=0 time, n=-1 time/no rotate)
    Qs   - search all points for the initial simplex
    Qz   - add point-at-infinity to Delaunay triangulation

Qhull extra options:
    QGn  - print Delaunay region if visible from point n, -n if not
    QVn  - print Delaunay regions that include point n, -n if not
    Qw   - allow option warnings
    Q12  - allow wide facets and wide dupridge
    Q14  - merge pinched vertices that create a dupridge

T options:
    TFn  - report summary when n or more facets created
    TI file - input file, may be enclosed in single quotes
    TO file - output file, may be enclosed in single quotes
    Ts   - statistics
    Tv   - verify result: structure, convexity, and in-circle test
    Tz   - send all output to stdout

Trace options:
    T4   - trace at level n, 4=all, 5=mem/gauss, -1= events
    Ta   - annotate output with message codes
    TAn  - stop qhull after adding n vertices
     TCn - stop qhull after building cone for point n
     TVn - stop qhull after adding point n, -n for before
    Tc   - check frequently during execution
    Tf   - flush each qh_fprintf for debugging segfaults
    TPn  - turn on tracing when point n added to hull
     TMn - turn on tracing at merge n
     TWn - trace merge facets when width > n

Precision options:
    Cn   - radius of centrum (roundoff added).  Merge facets if non-convex
     An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex
           C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge
    Rn   - randomly perturb computations by a factor of [1-n,1+n]
    Wn   - min facet width for outside point (before roundoff)

Output formats (may be combined; if none, produces a summary to stdout):
    f    - facet dump
    G    - Geomview output (see below)
    i    - vertices incident to each Delaunay region
    m    - Mathematica output (2-d only, lifted to a paraboloid)
    o    - OFF format (dim, points, and facets as a paraboloid)
    p    - point coordinates (lifted to a paraboloid)
    s    - summary (stderr)

More formats:
    Fa   - area for each Delaunay region
    FA   - compute total area for option 's'
    Fc   - count plus coincident points for each Delaunay region
    Fd   - use cdd format for input (homogeneous with offset first)
    FD   - use cdd format for numeric output (offset first)
    FF   - facet dump without ridges
    FI   - ID of each Delaunay region
    Fm   - merge count for each Delaunay region (511 max)
    FM   - Maple output (2-d only, lifted to a paraboloid)
    Fn   - count plus neighboring region for each Delaunay region
    FN   - count plus neighboring region for each point
    FO   - options and precision constants
    FP   - nearest point and distance for each coincident point
    FQ   - command used for qdelaunay
    Fs   - summary: #int (8), dimension, #points, tot vertices, tot facets,
                    output: #vertices, #Delaunay regions,
                                #coincident points, #non-simplicial regions
                    #real (2), max outer plane, min vertex
    FS   - sizes:   #int (0)
                    #real (2), tot area, 0
    Fv   - count plus vertices for each Delaunay region
    Fx   - extreme points of Delaunay triangulation (on convex hull)

Geomview output (2-d and 3-d points lifted to a paraboloid)
    Ga   - all points as dots
     Gp  -  coplanar points and vertices as radii
     Gv  -  vertices as spheres
    Gc   - centrums
    GDn  - drop dimension n in 3-d and 4-d output
    Gh   - hyperplane intersections
    Gi   - inner planes only
     Gn  -  no planes
     Go  -  outer planes only
    Gr   - ridges
    Gt   - transparent outer ridges to view 3-d Delaunay

Print options:
    PAn  - keep n largest Delaunay regions by area
    Pdk:n - drop facet if normal[k] <= n (default 0.0)
    PDk:n - drop facet if normal[k] >= n
    PFn  - keep Delaunay regions whose area is at least n
    Pg   - print good Delaunay regions (needs 'QGn' or 'QVn')
    PG   - print neighbors of good regions (needs 'QGn' or 'QVn')
    PMn  - keep n Delaunay regions with most merges
    Po   - force output.  If error, output neighborhood of facet
    Pp   - do not report precision problems

    .    - list of all options
    -    - one line descriptions of all options
    -?   - help with examples
    -V   - version

Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
To: synopsis • input • outputs • controls • graphics • notes • conventions • options


The Geometry Center Home Page

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

qhull-2020.2/html/qdelau_f.htm0000644060175106010010000004411513716271251014436 0ustar bbarber qdelaunay Qu -- furthest-site Delaunay triangulation Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
To: synopsis • input • outputs • controls • graphics • notes • conventions • options

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

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

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

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

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

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

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

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

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

Copyright © 1995-2020 C.B. Barber


»furthest-site qdelaunay synopsis

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

»furthest-site qdelaunay input

The input data on stdin consists of:

  • dimension
  • number of points
  • point coordinates

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

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

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

qdelaunay Qu i < data


Furthest-site Delaunay triangulation by the convex hull of 8 points in 3-d:

  Number of input sites: 8
  Number of Delaunay regions: 1
  Number of non-simplicial Delaunay regions: 1

Statistics for: RBOX c 4 D2 | QDELAUNAY s Qu i

  Number of points processed: 8
  Number of hyperplanes created: 20
  Number of facets in hull: 11
  Number of distance tests for qhull: 34
  Number of merged facets: 1
  Number of distance tests for merging: 107
  CPU seconds to compute hull (after input): 0.02

1
7 6 4 5

»furthest-site qdelaunay outputs

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

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

»furthest-site qdelaunay controls

These options provide additional control:

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

»furthest-site qdelaunay graphics

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

»furthest-site qdelaunay notes

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

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

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

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

»furthest-site qdelaunay conventions

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

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

»furthest-site qdelaunay options

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

Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
To: synopsis • input • outputs • controls • graphics • notes • conventions • options


The Geometry Center Home Page

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

qhull-2020.2/html/qh--4d.gif0000644060175106010010000001042407467602544013632 0ustar bbarberGIF87add>JJIQbKSNJILX\ZZZXXXVVSRQEF,GGHHMHKKJIQ]\NfOOdP[bVZPW[VVWZaX_Y`W^QRRW^Y.Z.+J^_JQ\]:<HHUVDFSdZOP:G?nZKLJKIJGH)KKMQJJJQE65GFIMHZf\bTUTSSSTQTUMUW]X^Y_LKV\V\RIRW=WV\W5W;OO#5HS3SW+WZ%Z6IJHI4KQKQUq[;=N!NK,AMMOOJMx!7IBA+LL89EF*J\qK(D67?POLLHFE[ZZDD4ONM8ITTSW SSRRF1LRRQQPPONNSDRMLL5)OLJKJLIKJJLHK-IJN,MIRKJMGF!\K4JJT\DE<"LL8:78DE(DwVNP\[ZNP\YZEDMOKMCCWUUO%JMKKLKJIL|JIHINHGF\c[bZa0LLNaOQU<>ZXRSSW^V]VGWKJW^FES9T@E[!\K7LP+Q\]!KJ9;NONoUSTNOOPDDNODIHKLJUe57FE,1DYZY[aY_TTTT|WOVO$JIOPOGTJJJILLLSjVJJJKHKLDL; LS`VK@K0ONJPNTRxX;<:<BC$EDLOpAEA@QQM68DC)GF\[[IEEXWWCDI>@UUTPOOOONJdjNMMMMLMKLV[AQIHLKKIL}JIILCK:MMKP\[KxZ;=KJWG$PDPPHHTgY 7G,dd9r$ FǘܹۖI BtÉ-FbbB 'M<ʗ.Ky0’(QΞ;5JH1HX\EJMa.9f#HDI$@(ϠC}zڑѐ᜺ۧ)a4x +ѽD8 Էma-)5ZOvs6b1tȺװckW&ۙry+My=N+7}3JWУP6Ǯ]쿗e=ܶm[W݁o>re9ȉ?lٶwmg\A#:1~eXeuRZM՘At5`#@0f?Ybq6|ThyH ȣ#X}&"(#Z\7"iV!!zh #]hՕXZ8#@ -u9D~|:" W_.F̜Tpw2hx}3 ]/I;shv-*xEʧ&Ph)lC9'-s4*~[gJZ)4I {|1+-> +K'9.ꩳB3 TnghfXf,-;7$cBy Y\\B e"$┱, )fqk#3+p2eZ2⤱دsq?#p@l ga4"q81k%i1L9mv*[:Y7m4`tuX" rH ޳Eս.,ll33qHb6 ֱ6̪=t*KSvcri.۴T"MwSFZ60؁s;!ՁsFy1E?C0con3Ɯ sԌ36_IHg!K[ӸARaO DdhaV_G,ˠs0-[ZJP!SKn-ZP/ ! hoxAPC .0f0 Z Pc2͎qC.%4y51OXTQ:B(@@kq q^̋&BzFs.Vq8@E0@5/p_g"4!}!GqA!b \FPi>DN^?:(QriGH!n xN ̦/Z Ґ\te:lB0& Ħ6 'Jq}0YlF !C ,Q"q a/K0QTH%FӨ q38B9(~Rc;xO hE-jјPhgz բI bphUN(NiFs@=՟/ZPvU%E-UDuQiN7*?;x4[TuPUEcִ֚4MQLݕҘa@Jt2mh5}͐oGiv]<*Xax9ETO:3>#L`B2!^ /4ġ@x^-H]t>8*ȭ|3v-4\A=caEaG}}O$}~MU 7/c4sRp РL7'l}@o~LZqG 8(Hp =@dmsoր7' їZ 0]p{of{z7d} ؁>pp(K*PYLՀD Wx h؏  0+&7 A0PTV H0 xz@s D gpIIoP)z 99y h#zXD@ b> 1ɂHo҈ 5 3q;HXA `Fseꇌj}0 k}0/ и{pQ<8voyЊo?,A &p S{ick7,yOcW}W ɠb0/Fwɋ>6vZ:9 F0/R 1HgK4IٜtйL`V}/G IMi, Pɜ)5Mُ@ɛYO 9L}幜ٜQYIiY0 `yܹe iY0Wiُ/MɔG湜P0:9 N0R 𚃘 1Z z@ ,;ʣf(y51 U Z ` MꤻgBdYT/`:yI}v0j,nfg Jѧ٠nZcɨ0ٝyڡɞL   ~J y7'z1ʪJ**" &Z?ګ-:/Jo9 `B l|PZ)kI:+6:&:ખ`銋Ю$j`FʦzRZ w:K 1媘 HZjʚ&  {Щf e;qhull-2020.2/html/qh--cone.gif0000644060175106010010000000560207467602544014251 0ustar bbarberGIF87add[~.TopPZ OXa>Uj3.OP*$?C1Lk5k4'#?9$k)KTRn(7+-aV_"/*&%Z@K\!JZ W=:5Q7]/F@(Y()]/D_)$&Kb>2;<}M7%,'X{-NY zvsUu*$j(f2?S=Q"9-\N:?I^C]B\AOz1L[!<6^caqpm_0T^"S\!86Oq*1.$PBCK$4''TVFEO:PRW.OQ(%MOk5?9LX >9&!608&U3+j>=}IU_"L`#E-$!T;QBGcZ{-2i*b>P:3-2-OP6%ikj3Q($qMY $j)put(D\01#:{O]C%.;B/)*"+{~{M5R\!QZ %FK33<520[@G3PD{7%k)LSSMq,-a.6/21.]B$#Xz[<=>9$g+<7Ls.HP_0Z*F?D^I.Qt,#TQM4=;$$GdQBAGCH;{K3=)&Q*&8[1/GP*HTVSUb0:)QSNPEd#'34Uw,>8Ne%\ZT'&U^" ::9s;!d*Ea=~L0+)*,dde H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗%-s_ & 5M"#[ u-[4S"ENUr"P:z:uv#gV=Im 6Rf$BտfՙދI^DS:\1 ƘWO/`%9s? بV6\vlr־MZ.!*gf͵ {lᄈ'[C vJ dP0|AnOP N~AL3j )B2nl}Uh8IQa"ލU%b8֝GFs &\hr/k\((y"*fib) h}fib!h&RUh漉Y |)daKLb 4s-R棁}ӌ~@y^PN$tsUɭ*Bd6yv>ݐb(kqъȥ^ Uᰬ4;j8֗C%6;gPNjqT,$ń& qh6@APQpc;LlŸkCM01$z TT`rLx\Wӧئk4U`JjIPǁ*. l% c)ҌTD Ph/qFC`݌fCpƽ+۴+I#uםr/|JG|, $L:|iktsD-P mhJ=ܰOC6 8<hJt9t|-H<VZU `6''C +62"M)uBV"MH>qK^bOGI7c4@nqy|5@%C` Ri`PȜ)Aڙ K1B_x(D!ɮ۳Ce(q!@U J s4iRl1~ޣx&m0K%i D+>>A,LFO@V$=ajD9HIQ#B"O]*1JP$YUZhP| KU@oa#F$C8w10$9h9Z( F_.*I0U0e@&PfR(h;=AGXCLkѪ(7IҀd*j)HBnJZ1Р X0$ 42,@]-@N)H?RN1 zQ1bԢF*Rz<i)XBIJ .@67en$GEP>)?TRufAkhC@m#1J :,([7Pc-4: ZfV& g hcȶ,nvu&3A>WuH\6^uK굳=oA@mڰ@KI :5Tmqt Xx`5X*V 1z $ dmay(01+ Wr 4k:#%Np6@'XU[(aM${Nn3Aվ$ l2ef+.|6M^;^$f @Npcu[h3T^B/ *A@QbKczӅFM hV_{>r.ZZ3Ԧû|a/.4XA g?.."=j0NpF* ф[ tBȫ Νu렧;H D—üh^`XGkYX OH4 o0N" A@\8@bZ sN.p|pЂV @OB^\PF&)!pE@;qhull-2020.2/html/qh--dt.gif0000644060175106010010000000727407467602544013743 0ustar bbarberGIF87add^+!6o$08%BL&7Go$Z5 #4hWIC"H4i9;QW5 Fw;<5!aU2qIc<%b<$WWLNM7YXo].XRPZ6pD_J*_:$ SwHJ [_>F=D-QQEwR<::<:AHbYN0G<@AP&FvW73TN2V1#C&IHHR5U )5x O-WW?!DY g&!2-+BuP('z="Nh[L!O &H]I[J+(pBO&AO%,<H)F'PL:MN,(EA@'zNVNT&9CG*FA--.IJ89CuDM1 pIKeLMmS0RUSXXb=$WXjOAz;McuUCn@v!NhCTTL5(_2;55;;<<==??A|A==@|@AzABxBDtD$$GnGHlHIjIN`NU1O^OP\PQZQRXRSVSTTTD$*PYF_> 7_> EQBL69O`FeIT!U[\: f1 V>EyJN+'Q3!/,R1M4&H*b?AO&n2!H*[8"I9.W:Y"F%R-P%!\Vd?$MM!]EYK5f<.G09;?#3@%FoHJgL R0u@UUb?%c=&\CVV^f,ddk H*\ȰÇ#JHŋ3jȱǏ CIɓ(S܈ʗ U%J%̛RAD"j}|iώ H&*tp$KJ'+D%ML6TċV) 99ilO6R2A+1ڮCu+e*Xb bp@ώ#;fS ښ*7Ĉ% 9ۍ&)Z q)L%ңk+G.z]ܲ .b&TCZdܶ?0uNuaXy-_NJ.cD3Mc`,-igkDЦNڵs8_(hۄ4z|bFwѨU5t934 ;lr]:!.( 1 8MdpdF{vcT6@Z\&tlaX&XUd&_PS `pAYxb61ġd8Y É! |pACN4`wh$.۸Î*Z8H 'L7(Xs"> $9DN]9 H G0 L:;HJ $w* dbJ/[2." (𒄯 ^up DcB4Ѷ|:j;/`(14ȯc0FR1ͧOkkx+ANI< 24w`BlB2QoŽ쬠LS rdEǬ JЈL65tG'zX"q]6FsT("P+r'&C+=ZFNp˛1` (3P)d ̠C$ A _څ߆CM* R(hRC % =k OJ#hR-L|N@ DhE-t^+A8jpbl ΰ M< h2Gb0j^@@0E5y3@&` ЀthV@7 X@nR8`E0{@ t @F<` DRQQ8"!q#B6;2 4Ad'$`sPj1R3Gr"ɍR =በ e(I g $PD$QN Х@pi qk&( 'Lw0b0'° CL! a1.H*b!N G,4ƶD8`wL25Q2xM@!! O,`eh1P,"YZAtu- jh%c0"v0<@/!ȠH1X$ϻ)0'l<$`Ma0>Tm,8*&X`@H!X؏5)Y_шlp@" )@r=K a"iZF h,٨f l ]XC8@x '%paH 6` D'&+|@*I -p%$xM'1)$ ڑT^n66<6oxB](#h9 BS_.8U0dAwP %PT E#[i!zXᐍ#smP0(-*Eg@ zq0@|D2Cbj0dHP5/h Pv(dp~Fև*A <#]0S -CU.  >}0xj~ )4 j #l_ŀ IaDC 7CȀe>pz 0U-Ph _$ *WPXp1<X 0t$0]h#S  8r|(/P*<2l 0a V Є >/PQXAЅP@!1k(N~7Qgp 5P 'A 7|#p1hC 4Y5P | /@e!  iseq8|c P v<8yp KY 5 a 5UW9A|0c061F ȀK#@t):rٙ;qhull-2020.2/html/qh--geom.gif0000644060175106010010000000047607467602544014260 0ustar bbarberGIF87a((LLL,((0Iٸ8'\Bl벧4_ @}9@,DgWl:{dPpZN^^F̈́a!a5gp'n}~Cil|Ui~WuJO_~LVqALrePnkq2g;[hkvkhƨe^j|tJxpFSz|c+@]   #WĊT Ə(^I2E;qhull-2020.2/html/qh--half.gif0000644060175106010010000000475107467602544014243 0ustar bbarberGIF87add.=-/HO%#-ZdbQ?qR0^S;D6gE2hTN;BGGPZLL9 \%+'/<>lN..hPHyJJHFNOJ91BW.\pX`NNOIGUM8No44II&B;X[@@XC2[:8']eqH8LPY\;.X_l)TKKeo|$.%HJO}84@CSSSQQQYkMMMkjRcmO1WgLKLSHIidEMOg'h7/BBfpR0>>7JJ7:0IBd48RW43#Zk$5'-19D`'=AgK46OS*-u&LHHGF?Og;4b9UYWKzvZ~EEQTeFG}FHH362-<,SXBBo.3#rS1HUXO?=JVVYA,Z*6,`@)MM`T@EBaAOS<=7-0[[\-g+.{JJ7YRSSG#Y:VY=8NOOfK?KMLn9rWN:i-FF|yNK/=-OV] (!Ie^:tQJ\ (Q-P/\DueHb1ɓ<`Æ%kV/kbFط`:דZ4 WM2sˤ+&'aDHA/ 7Lgs bKBxn=S~%ܭ~Uu/bDC[eрaQo"CNj' >Nk׮g GZ m OY6#=M˻Ф;X)b_XwM1pfaaّK;D~שbMl%:K< 5C5p|f.\̡rxf 8K=f _VR'Y@0mr )Fah6[#rB j5G1!!\q$,[G邗Q>,^0GI*ccNk_(*&^?DN2A>L0Be(E@IoJnI6-LFuBm+:DU2 )VT!~_ I!F>99=;`G #(5"nW]hlAN a]/D"E4fesjaEPF[I*1'RVv *fFBFIML4L*:#_@DK2-fmoM+U9+$DN=}uuUL&??=%)F$BU<;?|[5?4>-E;K87'F 4j{ov=eF5z4tzet+UGTF8l7:TMX}<9[BO:#'*UlC63(ng*7f".b-d-2hA3GF`XeHETH:^N+Sie?`:3ZK2M[]L4\";'Mk_hI;VK<:iG[.[vR<4-BFtydV>J1#'6@9E :&jc,C89T'yeUe-t@CcV2ht:-;?3RRRsBGJ>E-GT*zqEffr)>L!RfO>yE|wJZ|ZL(Z)04@*+7..Q2FIMT`)3 8877b3%:(/W,M3ilDg^xc`V;8@B@`JO2A=tjZAu*G`Ye5(N+\h,dd H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0c|&32*jĩW<}()CjW^6&ߕ+ʕomkuJ&NOU)Um^5>ZkK †A6FK.-e>}ccbnˌ[~)Ť+.fW9hlPD5e9[Fxmܚڴi+R$ xW.w 1'(Ơ&HPGJ9[OgqĀ7d`*,k $ݧO2>(Ac9 ,,~()%hSLU <$c x`"Ȣ$qʂAIY3P$'ָ@\'Z@5$rB )5 $83L8d쩩7jq5p-T3S.A4n^4ndbje-SƧ9KI5 l T:p~ {DR@lG7l)4R|F>nɶdZ"L̢Ha9.*3̘@$S (a,njE.TjJc OqH+lau་+%P3֜% O;͆.`4!Oa7!J˒|mI7sԻ쒪 rW;pTi20ؾ" ,I@N!nJݨ p 3:RL.-f p_@/oq yB\nPObq6 x'[(F6G%x:%$W&ސQ>2TIdK"Y:j_#HA gK(. ' \xEq@$(0_1(ҊGXYdf7 9KfbXȶU P0p \\%AhE3jZÒ!s VˍXke"q`-I90Sj$%jBes; E$".mm Uܒ_>MF"֤oX Ǧ[IxMnr8VBq06W>dc8 *x_(;a ^]c J80ұ ]$>B)}mjǵZCN0C' sy>-u(gl@!{B ah(%lQr;hpY y5>0~@ Glb?UK $  s@~~pzaVc|pp X@ c}q gz|n p 0xt 1|<ȃbHpGx0| Vh_`J Tfn{1J RhthPm BP6PHPX+xE (zsxVa@|j@Pc (  Y8 @$0 j@R8J Xv7s(` @ ÀR苄|hH ` f {Ҩ0 ؋@3p+@ _p@̨ ސ@(0}m v ppvXt 0 IH(G@ Qhull code

Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
To: Imprecision in Qhull
To: Qhull code: contents


[4-d cube] Qhull code

This section discusses the code for Qhull.

Copyright © 1995-2020 C.B. Barber


»Qhull code: contents


»Reentrant Qhull

Qhull-2015 introduces reentrant Qhull (libqhull_r). Reentrant Qhull uses a qhT* argument instead of global data structures. The qhT* pointer is the first argument to most Qhull routines. It allows multiple instances of Qhull to run at the same time. It simplifies the C++ interface to Qhull.

New code should be written with libqhull_r. Existing users of libqhull should consider converting to libqhull_r. Although libqhull will be supported indefinitely, improvements may not be implemented. Reentrant qhull is 1-2% slower than non-reentrant qhull.

Note: Reentrant Qhull is not thread safe. Do not invoke Qhull routines with the same qhT* pointer from multiple threads.

»How to convert code to reentrant Qhull

C++ users need to convert to libqhull_r. The new C++ interface does a better, but not perfect, job of hiding Qhull's C data structures. The previous C++ interface was unusual due to Qhull's global data structures.

All other users should consider converting to libqhull_r. The conversion is straight forward. Most of the changes may be made with global search and replace. The resulting files may be checked via eg/make-qhull_qh.sh. It performs the inverse mapping for comparison with non-reentrant code.

For example, even though the original conversion of libqhull to libqhull_r required thousands of changes, the first run of reentrant Qhull (unix_r.c) produced the same output, and nearly the same log files, as the original, non-reentrant Qhull (unix.c). The original conversion was made without the help of eg/make-qhull_qh.sh. Conversion errors almost always produce compiler errors.

Suggestions to help with conversion.

  • Qhull 2019.1 introduced eg/make-qhull_qh.sh. It simplifies the task of checking the consistency of reentrant and non-reentrant C code for Qhull.
  • Compare qconvex_r.c with qconvex.c. Define a qhT object and a pointer it. The qhT* pointer is the first argument to most Qhull functions. Clear qh_qh-<NOerrext before calling qh_initflags(). Invoke QHULL_LIB_CHECK to check for a compatible Qhull library.
  • Compare user_eg2_r.c with user_eg2.c
  • Compare user_eg_r.c with user_eg.c. If you use qhT before invoking qh_init_A, call qh_zero() to clear the qhT object. user_eg_r.c includes multiple Qhull runs.
  • Review user_eg3_r.cpp. As with the other programs, invoke QHULL_LIB_CHECK. Simple C++ programs should compile as is.
  • Compare QhullFacet.cpp with the same file in Qhull-2012.1. UsingLibQhull was replaced with the macro QH_TRY_() and 'qh_qh-<NOerrext= true'.
  • For detailed notes on libqhull_r, see "libqhull_r (reentrant Qhull)" and "Source code changes for libqhull_r" in Changes.txt.
  • For detailed notes on libqhullcpp, see "C++ interface" and following sections in Changes.txt.
  • For regexps and conversion notes, see README_r.txt (unedited).

Suggestions for updating src/libqhull/* from src/libqhull_r/*:

  • Make edits to libqhull_r/* instead of libqhull/*. The reverse update is more difficult, as desribed above.
  • Use 'eg/make-qhull_qh.sh libqhull_r' to automatically convert libqhull_r/* to qhull_qh/*
  • Compare src/qhull_qh/ to src/libqhull/ using Beyond Compare (www.scootersoftware.com) or another directory comparison utility.
  • Configure Beyond Compare for expected differences:
    • Rules > Importance > Unimportant text
      '$Id: ', '$DateTime: ', 'char qh_version'
    • When updating 'Unimportant text', select 'Use for all files in parent session' and, optionally, 'Updated session defaults'
    • Select 'Minor' to ignore unimportant text
    • Review Rules > Importance > Mark grammar elements. Be sure to include 'Comment'
  • Almost all unmodified lines should be identical.
  • Use 'Diffs' view to review diffs, and 'All' view to copy diffs. Otherwise wrong lines may be changed
  • Copy modified lines as needed.
  • Be careful of removing true differences, such as those involiving
    • DEFqhT
    • oldqhA, oldqhB
    • qh_QHpointer
    • qh_last_random
    • qh_rand_r
    • qhmem
    • qhstat, qhstatT
    • rbox_inuse
    • rboxT
    • "renentrant" vs. "non-reentrant"

»Qhull on 64-bit computers

Qhull compiles for 64-bit hosts. Since the size of a pointer on a 64-bit host is double the size on a 32-bit host, memory consumption increases about 50% for simplicial facets and up-to 100% for non-simplicial facets. If the convex hull does not fit in the computer's level 1 and level 2 cache memory, Qhull will run slower as it retrieves data from main memory.

If your data fits in 32-bits, run Qhull as 32-bit code. It will use less memory and run faster.

You can check memory consumption with option Ts. It includes the size of each data structure:

  • 32-bit -- merge 24 ridge 20 vertex 28 facet 88 normal 24 ridge vertices 16 facet vertices or neighbors 20
  • 64-bit -- merge 32 ridge 32 vertex 48 facet 120 normal 32 ridge vertices 40 facet vertices or neighbors 48

For Qhull 2015, the maximum identifier for ridges, vertices, and facets was increased from 24-bits to 32-bits. This allows for larger convex hulls, but may increase the size of the corresponding data structures. The sizes for Qhull 2012.1 were

  • 32-bit -- merge 24 ridge 16 vertex 24 facet 88
  • 64-bit -- merge 32 ridge 32 vertex 40 facet 120

»Calling Qhull from C++ programs

Qhull 2015 uses reentrant Qhull for its C++ interface. If you used the C++ interface from qhull 2012.1, you may need to adjust how you initialize and use the Qhull classes. See How to convert code to reentrant Qhull.

Qhull's C++ interface allows you to explore the results of running Qhull. It provides access to Qhull's data structures. Most of the classes derive from the corresponding qhull data structure. For example, QhullFacet is an instance of Qhull's facetT.

You can retain most of the data in Qhull and use the C++ interface to explore its results. Each object contains a reference to Qhull's data structure (via QhullQh), making the C++ representation less memory efficient.

Besides using the C++ interface, you can also use libqhull_r directly. For example, the FOREACHfacet_(...) macro will visit each facet in turn.

The C++ interface to Qhull is incomplete. You may need to extend the interface. If so, you will need to understand Qhull's data structures and read the code.

The C++ interface is not documented. You will need to read the code and review user_eg3 and Qhull's test program qhulltest. Please consider documenting the C++ interface with Doxygen or another javadoc-style processor.

user_eg3 demonstrates the C++ interface. For example, user_eg3 eg-100 prints the facets generated by Qhull.

    RboxPoints rbox;
    rbox.appendPoints("100");
    Qhull qhull;
    qhull.runQhull(rbox, "");
    cout << qhull.facetList();

The C++ iterface for RboxPoints redefines the fprintf() calls in rboxlib.c. Instead of writing its output to stdout, RboxPoints appends the output to a std::vector.

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

The same technique may be used for calling Qhull from C++. The class QhullUser provides a starting point. See user_eg3 eg-fifo for a demonstration of Voronoi diagrams.

Since the C++ interface uses reentrant Qhull, multiple threads may run Qhull at the same time. Each thread is one run of Qhull.

Do not have two threads accessing the same Qhull instance. Qhull is not thread-safe.

»CoordinateIterator

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

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

»Qhull

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

»QhullError

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

If error handling is not set up, Qhull exits with a code from 1 to 5. The codes are defined by qh_ERR* in libqhull_r.h. The exit is via qh_exit() in usermem_r.c. The C++ interface does not report the captured output in QhullError. Call Qhull::setErrorStream to send output to cerr instead.

»QhullFacet

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

»QhullFacetList

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

»QhullFacetSet

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

»QhullIterator

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

»QhullLinkedList

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

»QhullPoint

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

»QhullPointSet

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

»QhullQh

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

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

»QhullRidge

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

»QhullRidgeSet

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

»QhullSet

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

»QhullVertex

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

»QhullVertexList

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

»QhullVertexSet

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

»RboxPoints

RboxPoints is a std::vector of point coordinates (QhullPoint). Its iterator is CoordinateIterator.

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

»Cpp questions for Qhull

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

»Calling Qhull from C programs

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

For examples of calling Qhull, see GNU Octave's computational geometry code, and Qhull's user_eg_r.c, user_eg2_r.c, and user_r.c. To see how Qhull calls its library, read unix_r.c, qconvex.c, qdelaun.c, qhalf.c, and qvoronoi.c. The '*_r.c' files are reentrant, otherwise they are non-reentrant. Either version may be used. New code should use reentrant Qhull.

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

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

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

Qhull provides build/qhull.pc.in for pkg-config support and CMakeLists.txt for CMake. Using back-ticks, you can compile your C program with Qhull. For example:

  	gcc `pkg-config --cflags --libs qhull_r` -o my_app my_app.c

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

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

»How to avoid exit(), fprintf(), stderr, and stdout

Qhull sends output to qh.fout and errors, log messages, and summaries to qh.ferr. qh.fout is normally stdout and qh.ferr is stderr. qh.fout may be redefined by option 'TO' or the caller. qh.ferr may be redirected to qh.fout by option 'Tz'.

Qhull does not use stderr, stdout, fprintf(), or exit() directly.

Qhull reports errors via qh_errexit() by writting a message to qh.ferr and invoking longjmp(). This returns the caller to the corresponding setjmp() (c.f., QH_TRY_ in QhullQh.h). If qh_errexit() is not available, Qhull functions call qh_exit(). qh_exit() normally calls exit(), but may be redefined by the user. An example is libqhullcpp/usermem_r-cpp.cpp. It redefines qh_exit() as a 'throw'.

If qh_meminit() or qh_new_qhull() is called with ferr==NULL, then they set ferr to stderr. Otherwise the Qhull libraries use qh->ferr and qh->qhmem.ferr for error output.

If an error occurs before qh->ferr is initialized, Qhull invokes qh_fprintf_stderr(). The user may redefine this function along with qh_exit(), qh_malloc(), and qh_free().

The Qhull libraries write output via qh_fprintf() [userprintf_r.c]. Otherwise, the Qhull libraries do not use stdout, fprintf(), or printf(). Like qh_exit(), the user may redefine qh_fprintf().

»sets and quick memory allocation

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

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

»Delaunay triangulations and point indices

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

  facetT *facet;
  vertexT *vertex, **vertexp;

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

»locate a facet with qh_findbestfacet()

The routine qh_findbestfacet in poly2_r.c is particularly useful. It uses a directed search to locate the facet that is furthest below a point.

For Delaunay triangulations, this facet is either the Delaunay triangle or a neighbor of the Delaunay triangle that contains the lifted point. Qhull determines the Delaunay triangulation by projecting the input sites to a paraboloid. The convex hull matches the Delaunay triangulation at the input sites, but does not match along the edges. See this image by F. Drielsma. A point is green or yellow depending upon the facet returned by qh_findbestfacet. For points near an edge, the circumcircles overlap and the adjacent facet may be returned.

For convex hulls, the distance of a point to the convex hull is either the distance to this facet or the distance to a subface of the facet.

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

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

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

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

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

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

»on-line construction with qh_addpoint()

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

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

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

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

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

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

initialize qhull with an initial set of points
qh_qhull();

for each additional point p
   append p to the end of the point array or allocate p separately
   lift p to the paraboloid by calling qh_setdelaunay
   facet= qh_findbestfacet (p, !qh_ALL, &bestdist, &isoutside);
   if (isoutside)
      if (!qh_addpoint (point, facet, False))
         break;  /* user requested an early exit with 'TVn' or 'TCn' */

call qh_check_maxout() to compute outer planes
terminate qhull

»Constrained Delaunay triangulation

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

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

»Tricoplanar facets and option 'Qt'

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

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

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

See qh_detvridge for an example of ignoring tricoplanar facets.

»Voronoi vertices of a region

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

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

»Voronoi vertices of a ridge

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

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

»vertex neighbors of a vertex

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

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

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

»How to debug Qhull

Qhull continually checks its execution, so most errors will stop Qhull with an error message. Additional checking occurs for verified output ('Tv'), check frequently ('Tc'), check for duplicate ridges ('Q15'), and tracing at level 4 ('T4').

If Qhull detects an error, it writes a descriptive error message to stderr, and exits with an exit status code (see following). The C++ interface captures the message in Qhull::qhullMessage. If Qhull::setErrorStream was called, it writes the error message to Qhull::errorStream.

If a Qhull segfault occurs, turn on tracing with option 'T4' and flush output (qh_fprintf) with option 'Tf'. See core dumps and segfaults.

If Qhull never finishes, is Qhull running slow or was there an infinite loop?

  • If you are running Qhull under Git for Windows or MSYS2, 'qhull' waits for stdin instead of displaying a help message. Use 'qhull --help' instead.
  • Turn on monitoring with option 'TFn'. Qhull normally takes approximately the same amount of time per point. If the output is too large, it will slow down due to main memory or virtual memory.
  • If there are large, non-simplicial facets, see "quadradic running time" in Limitations of merged facets.
  • See Performance and infinite loops for further suggestions.

If a Qhull error occurs, try to simplify the problem.

  • If new to Qhull, start with short examples that you can work out by hand. Your problem may be due to misunderstanding Qhull's output, or an incompatibility between your program and the Qhull libraries.
  • Can you produce the input that triggers the problem? The input to Qhull includes the dimension, number of points, point coordinates, and Qhull options. Qhull is usually deterministic for a particular build.
  • Can you duplicate the problem using one of the Qhull programs (e.g., 'qhull' or 'qconvex')?
  • Does a shorter output trigger the problem?
  • Can you turn on tracing with option 'T4'? If too much output occurs, use the trace options to reduce the trace output.
  • The test program, 'eg/qtest.sh', repeats a qhull run for intermittent errors. It can log a qhull run to 'qhull.log' and a reduced log, 'qhull-step.log'.

If the segfault, infinite loop, or internal error was due to Qhull, please report the error to 'bradb@shore.net. Please include the input data (i.e., point coordinates) that triggered the error.

»Qhull errors

Qhull errors start with 'QH6...' and Qhull warnings start with 'QH7...'. The error message and error code are arguments to a qh_fprintf call. After printing the error message, Qhull exits with an exit status code. The exit status code indicates the type of error:

  • qh_ERRinput (1) -- badly formed options or input. Badly formed options are reported as Qhull warnings. Unless option 'Qw' is specified, Qhull reports error QH6035 or QH6037 and exits with qh_ERRinput. Inconsistent options typically report an error.
    The input to Qhull specifies the dimension and number of points. If the input contains fewer or more points than coordinates, Qhull reports error QH6410 and exits with qh_ERRinput. If option 'Qa' is specified, it reports warning QH7073 and continues execution.
  • qh_ERRsingular (2) -- singular input data. If the input data is singular or flat (e.g., a line segment in 2-d), Qhull reports error QH6114, QH6379, or QH6154. Qhull calls qh_printhelp_singular to print an explanation of the error. It exits qhull with qh_ERRsingular.
  • qh_ERRprec (3) -- precision error. By default, Qhull handles precision errors by merging. If merging is not possible, or if a precision error is identified after Qhull finishes, Qhull reports an error and calls qh_printhelp_degenerate. It exits qhull with qh_ERRprec.
  • qh_ERRmem (4) -- memory error. If Qhull runs out of memory, it reports an error and exits qhull with qh_ERRmem.
  • qh_ERRQhull (5) -- internal error. If Qhull detects an internal error, it reports the error and calls qh_printhelp_internal. It exits qhull with qh_ERRQhull.
  • qh_ERRother (6) -- other errors. If Qhull identifies an error while reporting another error, it prints "qhull error while handling previous error" and exits Qhull with qh_ERRother. The same exit code is used for vertex id overflow and missing exitcode for qh_errexit.
  • qh_ERRtopology (7) -- topology error. If Qhull cannot recover from a topology error, it reports the error and calls qh_printhelp_topology. It exits qhull with qh_ERRtopology.
  • qh_ERRwide (8) -- wide facet error. If Qhull produces an extra-wide facet, it reports the error and calls qh_printhelp_wide. It exits qhull with qh_ERRwide.
  • qh_ERRdebug (9) -- debug. Use qh_ERRdebug for exits from debugging code.

»Qhull infinite loops

Except for list traversals, most loops in Qhull are limited by a count or the size of set. Linked lists of facets and vertices terminate with a sentinel whose next element is NULL. If a programming error inserts a link to a previous facet or vertex, an infinite loop occurs on the next traversal. Qhull periodically checks and corrects its linked lists for infinite loops (qh_checklists).

»Qhull trace options

Qhull's trace options are the key to debugging Qhull. They describe an execution of Qhull at various levels of detail, with various options to control what is traced.

  • Level 0 ('T-1') -- Key events are prefixed with '[QH00nn]'
  • Level 1 ('T1') -- Main steps in the program are prefixed with '[QH1nnn]'.
    [QH1049]qh_addpoint -- When Qhull adds a point, it logs information about the point, the convex hull so far, and changes since the previous qh_addpoint.
  • Level 2 ('T2') -- Minor steps in the program are prefixed with '[QH2nnn]'.
  • Level 3 ('T3') -- Merge and other events are prefixed with '[QH3nnn]'.
  • Level 4 ('T4') -- Detailed trace of Qhull execution.
  • Level 5 ('T5') -- Memory allocations and Guassian elimination. Memory allocations are prefixed with "qh_mem " followed by address, sequence number, alloc/free, short/long, etc. If you sort by address and sequence number, each allocate should be paired with its free.

These options select when tracing starts or stops. It limits the amount of tracing, especially in high dimensions.

  • 'TAn' -- stop Qhull after adding n vertices
  • 'TCn' -- stop Qhull after building cone for point n
  • 'TMn' -- turn on tracing at merge n. When Qhull reports an error, it reports "Last merge was #nnn".
  • 'TPn' -- turn on tracing when point n is added to hull or point n is referenced. When Qhull reports an error, it reports "Last point added to hull was pnnn".
  • 'TVn' -- stop Qhull after adding point n, -n for before
  • 'TWn' -- trace merge facets when width > n

Additional logging by facet id (fnnn), ridge id (rnnn) or vertex id (vnnn), may be enabled by setting qh.tracefacet_id, qh.traceridge_id, or qh.tracevertex_id in global_r.c/qh_initqhull_start2.

»Qhull core dumps and segfaults

If a segfault occurs, use option 'Tf' to flush output after every qh_fprintf. Logging will be significantly slower than normal.

The following debugging plan usually identifies the error

  1. Trace execution at level 1 with flush after each qh_fprintf and output to stdout ('T1 Tf Tz').
  2. Repeat at level 4 after the last qh_addpoint (QH1049, 'TPn'). Add line numbers to the log by piping the output through 'grep -n .'.
    • If there is too much level 4 output, repeat at level 2 to find the last qh_mergefacet (QH2081) and then trace at level 4 from the last merge ('TMn').
    • If there is still too much level 4 output, identify one of the last level 3 events and add debugging to the corresponding trace3 call. Be sure to mark the code for removal. For example
        if (facetA->id==4675)
          qh->IStracing= 4; /* DEBUG */
        trace3((qh, qh->ferr, 3020, "qh_triangulate_facet: triangulate facet f%d\n", facetA->id));
      
  3. Identify the location of the failure using a build of Qhull with debug symbols.
  4. Use the debugger to find relevant facet ids, ridge ids, and vertex ids. These identifiers will appear in the level 4 log.

»eg/qtest.sh for intermittent errors and logging

For intermittent errors, use 'rbox' to generate random test cases, and eg/qtest.sh to invoke multiple runs of qhull. When a failing case is found, rerun eg/qtest.sh with the test case identifier. It produces qhull.log and the corresponding reduced log, qhull-step.log. These logs include line numbers generated by 'grep -n .'

qtest.sh provides the following options

  • N qhull runs (qtest.sh -N 'rbox c | qhull')
    execute the qhull command N times with rotated input 'QR1', 'QR2', ...
  • N random qhull runs (qtest.sh N 'rbox c | qhull')
    execute the qhull command N times with random rotations 'QRn', ...

  • N 'rbox|qhull' runs (qtest.sh -N 'rbox-opts' 'qhull-opts')
    execute rbox and qhull N times with random inputs 't1', 't2', ...
  • N random 'rbox|qhull' runs (qtest.sh N 'rbox-opts' 'qhull-opts')
    execute rbox and qhull N times with random inputs 'tnnn', ...

  • Run qhull command (qtest.sh run 'rbox c | qhull')
    execute a qhull command line
  • Run qhull QRnnn (qtest.sh run QRnnn 'rbox | qhull')
    execute a qhull command line with QRnnn rotated input
  • Run rbox tnnn | qhull (qtest.sh run t... 'rbox-opts' 'qhull-opts')
    execute rbox and qhull commands with tnnn random input

  • Log qhull command (qtest.sh log 'rbox c | qhull')
    trace (T4) a qhull command line to qhull.log and qhull-step.log
  • Log qhull QRnnn (qtest.sh QRnnn 'rbox | qhull')
    trace (T4) a qhull command line with QRnnn rotated input to qhull.log and qhull-step.log
  • Log rbox tnnn | qhull (qtest.sh tnnn 'rbox-opts' 'qhull-opts')
    trace (T4) rbox and qhull commands with tnnn random input to qhull.log and qhull-step.log

  • Grep qhull.log for events (qtest.sh grep)
    grep qhull.log for $QH_GREP excluding $QH_GREPX to stdout
  • Grep qhull.log for regexp (qtest.sh grep 'include-regexp')
    grep qhull.log for regexp|$QH_GREP excluding $QH_GREPX to stdout
  • Grep qhull.log for include and exclude regexps (qtest.sh grep 'include-regexp' 'exclude-regexp')
    grep qhull.log for include|$QH_GREP excluding exclude|$QH_GREPX to stdout

  • Grep logfile for merge events (qtest.sh grep-merge logfile)
    grep logfile for merge events to stdout, see #grep-merge in qtest.sh

  • Grep logfile for step events (qtest.sh grep-merge logfile)
    grep logfile for step events to stdout, same as qhull-step.log

  • Verbose logging (qtest.sh -v ...)
    prepend log with command and environment variables

»Memory errors

Qhull checks memory usage before exiting. To locate memory that is not freed ("QH7079 qhull internal warning (main): did not free ..."):
  1. Run qhull with memory tracing 'T5'.
    See 'Level 5' in Qhull trace options (above)
  2. Sort lines that start with 'qh_mem'. It matches qh_memalloc with the corresponding qh_memfree.
  3. For long allocations, sort lines that contain -- qh_mem.*long:
  4. Replace -- qh_mem.*alloc.*\nqh_mem.*free.* -- with 'Match' (Textpad supports internal newlines in match expressions).
  5. Sort by column 25 (n...). It shows unallocated actions. Long allocations are in execution order. Short and quick allocations are in execution order.
  6. For example: qh_mem 0000000000537440 n 10053 alloc long: 128 bytes (tot 484800 cnt 1209)
  7. To check quick vs. long allocations -- grep "qh_mem .*alloc " qhull.log | sed -e 's/^.*long/long/' -e 's/^.*short/short/' -e 's/^.*quick/quick/' -e 's/bytes.*/bytes/' | sort | uniq -c >x.1

Option 'Ts' reports numerous memory statistics.

»Qhull debugging tips

  • qh_printlists in poly2_r.c -- called during qh_addpoint. Easily inserted into existing code and a good location for debugging code.
  • qh_fprintf in user_r.c -- called for all Qhull output, including trace logs. A good location for reasonably efficient debugging code. The debugging code may refer to a facet, ridge, or vertex by setting qh.tracefacet_id, qh.traceridge_id, or qh.tracevertex_id in global_r.c/qh_initqhull_start2.
  • qh_tracemerge in merge_r.c -- called after each merge. It is a good location for debugging code.

»Performance of Qhull

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

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

The time complexity for merging is unknown. The default options 'C-0' (2-d, 3-d, 4-d) and 'Qx' (5-d and higher) handle precision problems due to floating-point arithmetic. They are optimized for simplicial outputs.

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

Additional detail is provided by QH1049 in the level-1 trace ('T1'). For each qh_addpoint, it provides vertex id, facet count, outside point count, CPU time for the previous point, deltas for facets/hyperplanes/distplanes, and the number of retries due to merged pinched vertices. For example:

[QH1049]qh_addpoint: add p260(v176) to hull of 286 facets (1.4e-12 above f830) and 2 outside at 1.192 CPU secs. Previous p710(v175) delta 0.007 CPU, 2 facets, 3 hyperplanes, 443 distplanes, 0 retries

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

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

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

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

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

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

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

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

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

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

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

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

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

»eg/q_benchmark for optimizing Qhull

eg/q_benchmark and eg/qtest.sh make multiple runs of Qhull for testing, benchmarking, and debugging. They help test and analyze intermittent errors, performance issues, and precision issues. Each release updates eg/q_benchmark-ok.txt.

Qhull 2019.1 is 15% larger than Qhull 2015.2 due to enhanced error reporting, tracing, and facet merging. The increased code size may increase startup times.

Qhull is single threaded. Gcc's gprof works well for profiling Qhull performance.

  • Recompile Qhull with '-pg' added to CC_OPTS1 in qhull's Makefile. Check for optimization ('-O3').
  • Execute a performance test of Qhull
    • See "=== Timing test cases ===" in 'eg/q_benchmark'.
  • Check for gmon.out from gcc's '-pg' option -- ls -l gmon.out
  • Run gprof -- gprof qhull >gprof.txt # gprof qhull.exe >gprof.txt
  • Review gprof.txt
    • The first section gives results by function, the second section, results by caller
  • Sample runs
    rbox 500000 s >r.x; time qhull TI r.x
    
    AIR2-/local/qhull/bin> time qhull TI r.x
    
    Convex hull of 500000 points in 3-d:
    
      Number of vertices: 500000
      Number of facets: 999996
    
    Statistics for: rbox 500000 s | qhull TI r.x
    
      Number of points processed: 500000
      Number of hyperplanes created: 2827999
      Number of distance tests for qhull: 24786928
      CPU seconds to compute hull (after input): 4.852
    
    
    [4]     62.8    0.02    2.11  499996         qh_addpoint [4]
                    0.01    0.83  499996/499996      qh_buildcone [5]
                    0.04    0.56  499996/499996      qh_partitionvisible [7]
                    0.01    0.28  499996/499996      qh_premerge [13]
                    0.04    0.13  499996/499996      qh_findhorizon [19]
    
    # 2015.2
    Statistics for: rbox 500000 s | qhull TI c:/bash/local/qhull/bin/r.x
      Number of vertices: 500000
      Number of facets: 999996
      Number of points processed: 500000
      Number of hyperplanes created: 2827999
      Number of distance tests for qhull: 24786929
      CPU seconds to compute hull (after input): 4.477
    real    0m6.334s
    user    0m0.016s
    sys     0m0.015s
    

»Enhancements to Qhull

There are many ways in which Qhull can be improved.

Top Suggestions
 - Document the C++ interface using Doxygen
 - Construct the full Voronoi Diagram using the C++ interface.  See "To do" in Changes.txt
 - Optimize for 64-bit code
   Custom facetT for simplicial facets
   32-bit indices for facets and vertices
 - Bulk qh_addpoint with a custom point partition
 - Full-dimensional flats
   Add points at right angles like 'Qz'
   Ignore added facets in output (cf. f.upperDelaunay and f.good)
 - Per-vertex joggle
   Joggle by random flip of low-order and adjustable-order bits in mantissa
   Allows consistent triangulations across distributed partitions
   Detect integer input data and automatically translate to the origin
 - Develop a theory for merging Qhull's non-simplicial facets
   A merge creates constraints on subsequent merges, what are these constraints?
   Identify topological errors in qh_findbest_test (merge_r.c)f
   Prevent duplicate ridges (Q15-check-duplicates) or facets with the same vertices
   Preserve facet-ridge orientation for nonsimplicial facets (ridge top/bot)
   Produce conformant triangulations for nonsimplicial facets (option 'Qt', QH2088)
   Should vertex merge account for facet orientation?
   Rationalize the merge options qh_RATIOtwisted, qh_WIDEdupridge, etc.
   Should wide merges be proportional to qh.ONEmerge or f.maxoutside?
   Can dupridges be avoided with geometric and topological constraints?
   Review coplanar tests across sharp ridges (coplanar horizon, qh_test_appendmerge, qh_check_maxout)
 - Improve Qhull's computations, particularly qh_setfacetplane for hyperplanes
   Toronto, N., McCarthy, J., "Practically accurate floating-point math,", Computing in
   Science & Engineering, IEEE, July/August 2014, p. 80-95.
 - Octave creates endpoints for unbounded ridges, for drawing Delaunay/Voronoi diagrams [M. Voss]
 - Option to select bounded Voronoi regions [A. Uzunovic]
 - Review Qhull performance.  qh_next_vertexmerge and qh_check_maxout are slower than expected
   Compare to Peterka et al and Li and Snoeyink, particularly 64-bit vs. 32-bit
 - Use Gaussian distribution for random cospherical points in rbox
 - Implement dimension reduction via Johnson-Lindenstrauss flattening
 - Implement bulk qh_addpoint via a subset of the facets, perhaps a box about qh.interior_point
   Allow qh_triangulate to run after each increment [coldfix, scipy #4974]
 - Write incremental addPoint with bucketed inputs and facet search (CGAL)
 - Compute hyperplanes in parallel (cf. qh_setfactplane)
 - Create Voronoi volumes and topology in parallel
 - Implement Delaunay to Voronoi tesselation [Peterka et al, 2014, www.mcs.anl.gov/papers/P5154-0614.pdf]
 - Integrate 4dview with Geomview 1.9.5
 - Use coverage testing to expand Qhull's test programs
 - Add RPM and Debian builds to Qhull (CMake's CPackRMP and CPackDeb).
 - Create a mirror/archive web site for old and new Qhull builds
 - Constrain delaunay triangulations via Shewchuk's algorithm (ACM Symp. Comp. Geo., 1998)

-----------
To do for a furture version of the C++ interface
 - Document C++ using Doxygen conventions (//! and //!<)
 - Add defineAs() to each object
 - Add Qtest::toString() functions for QhullPoint and others.  QByteArray and qstrdup()
 - Add toQVector() for Qt container support.  QVector is preferred over QList
 - Add mutable Java-style iterators for containers.  Limited due to memory-allocation issues.
 - Should Qhull manage the output formats for doubles?  QH11010 FIX: user_r.h defines qh_REAL_1 as %6.8g
 - Allocate memory for QhullSet using Qhull.qhmem.  Create default constructors for QhullVertexSet etc.  Also mid() etc.
 - Add interior point for automatic translation?
 - Write a program with concurrent Qhull
 - Write QhullStat and QhullStat_test
 - Add QList and vector instance of facetT*, etc.
 - Generalize QhullPointSetIterator
 - qh-code.htm: Document changes to C++ interface.
      Organize C++ documentation into collection classes, etc.
 - Review all C++ classes and C++ tests
 - QhullVertexSet uses QhullSetBase::referenceSetT() to free its memory.   Probably needed elsewhere
 - The Boost Graph Library provides C++ classes for graph data structures. It may help
   enhance Qhull's C++ interface [Dr. Dobb's 9/00 p. 29-38; OOPSLA 99 p. 399-414].

[May 2020] Suggestions
- Check that the midpoint for Voronoi option 'Fo' is not a Voronoi vertex (rbox c D2 P0 | qvoronoi Fo)
- How to detect degenerate hyperplanes for Voronoi option 'Fo' and 'Fi'?
  qh_sethyperplane_gauss reports nearzero for axis parallel hyperplanes.
- Add a 'Tv' test for Voronoi option 'Fo' that does not use midpoints

[May 2019] Suggestions
------------
Precision issues
- Improve handling of data with positive, integer coordinates, particularly for Delaunay triangulation
  eg Sterratt's github issue #25
  Add a warning that available precision is reduced
  Add an option to automatically translate the data to the origin
- Review qh.MAXcoplanar ('Un'), it varies by dimension compared to qh.ONEmerge

Topology issues
- Need theory for facet merging, vertex merging, and topological errors
- Does qh_triangulate produce a consistent orientation if qh_renamevertex is not called?

Facet and vertex merging
- Reduce the overhead of qh.NEWtentative ('Q14') and improve the speed of facet and vertex merging
- Review MRGconcavecoplanar and early out for isconcave in qh_test_nonsimplicial_merge
- Review user_r.h ratios and precision constants for merging
  Pre-compute derived precision values (e.g., qh_detmaxoutside)
- Use a fixed target instead of a relative wide-max ratio.
  Why should qh.MAXoutside increase when qh.max_outside increases dramatically
  Why should a slow but steady increase in qh.max_outside be OK?
  Define an option to specify wide-max ratio -- 100x is borderline, bad cases can produce 400x,
- Add statistics for dupridge matching in qh_matchneighbor and qh_matchdupridge.  Report as a "precision problem"
- Collect statistics for MRGdegen and MRGredundant
- In qh_all_merges, why is isreduce set when qh.POSTmerging && qh.hull_dim >= 4?
- In qh_forcedmerges and qh_initmergesets, remove assumption that qh.facet_mergeset is the last temporary set
- Review comparisons for qh_compare_anglemerge and qh_compare_facetmerge (after developing a theory)

Other
- Add a version flag to 'rbox' (cf. global_r.c/qh_version).  Currently, the release date is part of its help prompt.
- Review effect of qh.GOODclosest on qh_buildcone_onlygood ('Qg', QH11030 FIX).  qh_findgood preserves old value if didn't find a good facet.  See qh_findgood_all for disabling
- Review the rules for -REALmax -- they look inconsistent.
  Why REALmax/2 and -REALmax/2?  The comments say 'avoid underflow'.  When was it introduced?
- Review comment in qh_matchnewfacets -- "do not allocate memory after qh.hash_table (need to free it cleanly)"
- Chase circular dependencies when compiling qhulltest with Microsoft Devstudio
  Warning MSB8017 A circular dependency has been detected while executing custom build commands for item "moc\Coordinates_test.moc". This may cause incremental build to work incorrectly.        qhulltest-64    C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\VC\VCTargets\Microsoft.CppCommon.targets   209
- Add 'design:' documentation for poly2_r.c/qh_triangulate
  Consider splitting up
- Geomview for 4-d merge is difficult to understand.  Not able to see the convexity of the edges
- Review memory sizes (mem_r.c/qh_memsize) and quick allocations for 64-bit code
- Review Qhull's collection API conventions, http://www.qhull.org/road/road-faq/xml/qhull-cpp.xml
  See http://gnuwin32.sourceforge.net/packages.html and https://google-styleguide.googlecode.com/svn/trunk/cppguide.html

[Jan 2019] Suggestions
- Optimize poly_r.c/qh_update_vertexneighbors for qh_triangulate. qh_setunique and qh_setcompact are slow
- The size of maxpoints in qh_initialvertices/qh_maxsimplex should be d+3 unique points to help avoid QH6154
- Review coordT vs. realT.  Should parameters and variables be coordT when they are distances or coordinates?
  'coordT' is defined as 'realT'
  Having computations as 'double' with coordinates stored as 'float' requires many type conversions
  Expressions are often computed as 'double' anyway
  Source code sometimes uses 'coordT' and sometimes 'realT'
- Need a separate, hash check for duplicate ridge vertices in a facet list -- faster than current qh_checkfacet
- Add joggle for 'almost incident' vertices (order of 100), may clean up Qt as well, projected to hyperplane
- Consider using r.mergevertex2 to optimize qh_postmerge
- Report two facets with same ridge vertices, opposite orientation (topology error)
  add warning (see QH7084) for duplicate ridge with opposite orientation (only two facets in the list)
- Check 'qh_NOmerge' compiler option

[Jan 2016] Suggestions
------------
 - Add a post-merge pass for Delaunay slivers.  Merge into a neighbor with a circumsphere that includes the opposite point. [M. Treacy]
 - Option to add a bounding box for Delaunay triangulations, e,g., nearly coincident points
 - Rescale output to match 'QbB' on input [J. Metz, 1/30/2014 12:21p]
 - Run through valgrind
 - Notes to compgeom on conformant triangulation and Voronoi volume
 - Implement weighted Delaunay triangulation and weighted Voronoi diagram [A. Liebscher]
   e.g., Sugihara, "Three-dimensional convex hull as a fruitful source of diagrams," Theoretical Computer Science, 2000, 235:325-337
 - testqset: test qh_setdelnth and move-to-front
 - Makefile: Re-review gcc/g++ warnings.  OK in 2011.
 - Break up -Wextra into its components or figure out how to override -Wunused-but-set-variable
   unused-but-set-variable is reporting incorrectly.  All instances are annotated.

 - Can countT be defined as 'int', 'unsigned int', or 64-bit int?
   countT is currently defined as 'int' in qset_r.h
   Vertex ID and ridge ID perhaps should be countT, They are currently 'unsigned'
   Check use of 'int' vs. countT in all cpp code
   Check use of 'int' vs. countT in all c code
   qset_r.h defines countT -- duplicates code in user_r.h -- need to add to qset.h/user.h
   countT -1 used as a flag in Coordinates.mid(), QhullFacet->id()
   Also QhullPoints indexOf and lastIndexOf
   Also QhullPointSet indexOf and lastIndexOf
   Coordinates.indexOf assumes countT is signed (from end)
   Coordinates.lastIndexOf assumes countT is signed (from end)
   All error messages with countT are wrong, convert to int?
   RboxPoints.qh_fprintf_rbox, etc. message 9393 assumes countT but may be int, va_arg(args, countT);  Need to split

[Jan 2010] Suggestions
 - Generate vcproj from qtpro files
   cd qtpro && qmake -spec win32-msvc2005 -tp vc -recursive
   sed -i 's/C\:\/bash\/local\/qhull\/qtpro\///' qhull-all.sln
   Change qhullcpp to libqhull.dll
   Allow both builds on same host (keep /tmp separate)
 - C++ class for access to statistics, accumulate vs. add
 - Add dialog box to RoadError-- a virtual function?
 - Option 'Gt' does not make visible all facets of the mesh example, rbox 32 M1,0,1 | qhull d Gt
 - Merge small volume boundary cells into unbounded regions [Dominik Szczerba]
 - Postmerge with merge options
 - Add modify operators and MutablePointCoordinateIterator to PointCoordinates
 - Fix option Qt for conformant triangulations of merged facets
 - Investigate flipped facet -- rbox 100 s D3 t1263080158 | qhull R1e-3 Tcv Qc
 - Add doc comments to c++ code
 - Measure performance of Qhull, seconds per point by dimension
 - Report potential wraparound of 64-bit ints -- e.g., a large set or points

Documentation
- Qhull::addPoint().  Problems with qh_findbestfacet and otherpoints see
   qh-code.htm#inc on-line construction with qh_addpoint()
- How to handle 64-bit possible loss of data.  WARN64, ptr_intT, size_t/int
- Show custom of qh_fprintf
- cat x.x | grep 'qh_mem ' | sort | awk '{ print $2; }' | uniq -c | grep -vE ' (2|4|6|8|10|12|14|16|20|64|162)[^0-9]'
- qtpro/qhulltest contains .pro and Makefile.  Remove Makefiles by setting shadow directory to ../../tmp/projectname
- Rules for use of qh_qh and multi processes
    UsingQhull
    errorIfAnotherUser
    ~QhullPoints() needs ownership of qh_qh
    Does !qh_pointer work?
    When is qh_qh required?  Minimize the time.
   qhmem, qhstat.ferr
   qhull_inuse==1 when qhull globals active [not useful?]
   rbox_inuse==1 when rbox globals active
   - Multithreaded -- call largest dimension for infinityPoint() and origin()
 - Better documentation for qhmem totshort, freesize, etc.
 - how to change .h, .c, and .cpp to text/html.  OK in Opera
 - QhullVertex.dimension() is not quite correct, epensive
 - Check globalAngleEpsilon
 - Deprecate save_qhull()

[Dec 2003] Here is a partial list:
 - fix finddelaunay() in user_eg.c for tricoplanar facets
 - write a BGL, C++ interface to Qhull
     http://www.boost.org/libs/graph/doc/table_of_contents.html
 - change qh_save_qhull to swap the qhT structure instead of using pointers
 - change error handling and tracing to be independent of 'qh ferr'
 - determine the maximum width for a given set of parameters
 - prove that directed search locates all coplanar facets
 - in high-d merging, can a loop of facets become disconnected?
 - find a way to improve inner hulls in 5-d and higher
 - determine the best policy for facet visibility ('Vn')
 - determine the limitations of 'Qg'

Precision improvements:
 - For 'Qt', resolve cross-linked, butterfly ridges.
     May allow retriangulation in qh_addpoint().
 - for Delaunay triangulations ('d' or 'v') under joggled input ('QJ'),
     remove vertical facets whose lowest vertex may be coplanar with convex hull
 - review use of 'Qbb' with 'd QJ'.  Is MAXabs_coord better than MAXwidth?
 - check Sugihara and Iri's better in-sphere test [Canadian
     Conf. on Comp. Geo., 1989; Univ. of Tokyo RMI 89-05]
 - replace centrum with center of mass and facet area
 - handle numeric overflow in qh_normalize and elsewhere
 - merge flipped facets into non-flipped neighbors.
     currently they merge into best neighbor (appears ok)
 - determine min norm for Cramer's rule (qh_sethyperplane_det).  It looks high.
 - improve facet width for very narrow distributions

New features:
 - implement Matlab's tsearch() using Qhull
 - compute volume of Voronoi regions.  You need to determine the dual face
   graph in all dimensions [see Clarkson's hull program]
 - compute alpha shapes [see Clarkson's hull program]
 - implement deletion of Delaunay vertices
      see Devillers, ACM Symposium on Computational Geometry, Minneapolis 1999.
 - compute largest empty circle [see O'Rourke, chapter 5.5.3] [Hase]
 - list redundant (i.e., coincident) vertices [Spitz]
 - implement Mucke, et al, ['96] for point location in Delaunay triangulations
 - implement convex hull of moving points
 - implement constrained Delaunay diagrams
      see Shewchuk, ACM Symposium on Computational Geometry, Minneapolis 1998.
 - estimate outer volume of hull
 - automatically determine lower dimensional hulls
 - allow "color" data for input points
      need to insert a coordinate for Delaunay triangulations

Input/output improvements:
 - Support the VTK Visualization Toolkit, http://www.kitware.com/vtk.html
 - generate output data array for Qhull library [Gautier]
 - need improved DOS window with screen fonts, scrollbar, cut/paste
 - generate Geomview output for Voronoi ridges and unbounded rays
 - generate Geomview output for halfspace intersection
 - generate Geomview display of furthest-site Voronoi diagram
 - use 'GDn' to view 5-d facets in 4-d
 - convert Geomview output for other 3-d viewers
 - add interactive output option to avoid recomputing a hull
 - orient vertex neighbors for 'Fv' in 3-d and 2-d
 - track total number of ridges for summary and logging

Performance improvements:
 - GPU hardware acceleration, particularly for qh_setplane [D. Reese]
 - optimize Qhull for 2-d Delaunay triangulations
 -   use O'Rourke's '94 vertex->duplicate_edge
 -   add bucketing
 -   better to specialize all of the code (ca. 2-3x faster w/o meSrging)
 - use updated LU decomposition to speed up hyperplane construction
 -        [Gill et al. 1974, Math. Comp. 28:505-35]
 - construct hyperplanes from the corresponding horizon/visible facets
 - for merging in high d, do not use vertex->neighbors

Please let us know about your applications and improvements.


Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
To: Imprecision in Qhull
To: Qhull code: contents


The Geometry Center Home Page

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

qhull-2020.2/html/qh-eg.htm0000644060175106010010000007463013716273040013662 0ustar bbarber Examples of Qhull

Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
To: Qhull examples: contents


[halfspace] Examples of Qhull

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

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

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

Copyright © 1995-2020 C.B. Barber


»Qhull examples: contents



»2-d and 3-d examples

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

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

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

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

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

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

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

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

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

One rotation of a spiral.

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

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

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

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

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

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

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

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

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

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

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

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

»How Qhull adds a point

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

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

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

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

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

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

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

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

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

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

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

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

»Triangulated output or joggled input

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

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

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

rbox 500 W0 | qhull QR0 Q0

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

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

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

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

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

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

»Delaunay and Voronoi diagrams

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

»Facet merging for imprecision

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

»4-d objects

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

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

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

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

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

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

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

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

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

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

»rbox 30 s D4 | qconvex s G Pd0d1d2D3

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

»Halfspace intersections

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

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

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

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

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


Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
To: Qhull examples: contents


The Geometry Center Home Page

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

qhull-2020.2/html/qh-faq.htm0000644060175106010010000015652113716276715014052 0ustar bbarber Qhull FAQ

Up: Home page for Qhull (local)
Up: Qhull Wiki and FAQ (local)
Up: Qhull manual: contents
To: Imprecision in Qhull
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
To: FAQ: contents


[4-d cube] Frequently Asked Questions about Qhull

If your question does not appear here, see:

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

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

Version 2019.1 adds an experimental option for vertex merging of nearly adjacent vertices ('Q14'). It may resolve topological issues such as "dupridges" with more than two facet neighbors.

Version 2015.1 introduced the reentrant library. It should be used for all code that calls Qhull. The 'qhull' program is built with the reentrant library.

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

Brad Barber, Arlington MA, 2019/02/11

Copyright © 1998-2020 C.B. Barber


»FAQ: contents

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

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

»Startup questions

»How do I run Qhull from Windows?

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

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

If you regularly use Qhull on a Windows host, install a bash shell such as

  • Git for Windows (wiki, based on MSYS2) -- Git for Windows v2.21 requires arguments for 'qhull', otherwise it waits for stdin. Use 'qhull --help' for a usage note instead of 'qhull'.
  • MSYS2 (wiki)
  • Cygwin

If you use Windows XP or Windows 8, you may use

»How do I enter points for Qhull?

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

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

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

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

rbox c | qconvex o

computes the convex hull of a cube.

»How do I learn to use Qhull?

First read:

Look at Qhull's on-line documentation:

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

Then try out the Qhull programs on small examples.

  • 'rbox c' -- lists the vertices of a cube
  • 'rbox c D2 | qconvex' -- is the convex hull of a square
  • 'rbox c D2 | qconvex o' -- lists the vertices and facets of a square
  • 'rbox c | qconvex' -- is the convex hull of a cube
  • 'rbox c | qconvex o' -- lists the vertices and facets of a cube
  • 'rbox c | qconvex Qt o' -- triangulates the cube
  • 'rbox c | qconvex QJ o' -- joggles the input and triangulates the cube
  • 'rbox c D4 | qconvex' -- is the convex hull of a hypercube

  • 'rbox 6 s D2 t | qconvex p Fx' -- is the convex hull of 6 random, cocircular points. Option 'p' lists the points while option 'Fx' lists the vertices in order.

  • 'rbox d D2 c G2 | qdelaunay' -- is the Delaunay triangulation of a diamond and a square. The diamond's vertices are cocircular.
  • 'rbox d D2 c G2 | qdelaunay o' -- lists the input sites projected to a paraboloid and the Delaunay regions. The region with 4 vertices is the diamond.
  • 'rbox d D2 c G2 | qdelaunay o Qt' -- the cocircular diamond is triangulated as two Delaunay regions.
  • 'rbox d D2 c G2 | qdelaunay o QJ' -- the input is joggled and the diamond is triangulated.

  • 'rbox d D2 c G2 | qvoronoi o' -- is the Voronoi regions for a diamond and a square. The Voronoi vertex for the diamond is the origin (0,0). Unbounded regions are represented by the first vertex (-10.101 -10.101)
  • 'rbox d D2 c G2 | qvoronoi Fv' -- shows the Voronoi diagram for the previous example. Each line is one edge of the diagram. The first number is 4, the next two numbers list a pair of input sites, and the last two numbers list the corresponding pair of Voronoi vertices.
  • 'rbox d D2 c G2 | qvoronoi o Qt' -- the cocircular Delaunay region is triangulated. Instead of one Voronoi vertex for the diamond, there are two Voronoi vertices (0,0) and (0,0).

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

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

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

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

»Convex hull questions

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

Use option 'FS' or 'FA'. The area is the area of the surface of the convex hull, while the volume is the total volume of the convex hull.

For example,

rbox 10 | qconvex FS
0
2 2.192915621644613 0.2027867899638665

rbox 10 | qconvex FA

Convex hull of 10 points in 3-d:

  Number of vertices: 10
  Number of facets: 16

Statistics for: RBOX 10 | QCONVEX FA

  Number of points processed: 10
  Number of hyperplanes created: 28
  Number of distance tests for qhull: 44
  CPU seconds to compute hull (after input):  0
  Total facet area:   2.1929156
  Total volume:       0.20278679

In 2-d, the convex hull is a polygon. Its surface is the edges of a polygon. So in 2-d, the 'area' is the length of the polygon's edges, while the 'volume' is the area of the polygon.

For example the convex hull of a square,

rbox c D2 | qconvex FS
0
2      4      1

rbox c D2 | qconvex FA

Convex hull of 4 points in 2-d:

  Number of vertices: 4
  Number of facets: 4

Statistics for: rbox c D2 | qconvex FA

  Number of points processed: 4
  Number of hyperplanes created: 6
  Number of distance tests for qhull: 5
  CPU seconds to compute hull (after input):  0
  Total facet area:    4
  Total volume:        1

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

Options 'i' (in 4-D and higher) and 'Ft' (in 3-D and higher) use "extra" points for non-simplicial facets (e.g., a face of a cube or hypercube). These points are not part of the convex hull. Options 'i' and 'Ft' triangulate non-simplicial facets using the facet's centrum.

For example, Qhull reports the following for one facet of the convex hull of a hypercube. The facets of a 4-D hypercube are 3-d cubes. Option 'Pd0:0.5' returns the facet along the positive-x axis. Point 17 represents the centrum of this facet. The facet's vertices are eight points: point 8 to point 15

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

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

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

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

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

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

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

The coordinates of the extra point are printed with the 'Ft' option. For centrums, option 'Ft' uses indices one less than option 'i'. In this case, point 16 represents the centrum of the facet.

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

»How do I report duplicate vertices?

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

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

»Delaunay triangulation questions

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

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

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

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

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

If you are calling Qhull from a program, you can merge slivers into an adjacent facet. In d dimensions with simplicial facets (e.g., from 'Qt'), each facet has d+1 neighbors. Each neighbor shares d vertices of the facet's d+1 vertices. Let the other vertex be the opposite vertex. For each neighboring facet, if its circumsphere includes the opposite.vertex, the two facets can be merged. [M. Treacy]

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

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

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

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

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

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

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

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

»Can Qhull produce a triangular mesh for an object?

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

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

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

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

For example,

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

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

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

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

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

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

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

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

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

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

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

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

rbox 10 D2 | qdelaunay Qt i

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

rbox 10 D2 | qvoronoi o

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

rbox 10 D2 | qvoronoi Fv

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

rbox 10 D2 | qvoronoi QV5 p | qconvex s FS

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

rbox 10 D2 | qvoronoi QV5 p | qconvex n

or

rbox 10 D2 | qvoronoi QV5 Fi Fo

To list the extreme points of the input sites use

rbox 10 D2 | qdelaunay Fx

You will get the same point ids with

rbox 10 D2 | qconvex Fx

»Can Qhull triangulate a hundred 16-d points?

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

»Voronoi diagram questions

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

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

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

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

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

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

An unbounded Voronoi region does not have a volume.

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

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

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

»What is the Voronoi diagram of a square?

Consider a square,

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

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

C:\qhull>rbox c D2 | qvoronoi Qz

Voronoi diagram by the convex hull of 5 points in 3-d:

  Number of Voronoi regions and at-infinity: 5
  Number of Voronoi vertices: 1
  Number of facets in hull: 5

Statistics for: RBOX c D2 | QVORONOI Qz

  Number of points processed: 5
  Number of hyperplanes created: 7
  Number of distance tests for qhull: 8
  Number of merged facets: 1
  Number of distance tests for merging: 29
  CPU seconds to compute hull (after input):  0

C:\qhull>rbox c D2 | qvoronoi Qz o
2
2 5 1
-10.101 -10.101
     0      0
2 0 1
2 0 1
2 0 1
2 0 1
0

C:\qhull>rbox c D2 | qvoronoi Qz Fv
4
4 0 1 0 1
4 0 2 0 1
4 1 3 0 1
4 2 3 0 1

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

With triangulated output, the Voronoi vertex is duplicated:

C:\qhull3.1>rbox c D2 | qvoronoi Qt Qz

Voronoi diagram by the convex hull of 5 points in 3-d:

  Number of Voronoi regions and at-infinity: 5
  Number of Voronoi vertices: 2
  Number of triangulated facets: 1

Statistics for: RBOX c D2 | QVORONOI Qt Qz

  Number of points processed: 5
  Number of hyperplanes created: 7
  Number of facets in hull: 6
  Number of distance tests for qhull: 8
  Number of distance tests for merging: 33
  Number of distance tests for checking: 30
  Number of merged facets: 1
  CPU seconds to compute hull (after input): 0.05

C:\qhull3.1>rbox c D2 | qvoronoi Qt Qz o
2
3 5 1
-10.101 -10.101
     0      0
     0      0
3 2 0 1
2 1 0
2 2 0
3 2 0 1
0

C:\qhull3.1>rbox c D2 | qvoronoi Qt Qz Fv
4
4 0 2 0 2
4 0 1 0 1
4 1 3 0 1
4 2 3 0 2

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

C:\qhull>rbox c D2 | qvoronoi Qt Qz

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

C:\qhull>rbox c D2 | qvoronoi QJ Fv
5
4 0 2 0 1
4 0 1 0 1
4 1 2 1 2
4 1 3 0 2
4 2 3 0 2

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

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

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

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

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

The facet normals are:

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

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

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

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

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

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

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

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

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

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

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

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

»Approximation questions

»How do I approximate data with a simplex

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

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

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

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

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

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

»Halfspace questions

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

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

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

»Qhull library questions

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

MATLAB

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

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

Mathematica and Maple

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

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

»Why are there too few ridges?

The following sample code may produce fewer ridges than expected:
  facetT *facetp;
  ridgeT *ridge, **ridgep;

  FORALLfacets {
    printf("facet f%d\n", facet->id);
    FOREACHridge_(facet->ridges) {
      printf("   ridge r%d between f%d and f%d\n", ridge->id, ridge->top->id, ridge->bottom->id);
    }
  }

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

  facetT *facet, *neighbor;
  ridgeT *ridge, **ridgep;

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

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

You may call Qhull from a program. Please use the reentrant Qhull library (libqhullstatic_r.a, libqhull_r.so, or qhull_r.dll). See user_eg.c and "Qhull-template" in user_r.c for examples.. See Qhull code for an introduction to Qhull's reentrant library and its C++ interface.

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

»How large are Qhull's data structures?

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

Qhull's data structures use many pointers. For 64-bit code, pointers are twice the size of integers. For 64-bit code, Qhull uses 50% more memory. It there is not enough memory in the computer's level 1 and level 2 caches, Qhull will run slower as it retrieves data from main memory. A future version of Qhull will include memory and performance improvements for 64-bit code.

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

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

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

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

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

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

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

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

In undebugged, C code:

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

»How do I visit the Delaunay regions?

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

    facetT *facet;

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

»When is a point outside or inside a facet?

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

    facetT *facet;
    pointT *point;
    realT dist;

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

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

    facetT *facet;
    pointT *point;
    realT dist;

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

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

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

See Locate facet with qh_findbestfacet. For Delaunay triangulations, qh_findbestfacet returns the Delaunay triangle or adjacent triangle that contains the point.

Use qh_findbestfacet(). For example,

    coordT point[ DIM ];
    boolT isoutside;
    realT bestdist;
    facetT *facet;

    ... set coordinates for point ...

    facet= qh_findbestfacet (point, qh_ALL, &bestdist, &isoutside);

    /* 'facet' or an adjacent facet is the closest facet to 'point' */

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

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

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

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

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

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

    coordT point[ DIM + 1];  /* one extra coordinate for lifting the point */
    boolT isoutside;
    realT bestdist;
    facetT *facet;

    ... set coordinates for point[] ...

    qh_setdelaunay (DIM+1, 1, point);
    facet= qh_findbestfacet (point, qh_ALL, &bestdist, &isoutside);
    /* 'facet' or an adjacent facet is the closest Delaunay triangle to 'point' */

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

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

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

    realT dist, bestdist= REALmax;
        vertexT *bestvertex= NULL, *vertex, **vertexp;

    /* 'facet' is the closest Delaunay triangle to 'point' */

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

»How do I list the vertices?

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

    vertexT *vertex;

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

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

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

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

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

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


Up:Home page for Qhull (local)
Up: Qhull Wiki and FAQ (local)
Up: Qhull manual: contents
To: Imprecision in Qhull
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
To: FAQ: contents


The Geometry Center Home Page

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

qhull-2020.2/html/qh-get.htm0000644060175106010010000001353213724320022014030 0ustar bbarber Qhull Downloads

Up: Qhull Home Page (www.qhull.org)


[CONE] Qhull Downloads

  • Qhull Home Page

    Qhull computes the convex hull, Delaunay triangulation, Voronoi diagram, halfspace intersection about a point, furthest-site Delaunay triangulation, and furthest-site Voronoi diagram. It runs in 2-d, 3-d, 4-d, and higher dimensions. It implements the Quickhull algorithm for computing the convex hull. Qhull handles roundoff errors from floating point arithmetic. It can approximate a convex hull.

    Visit Qhull News for news, bug reports, change history, and users. If you use Qhull 2003.1 or 2009.1, please upgrade or apply poly.c-qh_gethash.patch.

  • Download: Qhull 2020.2 for Windows 10, 8, 7, XP, and NT (3.3 MB, readme, md5sum, contents)

    Type: console programs for Windows (32- or 64-bit)

    Includes 32-bit executables, documentation, and sources files. It runs in a command window. Qhull may be compiled for 64-bits.

  • GitHub Qhull (git@github.com:qhull/qhull.git)

    Type: git repository for Qhull. See current Changes.txt

    Includes documentation, source files, C++ interface, and test programs. It builds with gcc, mingw, CMake, DevStudio, and Qt Creator.

  • Download: Qhull 2020.2 for Unix (1.3 MB, readme, md5sum, contents)

    Type: C/C++ source code for 32-bit and 64-bit architectures.

    Includes documentation, source files, Makefiles, CMakeLists.txt, DevStudio projects, and Qt projects. Includes C++ support.

    Download and search sites for pre-built packages include

  • The Quickhull algorithm for convex hulls (PDF, 307K)

    Type: PDF on ACM Digital Library (from this page only)

    Barber, C.B., Dobkin, D.P., and Huhdanpaa, H.T., "The Quickhull algorithm for convex hulls," ACM Transactions on Mathematical Software, 22(4):469-483, Dec 1996 [abstract].

  • Download: Qhull version 1.0 (92K)

    Type: C source code for 32-bit architectures

    Version 1.0 is a fifth the size of version 2.4. It computes convex hulls and Delaunay triangulations. If a precision error occurs, it stops with an error message. It reports an initialization error for inputs made with 0/1 coordinates.

    Version 1.0 compiles on a PC with Borland C++ 4.02 for Win32 and DOS Power Pack. The options for rbox are "bcc32 -WX -w- -O2-e -erbox -lc rbox.c". The options for qhull are the same. [D. Zwick]

  • Sept. 3, 2020 22:00:41 EDT md5sum for Qhull 2020.2 downloads
    368f2aa9bf89677af04d57d281041359 *qhull-2020.2/qhull-2020.2-zip.md5sum
    27c44a7e2db5f127e1c6fc7807580566 *qhull-2020.2/qhull-2020-src-8.0.2-tgz.md5sum
    a1a58969aa17d89088ebbd0b0eb44a82 *qhull-2020.2.zip
    fa34047579937433e3a36c5d4033a988 *qhull-2020-src-8.0.2.tgz
    

Up: Qhull Home Page (www.qhull.org)


[HOME] The Geometry Center Home Page

Comments to: qhull@qhull.org
qhull-2020.2/html/qh-impre.htm0000644060175106010010000011551413716273635014412 0ustar bbarber Imprecision in Qhull

Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
To: Qhull imprecision: contents


[4-d cube] Imprecision in Qhull

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

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

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

Copyright © 1995-2020 C.B. Barber


»Qhull imprecision: contents


»Precision problems

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

There are several kinds of precision errors:

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

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

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

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

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

Joggled input avoids merged facets and the topological issues that may arise. If your application is sensitive to errors, consider joggled input and the corresponding flag, qh_NOmerge.

Qhull 3.1 and later provides option 'Qt' for triangulated output. Non-simplicial facets are triangulated. The facets may have zero area. Triangulated output is particularly useful for Delaunay triangulations.

Qhull 2019.1 includes an experimental option ('Q14') to merge nearly adjacent vertices due to duplicated ridges. If reports a topological error if merging fails to resolve the issue. Further work is needed.

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

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

qconvex FV n | qhalf Fp

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

»Merged facets or joggled input

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

  • Use merged facets (the default) when you want non-simplicial output (e.g., the faces of a cube).
  • Use joggled input ('QJ') when you need clearly-convex, simplicial output.
  • Use joggled input if your code is sensitive to errors. Joggled input handles all inputs, even highly degenerate inputs such as 100 identical points. If you compile with qh_NOmerge, Qhull does not contain code for merging facets. It uses joggled input instead.
  • Otherwise, use merged facets and triangulated output ('Qt') when you want simplicial output and coplanar facets (e.g., triangles for a Delaunay triangulation).

The choice between merged facets and joggled input depends on the application. Both run about the same speed. Joggled input may be faster if the initial joggle is sufficiently large to avoid precision errors. Although less precise, joggled input is more reliable than merged facets. A future version of Qhull will provide per vertex joggle.

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

  • Your application supports non-simplicial facets, or it allows degenerate, simplicial facets (option 'Qt').
  • You do not want the input modified.
  • Your input coordinates start with the same five or more digits (i.e., it is shifted relative to the origin). This reduces the available precision.
  • You use single precision arithmetic (realT).
  • You want to set additional options for approximating the hull.

Use joggled input ('QJ') if

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

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

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

Merged facets ('C-0') handles precision problems directly. If a precision problem occurs, Qhull merges one of the offending facets into one of its neighbors. With multiple merges, topological problems may lead to severe precision problems, or prevent Qhull from continuing. Otherwise, Qhull will either fix the problem or attempt to merge the last remaining facets.

»Joggled input

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

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

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

Convex hull of unit cube

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

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

Convex hull of 1000 points on unit cube

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

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

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

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

»Delaunay triangulations

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

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

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

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

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

»Halfspace intersection

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

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

»Merged facets

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

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

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

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

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

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

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

»How Qhull merges facets

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

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

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

If a topological error occurs, such as more than two neighbors for a newly created ridge, Qhull may merge nearly adjacent vertices.

»Limitations of merged facets

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

    For example, compare

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

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

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

            rbox 10000 W1e-13  | qhull Q6  Tv
    

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

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

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

             rbox 1000 L100000 s G1e-16 t1002074964 | qhull Tv Q10
    

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

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

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

             rbox 1000 L100000 s G1e-16 t1002074964 | qhull Tv Q10
    

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

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

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

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

  • Nearly adjacent vertices within 1e-13 -- Multiple, nearly adjacent vertices within a 1e-13 ball in the unit cube may lead to topological errors and wide facets. The experimental option 'Q14' for Qhull 2019.1 merges nearly adjacent vertices to resolve dupridges. A dupridge is a topological error where multiple facets meet at the same ridge. Further improvements are needed, primarily for 4-D and higher. For example, the Delaunay triangulation of 400 pairs of nearly adjacent 5-D points frequently fails with a topological error (eg/qtest.sh 10 '400 C1,2e-13 D5' 'Q14 d Qbb').

    For Delaunay triangulations, the problem typically occurs for extreme points of the input set (i.e., on the edge between the upper and lower convex hull). After multiple facet merges, four facets may share a "dupridge" and must be merged. Some of these facets may be twisted relative to each other, leading to a very wide merged facet. If so, error QH6271 is reported. It may be overriden with option 'Q12'.

    A "dupridge" may occur when the horizon facets for a new point is "pinched" (i.e., two vertices are nearly adjacent). If a subridge (e.g., a line segment in 3-d) is shared by two horizon facets, the four corresponding new facets meet at the same ridge, called a "dupridge". In poly_r.c, qh_matchnewfacets calls qh_matchneighbor. qh_matchneighbor identifies dupridges for matching by qh_matchdupridge. In merge_r.c, qh_mark_dupridges identifies facets for merging across a dupridge. If vertices are nearly adjacent, qh_merge_pinchedvertices merges the vertices, otherwise qh_forcedmerges merges the facets. qh_forcedmerges checks for wide merges with qh_check_dupridge.

    It is easy to generate nearly adjacent or coincident points with rbox option 'Cn,r,m'. It generates n points within an r ball for each of m input sites. For example, the following examples successfully merge pinched vertices. Substantially smaller or larger balls do not lead to pinched horizons.

            rbox 2000 C1,1e-13 D4 s t | qhull Q14
            rbox 500 C1,1e-13 t | qhull Q14 d Qbb
    
    For Delaunay triangulations, a bounding box may alleviate this issue (e.g., rbox 500 C1,1E-13 D4 t c G1.0 | qhull Q14 d Qbb). The Delaunay triangulation of a regular mesh is likewise sensitive to nearly adjacent vertices.
            rbox 2000 M3,4,5 D4 C1,1e-8 | qhull Q14 d Qbb
    

  • Topological errors -- Merging facets and vertices may lead to topological errors that do not occur for mathematical, convex hulls. Qhull merges redundant or degenerate facets. With option 'Q14', Qhull tries to correct "dupridges" by merging vertices or facets (see previous issue). It corrects some instances of dupridges. Qhull reports a "Qhull topology error" if a topological error leads to a wide facet or if Qhull fails to create a cone of new facets. It leaves other cases as is. The orientation of nonsimplicial facets is ill-defined. Ridges may have the same vertices. Adjacent nonsimplicial facets may have incompatible triangulations. These problems may be addressed in future releases of Qhull.

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

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

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

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

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

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

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

»Exact arithmetic

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

CGAL includes a practical implementation of symbolic perturbation. It uses the BOOST library to generate dimension-specific, C++ data structures. It makes good use of 64-bit memory. Input sites may be added incrementally. It is the fastest 64-bit code available.

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

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

»Approximating a convex hull

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

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

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


Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
To: Qhull imprecision: contents


The Geometry Center Home Page

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

qhull-2020.2/html/qh-optc.htm0000644060175106010010000002762013716271251014233 0ustar bbarber Qhull precision options

Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)


[delaunay] Qhull precision options

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

Copyright © 1995-2020 C.B. Barber


» Programs OptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)

Precision options

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

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

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

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

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

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

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

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

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

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

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

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

»C-0 - handle all precision errors

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

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

»C-n - centrum radius for pre-merging

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

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

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

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

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

»Cn - centrum radius for post-merging

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

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

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

»En - max roundoff error for distance computations

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

»Rn - randomly perturb computations

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

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

»Un - max distance for a new, coplanar point

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

»Vn - min distance for a visible facet

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

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

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

»Wn - min distance above plane for outside points

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

This option is good for approximating a convex hull.

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


Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)


The Geometry Center Home Page

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

qhull-2020.2/html/qh-optf.htm0000644060175106010010000010112013716271251014222 0ustar bbarber Qhull format options (F)

Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)


[delaunay] Qhull format options (F)

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

Copyright © 1995-2020 C.B. Barber


» Programs OptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)

Additional input & output formats

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

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

»Fa - print area for each facet

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

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

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

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

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

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

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

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

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

»Fc - print coplanar points for each facet

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

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

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

For halfspace intersection (qhalf), a "facet" is an intersection point and a "point" is a halfspace. Option 'Fc' lists the coplanar halfspaces for each intersection point. The first line is the number of intersection points. Each remaining line starts with the number of coplanar halfspaces. A coplanar halfspace is listed for one intersection point even though it is coplanar to multiple intersection points. Options "Fc Qi" list the redundant halfspaces for each intersection point.

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

»FC - print centrum or Voronoi vertex for each facet

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

»Fd - use cdd format for input

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

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

»FD - use cdd format for normals

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

»FF - print facets w/o ridges

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

»Fi - print inner planes for each facet

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

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

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

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

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

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

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

»FI - print ID for each facet

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

»Fm - print merge count for each facet

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

»FM - print Maple output

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

Warning: This option has not been tested in Maple.

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

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

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

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

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

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

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

    qconvex s FM <datafile.txt >dataplot.mpl

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

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

For Delaunay triangulation orthogonal projection is better.

For halfspace intersections, Qhull produces the dual convex hull.

See Is Qhull available for Maple? for other URLs.

»Fn - print neighboring facets for each facet

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

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

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

For halfspace intersection (qhalf), a "facet" is an intersection point. Option 'Fn' lists the neighboring intersection points for each intersection point.

»FN - print neighboring facets for each point

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

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

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

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

For halfspace intersection (qhalf), a "facet" is an intersection point and a "point" is a halfspace. Option 'FN' lists the intersection points for each halfspace. The first line is the number of halfspaces. Each remaining line starts with the number of intersection points for this halfspace. Redundant halfspaces have 0 intersection points.

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

»Fo - print outer planes for each facet

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

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

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

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

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

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

Option 'Fo' gives the separating hyperplanes for the unbounded regions of the Voronoi diagram. The midpoint between each pair of input sites is used in place of the vertex at infinity.

If the midpoint happens to be a Voronoi vertex, the hyperplane is degenerate (e.g., 'rbox c P0 D2 | qvoronoi p Fo').

Use 'Fi' for bounded regions, and 'Fv' for the corresponding Voronoi vertices.

»FO - print list of selected options

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

»Fp - print points at halfspace intersections

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

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

»FP - print nearest vertex for coplanar points

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

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

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

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

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

»FQ - print command for qhull and input

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

»Fs - print summary

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

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

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

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

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

Later versions of Qhull may produce additional integers or reals.

»FS - print sizes

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

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

»Ft - print triangulation

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

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

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

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

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

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

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

»Fv - print vertices for each facet

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

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

For halfspace intersection (qhalf), a "facet" is an intersection point and a "point" is a halfspace. Option 'Fv' lists the non-redundant halfspaces incident to each intersection point. The first line is the number of non-redundant halfspaces. Each remaining line starts with the number of non-redundant halfspaces incident to that point.

»Fv - print Voronoi diagram

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

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

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

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

»FV - print average vertex

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

qconvex FV n | qhalf Fp

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

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

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

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

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

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


Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)


The Geometry Center Home Page

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

qhull-2020.2/html/qh-optg.htm0000644060175106010010000002600613716271251014234 0ustar bbarber Qhull Geomview options (G)

Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)


[delaunay] Qhull Geomview options (G)

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

Copyright © 1995-2020 C.B. Barber


» Programs OptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)

Geomview output options

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

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

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

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

»G - produce output for viewing with Geomview

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

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

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

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

»Ga - display all points as dots

Each input point is displayed as a green dot.

»Gc - display centrums (3-d)

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

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

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

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

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

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

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

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

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

»Gn - do not display planes

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

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

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

»Gp - display coplanar points and vertices as radii

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

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

»Gr - display ridges (3-d)

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

»Gt - transparent 3-d Delaunay

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

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

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


Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)


The Geometry Center Home Page

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

qhull-2020.2/html/qh-opto.htm0000644060175106010010000003672013716271251014250 0ustar bbarber Qhull output options

Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)


[delaunay] Qhull output options

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

Copyright © 1995-2020 C.B. Barber


» Programs OptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)

Output options

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

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

»f - print all fields of all facets

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

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

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

»i - print vertices incident to each facet

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

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

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

For halfspace intersection (qhalf), a "facet" is an intersection point and a "point" is a halfspace. Option 'i' lists the non-redundant halfspaces incident to each intersection point. The first line is the number of non-redundant halfspaces. Each remaining line lists the incident, non-redundant halfspaces for that intersection point.

»m - print Mathematica output

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

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

For halfspace intersections, Qhull produces the dual convex hull.

See Is Qhull available for Mathematica? for URLs.

»n - print hyperplane normals with offsets

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

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

A point is inside or below a hyperplane if its distance to the hyperplane is negative. A point is outside or above a hyperplane if its distance to the hyperplane is positive. Otherwise a point is on or coplanar to the hyperplane.

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

»o - print OFF file format

The output is:

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

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

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

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

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

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

»p - print vertex and point coordinates

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

With the 'Gc' and 'Gi' options, option 'p' also prints coplanar and interior points respectively.

For qvoronoi, it prints the coordinates of each Voronoi vertex.

For qdelaunay, it prints the input sites as lifted to a paraboloid. For qhalf it prints the dual points. For both, option 'p' is the same as the first section of option 'o'.

Use 'Fx' to list the point ids of the extreme points (i.e., vertices).

If a subset of the facets is selected ('Pdk', 'PDk', 'Pg' options), option 'p' only prints vertices and points associated with those facets.

If cdd-output format is selected ('FD'), the first line is "begin". The second line is the number of vertices, the dimension plus one, and "real". The vertices follow with a leading "1". Output ends with "end".

»s - print summary to stderr

The default output of Qhull is a summary to stderr. Options 'FS' and 'Fs' produce the same information for programs. Note: Windows 95 and 98 treats stderr the same as stdout. Use option 'TO file' to separate stderr and stdout.

The summary lists the number of input points, the dimension, the number of vertices in the convex hull, and the number of facets in the convex hull. It lists the number of selected ("good") facets for options 'Pg', 'Pdk', qdelaunay, or qvoronoi (Delaunay triangulations only use the lower half of a convex hull). It lists the number of coplanar points. For Delaunay triangulations without 'Qc', it lists the total number of coplanar points. It lists the number of simplicial facets in the output.

The terminology depends on the output structure.

The summary lists these statistics:

  • number of points processed by Qhull
  • number of hyperplanes created
  • number of distance tests (not counting statistics, summary, and checking)
  • number of merged facets (if any)
  • number of distance tests for merging (if any)
  • CPU seconds to compute the hull
  • the maximum joggle for 'QJ'
    or, the probability of precision errors for 'QJ TRn'
  • total area and volume (if computed, see 'FS' 'FA' 'Fa' 'PAn')
  • max. distance of a point above a facet (if non-zero)
  • max. distance of a vertex below a facet (if non-zero)

The statistics include intermediate hulls. For example 'rbox d D4 | qhull' reports merged facets even though the final hull is simplicial.

Qhull starts counting CPU seconds after it has read and projected the input points. It stops counting before producing output. In the code, CPU seconds measures the execution time of function qhull() in libqhull.c. If the number of CPU seconds is clearly wrong, check qh_SECticks in user.h.

The last two figures measure the maximum distance from a point or vertex to a facet. They are not printed if less than roundoff or if not merging. They account for roundoff error in computing the distance (c.f., option 'Rn'). Use 'Fs' to report the maximum outer and inner plane.

A number may appear in parentheses after the maximum distance (e.g., 2.1x). It is the ratio between the maximum distance and the worst-case distance due to merging two simplicial facets. It should be small for 2-d, 3-d, and 4-d, and for higher dimensions with 'Qx'. It is not printed if less than 0.05.


Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)


The Geometry Center Home Page

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

qhull-2020.2/html/qh-optp.htm0000644060175106010010000002367113716271251014252 0ustar bbarber Qhull print options (P)

Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)


[delaunay] Qhull print options (P)

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

Copyright © 1995-2020 C.B. Barber


» Programs OptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)

Print options

Po
force output despite precision problems
Po
if error, output neighborhood of facet
Pp
do not report precision problems
 
 
Selection options
PAn
print n largest facets by area
Pdk:n
print facets with normal[k] >= n (default 0.0)
PDk:n
print facets with normal[k] <= n
PFn
print facets whose area is at least n
Pg
print good facets only (needs 'QGn' or 'QVn')
PG
print neighbors of good facets
PMn
print n facets with most merges

»PAn - keep n largest facets by area

The n largest facets are marked good for printing. This may be useful for approximating a hull. Unless 'PG' is set, 'Pg' is automatically set.

»Pdk:n - print facet if normal[k] >= n

For a given output, print only those facets with normal[k] >= n and drop the others. For example, 'Pd0:0.5' prints facets with normal[0] >= 0.5 . The default value of n is zero. For example in 3-d, 'Pd0d1d2' prints facets in the positive octant.

If no facets match, use option 'Pg' to print the closest facet.

On Windows 95, do not combine multiple options. A 'd' is considered part of a number. For example, use 'Pd0:0.5 Pd1:0.5' instead of 'Pd0:0.5d1:0.5'.

»PDk:n - print facet if normal[k] <= n

For a given output, print only those facets with normal[k] <= n and drop the others. For example, 'PD0:0.5' prints facets with normal[0] <= 0.5 . The default value of n is zero. For example in 3-d, 'PD0D1D2' displays facets in the negative octant.

If no facets match, use option 'Pg' to print the closest facet.

In 2-d, 'd G PD2' displays the Delaunay triangulation instead of the corresponding paraboloid.

Be careful of placing 'Dk' or 'dk' immediately after a real number. Some compilers treat the 'D' as a double precision exponent.

»PFn - keep facets whose area is at least n

The facets with area at least n are marked good for printing. This may be useful for approximating a hull. Unless 'PG' is set, 'Pg' is automatically set.

»Pg - print good facets

Qhull can mark facets as "good". This is used to

  • mark the lower convex hull for Delaunay triangulations and Voronoi diagrams
  • mark the facets that are visible from a point (option 'QGn')
  • mark the facets that contain a point (option 'QVn').
  • indicate facets with a large enough area (options 'PAn' and 'PFn')
  • indicate facets with many merges (option 'PMn')

Option 'Pg' only prints good facets that also meet 'Pdk' and 'PDk' options. It is automatically set for options 'd', 'PAn', 'PFn', 'PMn', 'QGn', and 'QVn'.

»PG - print neighbors of good facets

Option 'PG' can be used with or without option 'Pg' to print the neighbors of good facets. For example, options 'QGn' and 'QVn' print the horizon facets for point n.

»PMn - keep n facets with most merges

The n facets with the most merges are marked good for printing. This may be useful for approximating a hull. Unless 'PG' is set, 'Pg' is automatically set.

Use option 'Fm' to print merges per facet.

»Po - force output despite precision problems

Use options 'Po' and 'Q0' if you can not merge facets, triangulate the output ('Qt'), or joggle the input (QJ).

Option 'Po' can not force output when duplicate ridges or duplicate facets occur. It may produce erroneous results. For these reasons, merged facets, joggled input, or exact arithmetic are better.

If you need a simplicial Delaunay triangulation, use joggled input 'QJ' or triangulated output 'Ft'.

Option 'Po' may be used without 'Q0' to remove some steps from Qhull or to output the neighborhood of an error.

Option 'Po' may be used with option 'Q5') to skip qh_check_maxout (i.e., do not determine the maximum outside distance). This can save a significant amount of time.

If option 'Po' is used,

  • most precision errors allow Qhull to continue.
  • verify ('Tv') does not check coplanar points.
  • points are not partitioned into flipped facets and a flipped facet is always visible to a point. This may delete flipped facets from the output.

»Po - if error, output neighborhood of facet

If an error occurs before the completion of Qhull and tracing is not active, 'Po' outputs a neighborhood of the erroneous facets (if any). It uses the current output options.

See 'Po' - force output despite precision problems.

»Pp - do not report precision problems

With option 'Pp', Qhull does not print statistics about precision problems, and it removes some of the warnings. It removes the narrow hull warning.


Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)


The Geometry Center Home Page

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

qhull-2020.2/html/qh-optq.htm0000644060175106010010000011150413716271251014244 0ustar bbarber Qhull control options (Q)

Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)


[delaunay] Qhull control options (Q)

This section lists the control options for Qhull. These options are indicated by 'Q' followed by a letter.

Copyright © 1995-2020 C.B. Barber


» Programs OptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)

Qhull control options

Qa
allow input with fewer or more points than coordinates
Qc
keep coplanar points with nearest facet
Qi
keep interior points with nearest facet
QJ
joggled input to avoid precision problems
Qt
triangulated output
Qu
compute upper hull for furthest-site Delaunay triangulation
Qw
allow warnings about Qhull options
 
 
Precision handling
Qbb
scale last coordinate to [0,m] for Delaunay
Qs
search all points for the initial simplex
Qv
test vertex neighbors for convexity
Qx
exact pre-merges (allows coplanar facets)
Qz
add a point-at-infinity for Delaunay triangulations
 
 
Transform input
Qbk:n
scale coord[k] to low bound of n (default -0.5)
Qbk:0Bk:0
drop dimension k from input
QbB
scale input to fit the unit cube
QBk:n
scale coord[k] to upper bound of n (default 0.5)
QRn
random rotation (n=seed, n=0 time, n=-1 time/no rotate)
 
 
Select facets
Qg
only build good facets (needs 'QGn', 'QVn', or 'Pdk')
QGn
good facet if visible from point n, -n for not visible
QVn
good facet if it includes point n, -n if not
 
 
Experimental
Qf
partition point to furthest outside facet
Qm
process points only if they would increase the max. outer plane
Qr
process random outside points instead of furthest one
Q0
do not pre-merge facets with 'C-0' or 'Qx'
Q1
merge by mergetype/angle instead of mergetype/distance
Q2
merge all non-convex at once instead of independent sets
Q3
do not merge redundant vertices
Q4
avoid merging old facets into new facets
Q5
do not correct outer planes at end of qhull
Q6
do not pre-merge concave or coplanar facets
Q7
process facets depth-first instead of breadth-first
Q8
ignore near-interior points
Q9
process furthest of furthest points
Q10
no special processing for narrow distributions
Q11
copy normals and recompute centrums for tricoplanar facets
Q12
allow wide facets and wide dupridge
Q14
merge pinched vertices that create a dupridge
Q15
check for duplicate ridges with the same vertices

»Qa - allow input with fewer or more points than coordinates

Option 'Qa' (qh.ALLOWshort) allows input with fewer or more points than coordinates. Qhull's input starts with the number of points and the dimension, d. The coordinates follow, d coordinates per point.

With option 'Qa', there may be fewer or more points than coordinates. This simplifies exploring an input point set by adjusting the number of points.

»Qbb - scale the last coordinate to [0,m] for Delaunay

After scaling with option 'Qbb', the lower bound of the last coordinate will be 0 and the upper bound will be the maximum width of the other coordinates. Scaling happens after projecting the points to a paraboloid and scaling other coordinates.

Option 'Qbb' is automatically set for qdelaunay and qvoronoi. Option 'Qbb' is automatically set for joggled input 'QJ'.

Option 'Qbb' should be used for Delaunay triangulations with integer coordinates. Since the last coordinate is the sum of squares, it may be much larger than the other coordinates. For example, rbox 10000 D2 B1e8 | qhull d has precision problems while rbox 10000 D2 B1e8 | qhull d Qbb is OK.

»QbB - scale the input to fit the unit cube

After scaling with option 'QbB', the lower bound will be -0.5 and the upper bound +0.5 in all dimensions. For different bounds change qh_DEFAULTbox in user.h (0.5 is best for Geomview).

For Delaunay and Voronoi diagrams, scaling happens after projection to the paraboloid. Under precise arithmetic, scaling does not change the topology of the convex hull. Scaling may reduce precision errors if coordinate values vary widely.

»Qbk:n - scale coord[k] to low bound

After scaling, the lower bound for dimension k of the input points will be n. 'Qbk' scales coord[k] to -0.5.

»QBk:n - scale coord[k] to upper bound

After scaling, the upper bound for dimension k of the input points will be n. 'QBk' scales coord[k] to 0.5.

»Qbk:0Bk:0 - drop dimension k from the input points

Drop dimension k from the input points. For example, 'Qb1:0B1:0' deletes the y-coordinate from all input points. This allows the user to take convex hulls of sub-dimensional objects. It happens before the Delaunay and Voronoi transformation. It happens after the halfspace transformation for both the data and the feasible point.

»Qc - keep coplanar points with nearest facet

During construction of the hull, a point is coplanar if it is between 'Wn' above and 'Un' below a facet's hyperplane. A different definition is used for output from Qhull.

For output, a coplanar point is above the minimum vertex (i.e., above the inner plane). With joggle ('QJ'), a coplanar point includes points within one joggle of the inner plane.

With option 'Qc', output formats 'p', 'f', 'Gp', 'Fc', 'FN', and 'FP' will print the coplanar points. With options 'Qc Qi' these outputs include the interior points.

For Delaunay triangulations (qdelaunay or qvoronoi), a coplanar point is a point that is nearly incident to a vertex. All input points are either vertices of the triangulation or coplanar.

Qhull stores coplanar points with a facet. While constructing the hull, it retains all points within qh_RATIOnearInside (user.h) of a facet. In qh_check_maxout(), it uses these points to determine the outer plane for each facet. With option 'Qc', qh_check_maxout() retains points above the minimum vertex for the hull. Other points are removed. If qh_RATIOnearInside is wrong or if options 'Q5 Q8' are set, a coplanar point may be missed in the output (see Qhull limitations).

»Qf - partition point to furthest outside facet

After adding a new point to the convex hull, Qhull partitions the outside points and coplanar points of the old, visible facets. Without the 'f' option and merging, it assigns a point to the first facet that it is outside ('Wn'). When merging, it assigns a point to the first facet that is more than several times outside (see qh_DISToutside in user.h).

If option 'Qf' is selected, Qhull performs a directed search (no merging) or an exhaustive search (merging) of new facets. Option 'Qf' may reduce precision errors if pre-merging does not occur.

Option 'Q9' processes the furthest of all furthest points.

»Qg - only build good facets (needs 'QGn' 'QVn' or 'Pdk')

Qhull has several options for defining and printing good facets. With the 'Qg' option, Qhull will only build those facets that it needs to determine the good facets in the output. Outside points that are not above good facets are ignored. This may speed up Qhull in 2-d and 3-d. It is useful for furthest-site Delaunay triangulations (qdelaunay Qu, invoke with 'qhull d Qbb Qu Qg'). It is not effective in higher dimensions because many facets see a given point and contain a given vertex. It may not work for all combinations of options.

See 'QGn', 'QVn', and 'Pdk' for defining good facets, and 'Pg' and 'PG' for printing good facets and their neighbors. If pre-merging ('C-n') is not used and there are coplanar facets, then 'Qg Pg' may produce a different result than 'Pg'.

Option Qg disables renaming vertices due to duplicate ridges. See ('Q14' merge-pinched-vertices).

»QGn - good facet if visible from point n, -n for not visible

With option 'QGn', a facet is good (see 'Qg' and 'Pg') if it is visible from point n. If n < 0, a facet is good if it is not visible from point n. Point n is not added to the hull (unless 'TCn' or 'TPn').

With rbox, use the 'Pn,m,r' option to define your point; it will be point 0 ('QG0').

»Qi - keep interior points with nearest facet

Normally Qhull ignores points that are clearly interior to the convex hull. With option 'Qi', Qhull treats interior points the same as coplanar points. Option 'Qi' does not retain coplanar points. You will probably want 'Qc' as well.

Option 'Qi' is automatically set for 'qdelaunay Qc' and 'qvoronoi Qc'. If you use 'qdelaunay Qi' or 'qvoronoi Qi', option 's' reports all nearly incident points while option 'Fs' reports the number of interior points (should always be zero).

With option 'Qi', output formats 'p', 'f','Gp', 'Fc', 'FN', and 'FP' include interior points.

»QJ or QJn - joggled input to avoid precision errors

Option 'QJ' or 'QJn' joggles each input coordinate by adding a random number in the range [-n,n]. If a precision error occurs, It tries again. If precision errors still occur, Qhull increases n ten-fold and tries again. The maximum value for increasing n is 0.01 times the maximum width of the input. Option 'QJ' selects a default value for n. The header file user_r.h defines these parameters and a maximum number of retries. See Merged facets or joggled input.

On repeated joggles, Qhull errors (QH6010) if the joggle is greater than 0.1 or one quarter of the maximum coordinate width.

Users of joggled input should consider converting to triangulated output ('Qt'). Triangulated output is approximately 1000 times more accurate than joggled input.

Option 'QJ' also sets 'Qbb' for Delaunay triangulations and Voronoi diagrams. It does not set 'Qbb' if 'Qbk:n' or 'QBk:n' are set.

If 'QJn' is set, Qhull does not merge facets unless requested to. All facets are simplicial (triangular in 2-d). This may be important for your application. You may also use triangulated output ('Qt') or Option 'Ft'.

Qhull adjusts the outer and inner planes for 'QJn' ('Fs'). They are increased by sqrt(d)*n to account for the maximum distance between a joggled point and the corresponding input point.

Coplanar points ('Qc', option '_near-inside') require an additional sqrt(d)*n since vertices and coplanar points may be joggled in opposite directions.

For Delaunay triangulations (qdelaunay), joggle happens before lifting the input sites to a paraboloid. Instead of 'QJ', you may use triangulated output ('Qt')

This option is deprecated for Voronoi diagrams (qvoronoi). It triangulates cospherical points, leading to duplicated Voronoi vertices.

By default, 'QJn' uses a fixed random number seed. To use time as the random number seed, select 'QR-1'. The summary ('s') will show the selected seed as 'QR-n'.

With 'QJn', Qhull does not error on degenerate hyperplane computations. Except for Delaunay and Voronoi computations, Qhull does not error on coplanar points.

Use option 'FO' to display the selected options. Option 'FO' displays the joggle and the joggle seed. If Qhull restarts, it will redisplay the options.

Use option 'TRn' to estimate the probability that Qhull will fail for a given 'QJn'.

If your application incrementally adds points with qh_addpoint, facet merging for precision problems is disabled by default. You can reduce the probability of failure by joggling the point's coordinates before calling qh_addpoint. See qh_joggleinput for sample code.

»Qm - only process points that increase the maximum outer plane

Qhull reports the maximum outer plane in its summary ('s'). With option 'Qm', Qhull does not process points that are below the current, maximum outer plane. This is equivalent to always adjusting 'Wn ' to the maximum distance of a coplanar point to a facet. It is ignored for points above the upper convex hull of a Delaunay triangulation. Option 'Qm' is no longer important for merging.

»Qr - process random outside points instead of furthest ones

Normally, Qhull processes the furthest point of a facet's outside points. Option 'Qr' instead selects a random outside point for processing. This makes Qhull equivalent to the randomized incremental algorithms.

The original randomization algorithm by Clarkson and Shor ['89] used a conflict list which is equivalent to Qhull's outside set. Later randomized algorithms retained the previously constructed facets.

To compare Qhull to the randomized algorithms with option 'Qr', compare "hyperplanes constructed" and "distance tests". Qhull does not report CPU time because the randomization is inefficient.

»QRn - random rotation

Option 'QRn' randomly rotates the input. For Delaunay triangulations (qdelaunay or qvoronoi), it rotates the lifted points about the last axis.

If n=0, use time as the random number seed. If n>0, use n as the random number seed. If n=-1, don't rotate but use time as the random number seed. If n<-1, don't rotate but use n as the random number seed.

If set, the summary option ('s') displays the corresponding 'QRn' option after "Statistics for: ..."

»Qs - search all points for the initial simplex

Qhull constructs an initial simplex from d+1 points. It selects points with the maximum and minimum coordinates and non-zero determinants. If this fails, it searches all other points. In 8-d and higher, Qhull selects points with the minimum x or maximum coordinate (see qh_initialvertices in poly2.c ). It rejects points with nearly zero determinants. This should work for almost all input sets.

If Qhull can not construct an initial simplex, it reports a descriptive message. Usually, the point set is degenerate and one or more dimensions should be removed ('Qbk:0Bk:0'). If not, use option 'Qs'. It performs an exhaustive search for the best initial simplex. This is expensive is high dimensions.

»Qt - triangulated output

By default, qhull merges facets to handle precision errors. This produces non-simplicial facets (e.g., the convex hull of a cube has 6 square facets). Each facet is non-simplicial because it has four vertices.

Use option 'Qt' to triangulate all non-simplicial facets before generating results. Alternatively, use joggled input ('QJ') to prevent non-simplical facets. Unless 'Pp' is set, qhull produces a warning if 'QJ' and 'Qt' are used together.

For Delaunay triangulations (qdelaunay), triangulation occurs after lifting the input sites to a paraboloid and computing the convex hull.

Option 'Qt' is deprecated for Voronoi diagrams (qvoronoi). It triangulates cospherical points, leading to duplicated Voronoi vertices.

Option 'Qt' may produce degenerate facets with zero area.

Facet area and hull volumes may differ with and without 'Qt'. The triangulations are different and different triangles may be ignored due to precision errors.

With sufficient merging, the ridges of a non-simplicial facet may share more than two neighboring facets. If so, their triangulation ('Qt') will fail since two facets have the same vertex set.

»Qu - compute upper hull for furthest-site Delaunay triangulation

When computing a Delaunay triangulation (qdelaunay or qvoronoi), Qhull computes both the the convex hull of points on a paraboloid. It normally prints facets of the lower hull. These correspond to the Delaunay triangulation. With option 'Qu', Qhull prints facets of the upper hull. These correspond to the furthest-site Delaunay triangulation and the furthest-site Voronoi diagram.

Option 'qhull d Qbb Qu Qg' may improve the speed of option 'Qu'. If you use the Qhull library, a faster method is 1) use Qhull to compute the convex hull of the input sites; 2) take the extreme points (vertices) of the convex hull; 3) add one interior point (e.g., 'FV', the average of d extreme points); 4) run 'qhull d Qbb Qu' or 'qhull v Qbb Qu' on these points.

»Qv - test vertex neighbors for convexity

Normally, Qhull tests all facet neighbors for convexity. Non-neighboring facets which share a vertex may not satisfy the convexity constraint. This occurs when a facet undercuts the centrum of another facet. They should still be convex. Option 'Qv' extends Qhull's convexity testing to all neighboring facets of each vertex. The extra testing occurs after the hull is constructed..

»QVn - good facet if it includes point n, -n if not

With option 'QVn', a facet is good ('Qg', 'Pg') if one of its vertices is point n. If n<0, a good facet does not include point n.

If options 'PG' and 'Qg' are not set, option 'Pg' (print only good) is automatically set.

Option 'QVn' behaves oddly with options 'Fx' and 'qvoronoi Fv'.

If used with option 'Qg' (only process good facets), point n is either in the initial simplex or it is the first point added to the hull. Options 'QVn Qg' require either 'QJ' or 'Q0' (no merging).

»Qw - allow warnings about Qhull options

Option 'Qw' allows warning about unknown, malformed, or incompatible Qhull options. If 'Qw' is not specified, option warnings produce a 'Qhull option error' and return exit status qh_ERRinput (1).

»Qx - exact pre-merges (allows coplanar facets)

Option 'Qx' performs exact merges while building the hull. Options 'Qx' and 'C-0' are set by default in 5-d and higher. To disable this default, set option 'C-0' or another pre-merge option. Use option 'Q0' to disable all merging, including 'Qx' and 'C-0'.

The "exact" pre-merges are merging a point into a coplanar horizon facet (defined by 'Vn', 'Un', and 'C-n'), merging concave facets, merging duplicate ridges, and merging flipped facets. Coplanar merges and angle coplanar merges ('A-n') are not performed. Superfluous vertices are allowed. Concavity testing is delayed until a merge occurs.

After the hull is built, all coplanar merges are performed (defined by 'C-n' and 'A-n'), then post-merges are performed (defined by 'Cn' and 'An'). Superfluous vertices are removed.

If facet progress is logged ('TFn'), Qhull reports each phase and prints intermediate summaries and statistics ('Ts').

Without 'Qx' in 5-d and higher, options 'C-n' and 'A-n' may merge too many facets. Facets become increasingly wide.

Option 'Qx' may report a wide facet. With 'Qx', coplanar facets are not merged. This can produce a "dent" in an intermediate hull. If a point is partitioned into a dent and it is below the surrounding facets but above other facets, one or more wide facets will occur. In practice, this is unlikely. To observe this effect, run Qhull with option 'Q6' which doesn't pre-merge concave facets. A concave facet makes a large dent in the intermediate hull.

Option 'Qx' may set an outer plane below one of the input points. A coplanar point may be assigned to the wrong facet because of a "dent" in an intermediate hull. After constructing the hull, Qhull double checks all outer planes with qh_check_maxout in poly2.c . If a coplanar point is assigned to the wrong facet, qh_check_maxout may reach a local maximum instead of locating all coplanar facets. This appears to be unlikely.

»Qz - add a point-at-infinity for Delaunay triangulations

Option 'Qz' adds a point above the paraboloid of lifted sites for a Delaunay triangulation. It allows the Delaunay triangulation of cospherical sites. It reduces precision errors for nearly cospherical sites.

»Q0 - no merging with C-0 and Qx

Turn off default merge options 'C-0' and 'Qx'.

With 'Q0' and without other pre-merge options, Qhull ignores precision issues while constructing the convex hull. This may lead to precision errors. If so, a descriptive warning is generated. See Precision issues.

»Q1 - merge by mergetype/angle instead of mergetype/distance

Qhull merges coplanar facets first, then concave and flipped facets. Within a merge-type, it merges coplanar facets by distance first.

With option 'Q1', Qhull merges coplanar facets by angle instead of by distance.

»Q2 - merge all non-convex at once instead of independent sets

With 'Q2', Qhull merges all facets at once instead of performing merges in independent sets. This may make the facets wider.

»Q3 - do not merge redundant vertices

With 'Q3', Qhull does not remove redundant vertices. In 6-d and higher, Qhull never removes redundant vertices (since vertices are highly interconnected). Option 'Q3' may be faster, but it may result in wider facets. Its effect is easiest to see in 3-d and 4-d.

»Q4 - avoid merging old facets into new facets

With 'Q4', Qhull avoids merges of an old facet into a new facet. This sometimes improves facet width and sometimes makes it worse. See qh_merge_nonconvex. It is not supported for qh_merge_twisted.

»Q5 - do not correct outer planes at end of qhull

When merging facets or approximating a hull, Qhull tests coplanar points and outer planes after constructing the hull. It does this by performing a directed search (qh_findbest in geom.c). It includes points that are just inside the hull.

With options 'Q5' or 'Po', Qhull does not test outer planes. The maximum outer plane is used instead. Coplanar points ('Qc') are defined by 'Un'. An input point may be outside of the maximum outer plane (this appears to be unlikely). An interior point may be above 'Un' from a hyperplane.

Option 'Q5' may be used if outer planes are not needed. Outer planes are needed for options 's', 'G', 'Go', 'Fs', 'Fo', 'FF', and 'f'.

»Q6 - do not pre-merge concave or coplanar facets

With 'Q6', Qhull does not pre-merge concave or coplanar facets. This demonstrates the effect of "dents" when using 'Qx'.

»Q7 - depth-first processing instead of breadth-first

With 'Q7', Qhull processes facets in depth-first order instead of breadth-first order. This may increase the locality of reference in low dimensions. If so, Qhull may be able to use virtual memory effectively.

In 5-d and higher, many facets are visible from each unprocessed point. So each iteration may access a large proportion of allocated memory. This makes virtual memory ineffectual. Once real memory is used up, Qhull will spend most of its time waiting for I/O.

Under 'Q7', Qhull runs slower and the facets may be wider.

»Q8 - ignore near-interior points

With 'Q8' and merging, Qhull does not process interior points that are near to a facet (as defined by qh_RATIOnearInside in user.h). This avoids partitioning steps. It may miss a coplanar point when adjusting outer hulls in qh_check_maxout(). The best value for qh_RATIOnearInside is not known. Options 'Q8 Qc' may be sufficient.

»Q9 - process furthest of furthest points

With 'Q9', Qhull processes the furthest point of all outside sets. This may reduce precision problems. The furthest point of all outside sets is not necessarily the furthest point from the convex hull.

»Q10 - no special processing for narrow distributions

With 'Q10', Qhull does not special-case narrow distributions. See Limitations of merged facets for more information.

»Q11 - copy normals and recompute centrums for tricoplanar facets

Option 'Qt' triangulates non-simplicial facets into "tricoplanar" facets. Normally tricoplanar facets share the same normal, centrum, and Voronoi vertex. They can not be merged or replaced. With option 'Q11', Qhull duplicates the normal and Voronoi vertex. It recomputes the centrum.

Use 'Q11' if you use the Qhull library to add points incrementally and call qh_triangulate() after each point. Otherwise, Qhull will report an error when it tries to merge and replace a tricoplanar facet.

With sufficient merging and new points, option 'Q11' may lead to precision problems such as duplicate ridges and concave facets. For example, if qh_triangulate() is added to qh_addpoint(), RBOX 1000 s W1e-12 t1001813667 P0 | QHULL d Q11 Tv, reports an error due to a duplicate ridge.

»Q12 - allow wide facets and wide dupridge

Option 'Q12' (qh.ALLOWwide) disables error exits due to wide facets and wide dupridge. With 'Q12', Qhull may produce arbitrarily wide facets. A facet is 'wide' if there is a wide gap between its outer plane (f.maxoutside above all points) and its inner plane (below its vertices). A wide facet is typically due to multiple topological and geometric problems that Qhull cannot resolve. As Qhull merges facets, they become increasingly wide, making further problems more likely.

A 'dupridge' is a ridge with more than two neighboring facets. A dupridge is a loop in the facet topology. A convex hull should never have dupridges, but with imprecise arithmetic, they may occur. Dupridges may occur in 3-D and higher. They are more likely for nearly adjacent points in 4-D and higher.

Qhull handles dupridges by merging all but one pair of facets (qh_matchdupridge in poly2_r.c) or by dropping one of its vertices as a coplanar point (qh_getpinchedmerges in merge_r.c). If vertices are too far apart and a merge would produce an wide facet, qh_check_dupridge reports an error. The corresponding error exit is disabled by 'Q12'.

To demonstrate the problem, use rbox option 'Cn,r,m' to generate nearly adjacent points. For Delaunay triangulations, a bounding box may alleviate this error (e.g., rbox 500 C1,1E-13 c G1 | qhull d). This avoids the ill-defined edge between upper and lower convex hulls. For more information, see "Nearly adjacent vertices within 1e-13" in Limitations of merged facets.

Errors disabled by 'Q12' return an error status of qh_ERRwide (8). Wide facets are defined by constants in user_r.h (qh_WIDE... and qh_RATIO...).

»Q14 - merge pinched vertices due to a dupridge

A ridge in Qhull is the d-1 simplex between two neighboring facets. For example in 3-d, a ridge is the edge shared by two neighboring polygons. With non-simplicial facets, Qhull may create a "dupridge", a ridge with four or more neighboring facets. In effect, the surface of the convex hull forms a loop that crosses itself at the dupridge. Qhull resolves a dupridge by merging a pair of facets. With experimental option, 'Q14' it may resolve a dupridge by merging a pair of vertices.

In 3-d and higher, nearly adjacent vertices may lead to dupridges (see "Nearly adjacent vertices within 1e-13" in Imprecision in Qhull). With option 'Q14', Qhull merges nearly adjacent vertices when they create a dupridge.

»Q15 - check for duplicate ridges with the same vertices

Option 'Q15' (qh.CHECKduplicates) checks for duplicate ridges after each merge (qh_maybe_duplicateridges, qh_checkfacet). Duplicate ridges have the same vertices. It is a topological error for convex hulls. Qhull resolves a duplicate ridge by merging vertices and partitioning the deleted vertex as a coplanar point (qh_renamevertex).

Option 'Q15' does not prevent duplicate ridges for non-neighboring facets, nor does it prevent other topological errors such as inconsistent facet orientation. Resolving a duplicate ridge may itself lead to topological errors and wide facets.


Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)


The Geometry Center Home Page

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

qhull-2020.2/html/qh-optt.htm0000644060175106010010000003143413716271251014252 0ustar bbarber Qhull trace options (T)

Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)


[delaunay] Qhull trace options (T)

This section lists the trace options for Qhull. These options are indicated by 'T' followed by a letter.

Copyright © 1995-2020 C.B. Barber


» Programs OptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)

Trace options

 
General
Ta
annotate output with message codes
TFn
report progress whenever n or more facets created
TI file
input data from a file
TO file
output results to a file
Ts
print statistics
Tv
verify result: structure, convexity, and point inclusion
Tz
output error information to stdout instead of stderr
 
 
Debugging
T4
trace at level n, 4=all, 5=mem/gauss, -1= events
TAn
stop after adding n vertices
Tc
check frequently during execution
TCn
stop qhull after building cone for point n
Tf
flush each qh_fprintf for debugging segfaults
TMn
turn on tracing at merge n
TPn
turn on tracing when point n added to hull
TRn
rerun qhull n times for QJn statitics
TV-n
stop qhull before adding point n
TVn
stop qhull after adding point n
TWn
trace merge facets when width > n

»Ta - annotate output with message codes

With option 'Ta', Qhull annotates output with message codes. Programmers may use these codes to trap the corresponding print statements.

»TAn - stop Qhull after adding n vertices

With option 'TAn', Qhull stops after adding n vertices. See option 'TVn' to stop after adding point n.

»Tc - check frequently during execution

Qhull includes frequent checks of its data structures. Option 'Tc' will catch most inconsistency errors. It is slow and should not be used for production runs. Option 'Tv' performs the same checks after the hull is constructed. Tracing ('T4') adds additional calls to qh_checkconvex, qh_checkpolygon, and qh_checkfacet.

»TCn - stop qhull after building cone for point n

Qhull builds a cone from the point to its horizon facets. Option 'TCn' stops Qhull just after building the cone. The output for 'f' includes the cone and the old hull.'.

»Tf - flush each qh_fprintf for debugging segfaults

Option 'Tf' flushes each qh_fprintf for debugging segfaults.

See option 'Tz' for redirecting stderr.

»TFn - report summary whenever n or more facets created

Option 'TFn' reports progress whenever more than n facets are created. The test occurs just before adding a new point to the hull. During post-merging, 'TFn' reports progress after more than n/2 merges.

»TI file - input data from file

Input data from 'file' instead of stdin. The filename may be enclosed in single quotes. If the filename does not contain spaces, TIfile is OK.

You may use I/O redirection instead (e.g., 'rbox 10 | qdelaunay >results').

»TMn - turn on tracing at merge n

Turn on tracing at n'th merge.

»Tn - trace at level n

Qhull includes full execution tracing. 'T-1' traces events. 'T1' traces the overall execution of the program. 'T2' and 'T3' trace overall execution, and geometric, topological, and merge events. 'T4' is the detailed trace of Qhull. 'T5' adds information about memory allocation and Gaussian elimination. 'T1' is useful for logging progress of Qhull in high dimensions. See Debugging Qhull.

Option 'Tn' can produce large amounts of output. Use options 'TPn', 'TWn', and 'TMn' to selectively turn on tracing. Since all errors report the last processed point, option 'TPn' is particularly useful.

Different executions of the same program may produce different traces and different results. The reason is that Qhull uses hashing to match ridges of non-simplicial facets. For performance reasons, the hash computation uses memory addresses which may change across executions.

»TO file - output results to file

Redirect stdout to 'file'. The filename may be enclosed in single quotes. If the filename does not contain spaces, TOfile is OK. Unix and Windows NT users may use I/O redirection instead of 'TO' (e.g., 'rbox 10 | qdelaunay >results').

Windows95 users should always use 'TO file'. If they use I/O redirection, error output is not sent to the console. Qhull uses single quotes instead of double quotes because a missing double quote can freeze Windows95 (e.g., do not run, rbox 10 | qhull TO "x)

»TPn - turn on tracing when point n added to hull

Option 'TPn' turns on tracing when point n is added to the hull. It also traces partitions of point n. This option reduces the output size when tracing. It is the normal method to determine the cause of a Qhull error. All Qhull errors report the last point added.

Use option 'TP-1' to turn on tracing after qh_buildhull and qh_postmerge.

Use options 'TPn TVn' to trace the addition of point n to the convex hull and stop when done.

If used with option 'TWn', 'TPn' turns off tracing after adding point n to the hull. Use options 'TPn TWn' to trace the addition of point n to the convex hull, partitions of point n, and wide merges.

»TRn - rerun qhull n times for QJn statitics

Option 'TRn' reruns Qhull n times. It is used with 'QJn' to determine the probability that a given joggle will fail. The summary ('s') lists the failure rate and the precision errors that occurred. Option 'Ts' will report statistics for all of the runs. Trace and output options only apply to the last run. An event trace, 'T-1' reports events for all runs.

Tracing applies to the last run of Qhull. If an error is reported, the options list the run number as "_run". To trace this run, set 'TRn' to the same value.

»Ts - print statistics

Option 'Ts' collects statistics and prints them to stderr. For Delaunay triangulations, the angle statistics are restricted to the lower or upper envelope.

»Tv - verify result: structure, convexity, and point inclusion

Option 'Tv' checks the topological structure, flipped facets, and point inclusion. Facet convexity is tested if not merging or if 2-D/3-D and a merged facet. If precision problems occur, flipped facet tests and facet convexity tests occur whether or not 'Tv' is selected. Option 'Tv' does not check point inclusion if forcing output with 'Po', or if 'Q5' is set.

The convex hull of a set of points is the smallest polytope that includes the points. Option 'Tv' tests point inclusion. Qhull verifies that all points are below all outer planes (facet->maxoutside). Point inclusion is exhaustive if merging or if the facet-point product is small enough; otherwise Qhull verifies each point with a directed search (qh_findbest). To force an exhaustive test when using option 'C-0' (default), use 'C-1e-30' instead.

Point inclusion testing occurs after producing output. It prints a message to stderr unless option 'Pp' is used. This allows the user to interrupt Qhull without changing the output.

With 'qvoronoi Fi', option 'Tv' collects statistics that verify all Voronoi vertices lie on the separating hyperplane, and all separating hyperplanes are perpendicular bisectors.

»TV-n - stop qhull before adding point n

Qhull adds one point at a time to the convex hull. See how Qhull adds a point. Option 'TV-n' stops Qhull just before adding a new point. Output shows the hull at this time.

»TVn - stop qhull after adding point n

Option 'TVn' stops Qhull after it has added point n and before it deletes the visible facets. If facet merges lead to vertex merges, 'TVn' stops after vertex merges and deleting visible facets. Output shows the hull at this time. See option 'TAn' to stop after adding n vertices.

»TWn - trace merge facets when width > n

Along with TMn, this option allows the user to determine the cause of a wide merge.

»Tz - send all output to stdout

Redirect stderr to stdout. See option 'Tf' for flushing writes.


Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)


The Geometry Center Home Page

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

qhull-2020.2/html/qh-quick.htm0000644060175106010010000004477313661634406014416 0ustar bbarber Qhull quick reference

Up: Home page for Qhull (local)
Up: Qhull manual
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
To: Qhull code
To: Qhull files (local)
To: GeomGlobalIoMemMergePolyQhullSetStatUser


[cone] Qhull quick reference

This section lists all programs and options in Qhull.

Copyright © 1995-2020 C.B. Barber

 


Qhull programs

» ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)

qconvex -- convex hull
synopsis • input • outputs • controls • graphics • notes • conventions • options
 
qdelaunay -- Delaunay triangulation
synopsis • input • outputs • controls • graphics • notes • conventions • options
 
qdelaunay Qu -- furthest-site Delaunay triangulation
synopsis • input • outputs • controls • graphics • notes • conventions • options
 
qhalf -- halfspace intersection about a point
synopsis • input • outputs • controls • graphics • notes • conventions • options
 
qvoronoi -- Voronoi diagram
synopsis • input • outputs • controls • graphics • notes • conventions • options
 
qvoronoi Qu -- furthest-site Voronoi diagram
synopsis • input • outputs • controls • graphics • notes • conventions • options
 
rbox -- generate point distributions for qhull
synopsis • outputs • examples • notes • options
 
qhull -- convex hull and related structures
synopsis • input • outputs • controls • options
 
Qhull options

» ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)

'd' delaunay 'f' facet-dump 'G' Geomview 'H' Halfspace
'i' incidences 'm' mathematica 'n' normals 'o' OFF-format
'p' points 's' summary 'v' voronoi
 
'Fa' Farea 'FA' FArea-total 'Fc' Fcoplanars 'FC' FCentrums
'Fd' Fd-cdd-in 'FD' FD-cdd-out 'FF' FFacets-xridge 'Fi' Finner
'Fi' Finner-bounded 'FI' FIDs 'Fm' Fmerges 'FM' FMaple
'Fn' Fneighbors 'FN' FNeigh-vertex 'Fo' Fouter 'Fo' Fouter-unbounded
'FO' FOptions 'Fp' Fpoint-intersect 'FP' FPoint-near 'FQ' FQhull
'Fs' Fsummary 'FS' FSize 'Ft' Ftriangles 'Fv' Fvertices
'Fv' Fvoronoi 'FV' FVertex-ave 'Fx' Fxtremes
 
'Ga' Gall-points 'Gc' Gcentrums 'GDn' GDrop-dim 'Gh' Ghyperplanes
'Gi' Ginner 'Gn' Gno-planes 'Go' Gouter 'Gp' Gpoints
'Gr' Gridges 'Gt' Gtransparent 'Gv' Gvertices
 
'PAn' PArea-keep 'Pdk:n' Pdrop-low 'PDk:n' Pdrop-high 'PFn' PFacet-area-keep
'Pg' Pgood 'PG' PGood-neighbors 'PMn' PMerge-keep 'Po' Poutput-forced
'Po' Poutput-error 'Pp' Pprecision-not
 
'Qa' Qallow-short 'Qbk:n' Qbound-low 'QBk:n' QBound-high 'QbB' QbB-scale-box
'Qbb' Qbb-scale-last 'Qbk:0Bk:0' Qbound-drop 'Qc' Qcoplanar 'Qi' Qinterior
'QJn' QJoggle 'QRn' QRotate 'Qs' Qsearch-all 'Qt' Qtriangulate
'Qu' QupperDelaunay 'Qw' Qwarn-allow 'Qx' Qxact-merge 'Qz' Qzinfinite
 
'Qf' Qfurthest 'Qg' Qgood-only 'QGn' QGood-point 'Qm' Qmax-outside
'Qr' Qrandom 'Qv' Qvertex-neighbors 'QVn' QVertex-good
'Q0' Q0-no-premerge 'Q1' Q1-angle-merge 'Q2' Q2-no-independent 'Q3' Q3-no-redundant
'Q4' Q4-no-old 'Q5' Q5-no-check-out 'Q6' Q6-no-concave 'Q7' Q7-depth-first
'Q8' Q8-no-near-interior 'Q9' Q9-pick-furthest 'Q10' Q10-no-narrow 'Q11' Q11-trinormals
'Q12' Q12-allow-wide 'Q14' Q14-merge-pinched 'Q15' Q15-duplicate-ridges
 
'TFn' TFacet-log 'TI file' TInput-file 'TO file' TOutput-file 'Ts' Tstatistics
'Tv' Tverify 'Tz' Tz-stdout
 
'T4' T4-trace 'Ta' Tannotate 'TAn' TAdd-stop 'Tc' Tcheck-often
'TCn' TCone-stop 'Tf' Tflush 'TMn' TMerge-trace 'TPn' TPoint-trace
'TRn' TRerun 'TV-n' TVertex-stop-before 'TVn' TVertex-stop-after 'TWn' TWide-trace
 
'A-n' Angle-max-pre 'An' Angle-max-post 'C-0' Centrum-roundoff 'C-n' Centrum-size-pre
'Cn' Centrum-size-post 'En' Error-round 'Rn' Random-dist 'Un' Ucoplanar-max
'Vn' Visible-min 'Wn' Wide-outside


Up: Home page for Qhull (local)
Up: Qhull manual
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
To: Qhull code
To: Qhull files (local)
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

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

qhull-2020.2/html/qhalf.htm0000644060175106010010000007153013716271251013752 0ustar bbarber qhalf -- halfspace intersection about a point

Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
To: synopsis • input • outputs • controls • graphics • notes • conventions • options


[halfspace]qhalf -- halfspace intersection about a point

The intersection of a set of halfspaces is a polytope. The polytope may be unbounded. See Preparata & Shamos ['85] for a discussion. In low dimensions, halfspace intersection may be used for linear programming.

Example: rbox c | qconvex FV n | qhalf Fp

Print the intersection of the facets of a cube. rbox c generates the vertices of a cube. qconvex FV returns a feasible point for halfspace intersection. This feasible or interior point, qconvex FV, is the average of the cube's vertices (i.e., the origin). qconvex n returns the halfspaces that define the cube. qhalf Fp computes the intersection of the halfspaces about the feasible point. The intersection is the vertices of the original cube.

Example: rbox c | qconvex FQ n | qhalf H0.1,0.1,0.1

Compute the intersection of the facets of a cube and print a summary ('s'). Option 'FQ' prints the qconvex command as an input comment for the summary. 'qhalf Hn,n,n' specifies the feasible point as [0.1, 0.1, 0.1]. 'qhalf H0' would specify the feasible point as the origin.

Example: rbox c d G0.55 | qconvex FQ FV n | qhalf Fp

Print the intersection of the facets of a cube and a diamond. There are 24 facets and 14 intersection points. Four facets define each diamond vertex. Six facets define each cube vertex.

Example: rbox c d G0.55 | qconvex FQ FV n | qhalf Fp Qt

Same as above except triangulate before computing the intersection points. Three facets define each intersection point. There are two duplicates of the diamond and four duplicates of the cube.

Example: rbox 10 s t10 | qconvex FQ FV n | qhalf Fp Fn

Print the intersection of the facets of the convex hull of 10 cospherical points. Include the intersection points and the neighboring intersections. As in the previous examples, the intersection points are nearly the same as the original input points.

In Qhull, a halfspace is defined by the points on or below a hyperplane. The distance of each point to the hyperplane is less than or equal to zero.

Qhull computes a halfspace intersection by the geometric duality between points and halfspaces. See halfspace examples, qhalf notes, and option 'p' of qhalf outputs.

Qhalf's outputs are the intersection points (Fp) and the neighboring intersection points (Fn). For random inputs, halfspace intersections are usually defined by more than d halfspaces. See the sphere example.

The identity pipeline for Qhull starts with points, produces the halfspaces for their convex hull, and intersects these halfspaces, returning the original points. For example, 'rbox c' is the unit cube.

	rbox c | qconvex FV n | qhalf Fp
	3
	8
	  -0.5    0.5    0.5
	   0.5    0.5    0.5
	  -0.5    0.5   -0.5
	   0.5    0.5   -0.5
	   0.5   -0.5    0.5
	  -0.5   -0.5    0.5
	   0.5   -0.5   -0.5
	  -0.5   -0.5   -0.5

You can try triangulated output ('Qt') and joggled input ('QJ'). It demonstrates that triangulated output is more accurate than joggled input.

If you use 'Qt' (triangulated output), all halfspace intersections are simplicial (e.g., three halfspaces per intersection in 3-d). In 3-d, if more than three halfspaces intersect at the same point, triangulated output will produce duplicate intersections, one for each additional halfspace. See the third example, or add 'Qt' to the sphere example.

If you use 'QJ' (joggled input), all halfspace intersections are simplicial. This may lead to nearly identical intersections. For example, either replace 'Qt' with 'QJ' above, or add 'QJ' to the sphere example. See Merged facets or joggled input.

The 'qhalf' program is equivalent to 'qhull H'. It disables the following Qhull options: d n v Qbb QbB Qf Qg Qm Qr Qv Qx Qz TR E V Fa FA FC FD FS Ft FV Gt Q0,etc.

Copyright © 1995-2020 C.B. Barber


»qhalf synopsis

qhalf -- halfspace intersection about a point.
    input (stdin): [dimension, 1, interior point]
                       dimension+1, number of halfspaces, coefficients+offset
    comments start with a non-numeric character

options:
    Hn,n - specify coordinates of interior point
    Qt   - triangulated output
    QJ   - joggled input instead of merged facets
    Tv   - verify result: structure, convexity, and redundancy
    .    - concise list of all options
    -    - one-line description of each option
    -?   - this message
    -V   - version

output options (subset):
    s    - summary of results (default)
    Fp   - intersection coordinates
    Fv   - non-redundant halfspaces incident to each intersection
    Fx   - non-redundant halfspaces
    G    - Geomview output (dual convex hull)
    m    - Mathematica output (dual convex hull)
    o    - OFF file format (dual convex hull)
    QVn  - print intersections for halfspace n, -n if not
    TI file - input file, may be enclosed in single quotes
    TO file - output file, may be enclosed in single quotes

examples:
    rbox d | qconvex FQ n | qhalf s H0,0,0 Fp
    rbox c | qconvex FQ FV n | qhalf s i
    rbox c | qconvex FQ FV n | qhalf s o

»qhalf input

The input data on stdin consists of:

  • [optional] feasible point
    • dimension
    • 1
    • coordinates of feasible point
  • dimension + 1
  • number of halfspaces
  • halfspace coefficients followed by offset

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

Qhull needs a feasible point to compute the halfspace intersection. A feasible point is clearly inside all of the halfspaces. A point is inside a halfspace if its distance to the corresponding hyperplane is negative.

The feasible point may be listed at the beginning of the input (as shown above). If not, option 'Hn,n' defines the feasible point as [n,n,0,...] where 0 is the default coordinate (e.g., 'H0' is the origin). Use linear programming if you do not know the feasible point (see halfspace notes),

The input to qhalf is a set of halfspaces that are defined by their hyperplanes. Each halfspace is defined by d coefficients followed by a signed offset. This defines a linear inequality. The coefficients define a vector that is normal to the halfspace. The vector may have any length. If it has length one, the offset is the distance from the origin to the halfspace's boundary. Points in the halfspace have a negative distance to the hyperplane. The distance from the feasible point to each halfspace is likewise negative.

The halfspace format is the same as Qhull's output options 'n', 'Fo', and 'Fi'. Use option 'Fd' to use cdd format for the halfspaces.

For example, here is the input for computing the intersection of halfplanes that form a cube.

rbox c | qconvex FQ FV n TO data

RBOX c | QCONVEX FQ FV n
3 1
     0      0      0
4
6
     0      0     -1   -0.5
     0     -1      0   -0.5
     1      0      0   -0.5
    -1      0      0   -0.5
     0      1      0   -0.5
     0      0      1   -0.5

qhalf s Fp < data


Halfspace intersection by the convex hull of 6 points in 3-d:

  Number of halfspaces: 6
  Number of non-redundant halfspaces: 6
  Number of intersection points: 8

Statistics for: RBOX c | QCONVEX FQ FV n | QHALF s Fp

  Number of points processed: 6
  Number of hyperplanes created: 11
  Number of distance tests for qhull: 11
  Number of merged facets: 1
  Number of distance tests for merging: 45
  CPU seconds to compute hull (after input):  0

3
3
8
  -0.5    0.5    0.5
   0.5    0.5    0.5
  -0.5    0.5   -0.5
   0.5    0.5   -0.5
   0.5   -0.5    0.5
  -0.5   -0.5    0.5
  -0.5   -0.5   -0.5
   0.5   -0.5   -0.5

»qhalf outputs

The following options control the output for halfspace intersection.

 
Intersections
FN
list intersection points for each halfspace. The first line is the number of halfspaces. Each remaining line starts with the number of intersection points. Redundant halfspaces have 0 intersection points. For the cube example, each halfspace has four intersection points.
Fn
list neighboring intersections for each intersection point. The first line is the number of intersection points. Each following line starts with the number of neighboring intersections. For the cube example, each intersection point has three neighboring intersections.

In 3-d, a non-simplicial intersection has more than three neighboring intersections. For random data (e.g., the sphere example), non-simplicial intersections are the norm. Option 'Qt' produces three neighboring intersections per intersection by duplicating the intersection points. Option QJ' produces three neighboring intersections per intersection by joggling the hyperplanes and hence their intersections.

Fp
print intersection coordinates. The first line is the dimension and the second line is the number of intersection points. The following lines are the coordinates of each intersection point. The "infinity" point, [-10.101,-10.101,...] (qh_INFINITE), indicates an unbounded intersection.
FI
list intersection IDs. The first line is the number of intersections. The IDs follow, one per line.
 
 
Halfspaces
Fx
list non-redundant halfspaces. The first line is the number of non-redundant halfspaces. The other lines list one halfspace per line. A halfspace is non-redundant if it defines a facet of the intersection. Redundant halfspaces are ignored. For the cube example, none of the halfspaces are redundant.
Fv
list non-redundant halfspaces incident to each intersection point. The first line is the number of non-redundant halfspaces. Each remaining line starts with the number of non-redundant halfspaces incident to that point. For the cube example, each intersection point is incident to three halfspaces.
i
list non-redundant halfspaces incident to each intersection point. The first line is the number of intersection points. Each remaining line lists the incident, non-redundant halfspaces for that intersection point. For the cube example, each intersection point is incident to three halfspaces.
Fc
list coplanar halfspaces for each intersection point. The first line is the number of intersection points. Each remaining line starts with the number of coplanar halfspaces. A coplanar halfspace is listed for one intersection point even though it is coplanar to multiple intersection points.
Qi Fc
list redundant halfspaces for each intersection point. The first line is the number of intersection points. Each remaining line starts with the number of redundant halfspaces. Use options 'Qc Qi Fc' to list coplanar and redundant halfspaces.
 
 
General
s
print summary for the halfspace intersection. Use 'Fs' if you need numeric data.
o
print vertices and facets of the dual convex hull. The first line is the dimension. The second line is the number of vertices, facets, and ridges. The vertex coordinates are next, followed by the facets, one per line.
p
print vertex coordinates of the dual convex hull. Each vertex corresponds to a non-redundant halfspace. Its coordinates are the negative of the hyperplane's coefficients divided by the offset plus the inner product of the coefficients and the feasible point (-c/(b+a.p). Options 'p Qc' includes coplanar halfspaces. Options 'p Qi' includes redundant halfspaces.
m
Mathematica output for the dual convex hull in 2-d or 3-d.
FM
Maple output for the dual convex hull in 2-d or 3-d.
G
Geomview output for the dual convex hull in 2-d, 3-d, or 4-d.

»qhalf controls

These options provide additional control:

Qt
triangulated output. If a 3-d intersection is defined by more than three hyperplanes, Qhull produces duplicate intersections -- one for each extra hyperplane.
QRn
randomly rotate the input with a random seed of n. If n=0, the seed is the time. If n=-1, use time for the random seed, but do not rotate the input.
QJ
joggle the input instead of merging facets. In 3-d, this guarantees that each intersection is defined by three hyperplanes.
f
facet dump. Print the data structure for each intersection (i.e., facet)
TFn
report summary after constructing n intersections
QVn
select intersection points for halfspace n (marked 'good')
QGn
select intersection points that are visible to halfspace n (marked 'good'). Use -n for the remainder.
Qbk:0Bk:0
remove the k-th coordinate from the input. This computes the halfspace intersection in one lower dimension.
Tv
verify result
TI file
input data from file. The filename may not use spaces or quotes.
TO file
output results to file. Use single quotes if the filename contains spaces (e.g., TO 'file with spaces.txt'
Qs
search all points for the initial simplex. If Qhull can not construct an initial simplex, it reports a descriptive message. Usually, the point set is degenerate and one or more dimensions should be removed ('Qbk:0Bk:0'). If not, use option 'Qs'. It performs an exhaustive search for the best initial simplex. This is expensive is high dimensions.

»qhalf graphics

To view the results with Geomview, compute the convex hull of the intersection points ('qhull FQ H0 Fp | qhull G'). See Halfspace examples.

»qhalf notes

See halfspace intersection for precision issues related to qhalf.

If you do not know a feasible point for the halfspaces, use linear programming to find one. Assume, n halfspaces defined by: aj*x1+bj*x2+cj*x3+dj<=0, j=1..n. Perform the following linear program:

max(x5) aj*x1+bj*x2+cj*x3+dj*x4+x5<=0, j=1..n

Then, if [x1,x2,x3,x4,x5] is an optimal solution with x4>0 and x5>0 we get:

aj*(x1/x4)+bj*(x2/x4)+cj*(x3/x4)+dj<=(-x5/x4) j=1..n and (-x5/x4)<0,

and conclude that the point [x1/x4,x2/x4,x3/x4] is inside all the halfspaces. Since x5 is optimal, this feasible point is "clearly inside" the halfspaces (good for precision errors).

After finding a feasible point, the rest of the intersection algorithm is from Preparata & Shamos ['85, p. 316, "A simple case ..."]. Translate the halfspaces so that the feasible point is the origin. Calculate the dual polytope. The dual polytope is the convex hull of the vertices dual to the original faces in regard to the unit sphere (i.e., halfspaces at distance d from the origin are dual to vertices at distance 1/d). Then calculate the resulting polytope, which is the dual of the dual polytope, and translate the origin back to the feasible point [S. Spitz, S. Teller, D. Strawn].

»qhalf conventions

The following terminology is used for halfspace intersection in Qhull. This is the hardest structure to understand. The underlying structure is a convex hull with one vertex per non-redundant halfspace. See convex hull conventions and Qhull's data structures.

  • feasible or interior point - a point in the intersection of the halfspaces. Qhull needs a feasible point to compute the intersection. See halfspace input.
  • halfspace - d coordinates for the normal and a signed offset. The distance to the feasible point is negative.
  • non-redundant halfspace - a halfspace that defines an output facet
  • vertex - a dual vertex in the convex hull corresponding to a non-redundant halfspace
  • coplanar point - the dual point corresponding to a similar halfspace
  • interior point - the dual point corresponding to a redundant halfspace
  • intersection point- the intersection of d or more non-redundant halfspaces
  • facet - a dual facet in the convex hull corresponding to an intersection point
  • non-simplicial facet - more than d halfspaces intersect at a point
  • good facet - an intersection point that satisfies restriction 'QVn', etc.

»qhalf options

qhalf -- compute the intersection of halfspaces about a point
    http://www.qhull.org

input (stdin):
    optional interior point: dimension, 1, coordinates
    first lines: dimension+1 and number of halfspaces
    other lines: halfspace coefficients followed by offset
    comments:    start with a non-numeric character

options:
    Hn,n - specify coordinates of interior point
    Qc   - keep coplanar halfspaces
    Qi   - keep other redundant halfspaces
    QJ   - joggled input instead of merged facets
    Qt   - triangulated output

Qhull control options:
    Qa   - allow input with fewer or more points than coordinates
    Qbk:0Bk:0 - remove k-th coordinate from input
    QJn  - randomly joggle input in range [-n,n]
    QRn  - random rotation (n=seed, n=0 time, n=-1 time/no rotate)
    Qs   - search all halfspaces for the initial simplex

Qhull extra options:
    QGn  - print intersection if visible to halfspace n, -n for not
    QVn  - print intersections for halfspace n, -n if not
    Qw   - allow option warnings
    Q12  - allow wide facets and wide dupridge
    Q14  - merge pinched vertices that create a dupridge

T options:
    TFn  - report summary when n or more facets created
    TI file - input file, may be enclosed in single quotes
    TO file - output file, may be enclosed in single quotes
    Ts   - statistics
    Tv   - verify result: structure, convexity, and in-circle test
    Tz   - send all output to stdout

Trace options:
    T4   - trace at level n, 4=all, 5=mem/gauss, -1= events
    Ta   - annotate output with message codes
    TAn  - stop qhull after adding n vertices
     TCn - stop qhull after building cone for point n
     TVn - stop qhull after adding point n, -n for before
    Tc   - check frequently during execution
    Tf   - flush each qh_fprintf for debugging segfaults
    TPn - turn on tracing when point n added to hull
     TMn  - turn on tracing at merge n
     TWn - trace merge facets when width > n

Precision options:
    Cn   - radius of centrum (roundoff added).  Merge facets if non-convex
     An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex
           C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge
    Rn   - randomly perturb computations by a factor of [1-n,1+n]
    Un   - max distance below plane for a new, coplanar halfspace
    Wn   - min facet width for outside halfspace (before roundoff)

Output formats (may be combined; if none, produces a summary to stdout):
    f    - facet dump
    G    - Geomview output (dual convex hull)
    i    - non-redundant halfspaces incident to each intersection
    m    - Mathematica output (dual convex hull)
    o    - OFF format (dual convex hull: dimension, points, and facets)
    p    - vertex coordinates of dual convex hull (coplanars if 'Qc' or 'Qi')
    s    - summary (stderr)

More formats:
    Fc   - count plus redundant halfspaces for each intersection
         -   Qc (default) for coplanar and Qi for other redundant
    Fd   - use cdd format for input (homogeneous with offset first)
    FF   - facet dump without ridges
    FI   - ID of each intersection
    Fm   - merge count for each intersection (511 max)
    FM   - Maple output (dual 2-d or 3-d convex hull)
    Fn   - count plus neighboring intersections for each intersection
    FN   - count plus intersections for each halfspace
    FO   - options and precision constants
    Fp   - dim, count, and intersection coordinates
    FP   - nearest halfspace and distance for each redundant halfspace
    FQ   - command used for qhalf
    Fs   - summary: #int (8), dim, #halfspaces, #non-redundant, #intersections
                      output: #non-redundant, #intersections, #coplanar
                                  halfspaces, #non-simplicial intersections
                    #real (2), max outer plane, min vertex
    Fv   - count plus non-redundant halfspaces for each intersection
    Fx   - non-redundant halfspaces

Geomview output (2-d, 3-d and 4-d; dual convex hull)
    Ga   - all points (i.e., transformed halfspaces) as dots
     Gp  -  coplanar points and vertices as radii
     Gv  -  vertices (i.e., non-redundant halfspaces) as spheres
    Gc   - centrums
    GDn  - drop dimension n in 3-d and 4-d output
    Gh   - hyperplane intersections
    Gi   - inner planes (i.e., halfspace intersections) only
     Gn  -  no planes
     Go  -  outer planes only
    Gr   - ridges

Print options:
    PAn  - keep n largest facets (i.e., intersections) by area
    Pdk:n- drop facet if normal[k] <= n (default 0.0)
    PDk:n- drop facet if normal[k] >= n
    PFn  - keep facets whose area is at least n
    Pg   - print good facets (needs 'QGn' or 'QVn')
    PG   - print neighbors of good facets
    PMn  - keep n facets with most merges
    Po   - force output.  If error, output neighborhood of facet
    Pp   - do not report precision problems

    .    - list of all options
    -    - one line descriptions of all options
    -?   - help with examples
    -V   - version

Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
To: synopsis • input • outputs • controls • graphics • notes • conventions • options


The Geometry Center Home Page

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

qhull-2020.2/html/qhull-cpp.xml0000644060175106010010000002726213661634406014603 0ustar bbarber

Qhull C++ -- C++ interface to Qhull

Copyright (c) 2009-2020, C.B. Barber

This draft document records some of the design decisions for Qhull C++. Convert it to HTML by road-faq.xsl from road-faq. Please send comments and suggestions to bradb@shore.net

Help
.
Qhull's collection APIs are modeled on Qt's collection API (QList, QVector, QHash) w/o QT_STRICT_ITERATORS. They support STL and Qt programming.

Some of Qhull's collection classes derive from STL classes. If so, please avoid additional STL functions and operators added by inheritance. These collection classes may be rewritten to derive from Qt classes instead. See Road's .

Qhull's collection API (where applicable). For documentation, see Qt's QList, QMap, QListIterator, QMapIterator, QMutableListIterator, and QMutableMapIterator
  • STL types [list, qlinkedlist, qlist, qvector, vector] -- const_iterator, iterator
  • STL types describing iterators [list, qlinkedlist, qlist, qvector, vector] -- const_pointer, const_reference, difference_type, pointer, reference, size_type, value_type. Pointer and reference types not defined if unavailable (not needed for <algorithm>)
  • const_iterator, iterator types -- difference_type, iterator_category, pointer, reference, value_type
  • Qt types [qlinkedlist, qlist, qvector] -- ConstIterator, Iterator, QhullclassIterator, MutableQhullclassIterator. Qt's foreach requires const_iterator.
  • Types for sets/maps [hash_map, QHash] -- key_compare, key_type, mapped_type
  • Constructor -- default constructor, copy constructor, assignment operator, destructor
  • Conversion -- to/from/as corresponding C, STL, and Qt constructs. Include toQList and toStdVector (may be filtered, e.g., QhullFacetSet). Do not define fromStdList and fromQList if container is not reference counted (i.e., acts like a value)
  • Get/set -- configuration options for class
  • STL-style iterator - begin, constBegin, constEnd, end, key, value, =, *, [], ->, ++, --, +, -, ==, !=, <, <=, >, >=, const_iterator(iterator), iterator COMPARE const_iterator. An iterator is an abstraction of a pointer. It is not aware of its container.
  • Java-style iterator [qiterator.h] - countRemaining, findNext, findPrevious, hasNext, hasPrevious, next, peekNext, peekPrevious, previous, toBack, toFront, = Coordinates
  • Mutable Java-style iterator adds - insert, remove, setValue, value
  • Element access -- back, first, front, last
  • Element access w/ index -- [], at (const& only), constData, data, mid, value
  • Read-only - (int)count, empty, isEmpty, (size_t)size. Count() and size() may be filtered. If so, they may be zero when !empty().
  • Read-only for sets/maps - capacity, key, keys, reserve, resize, values
  • Operator - ==, !=, +, +=, <<
  • Read-write -- append, clear, erase, insert, move, prepend, pop_back, pop_front, push_back, push_front, removeAll, removeAt, removeFirst, removeLast, replace, swap, takeAt, takeFirst, takeLast
  • Read-write for sets/maps -- insertMulti, squeeze, take, unite
  • Search -- contains(const T &), count(const T &), indexOf, lastIndexOf
  • Search for sets/maps -- constFind, lowerBound, upperBound
  • Stream I/O -- stream <<
STL list and vector -- For unfiltered access to each element.
  • Apache: Creating your own containers -- requirements for STL containers. Iterators should define the types from 'iterator_traits'.
  • STL types -- allocator_type, const_iterator, const_pointer, const_reference, const_reverse_iterator, difference_type, iterator, iterator_category, pointer, reference, reverse_iterator, size_type, value_type
  • STL constructors -- MyType(), MyType(count), MyType(count, value), MyType(first, last), MyType(MyType&),
  • STL getter/setters -- at (random_access only), back, begin, capacity, end, front, rbegin, rend, size, max_size
  • STL predicates -- empty
  • STL iterator types -- const_pointer, const_reference, difference_type, iterator_category, pointer, reference, value_type
  • STL iterator operators -- *, -<, ++, --, +=, -=, +, -, [], ==, !=, <, >, >=, <=
  • STL operators -- =, [] (random_access only), ==, !=, <, >, <=, >=
  • STL modifiers -- assign, clear, erase, insert, pop_back, push_back, reserve, resize, swap
Qt Qlist -- For unfiltered access to each element
  • Additional Qt types -- ConstIterator, Iterator, QListIterator, QMutableListIterator
  • Additional Qt get/set -- constBegin, constEnd, count, first, last, value (random_access only)
  • Additional Qt predicates -- isEmpty
  • Additional Qt -- mid (random_access only)
  • Additional Qt search -- contains, count(T&), indexOf (random_access only), lastIndeOf (random_access only)
  • Additional Qt modifiers -- append, insert(index,value) (random_access only), move (random_access only), pop_front, prepend, push_front, removeAll, removeAt (random_access only), removeFirst, removeLast, replace, swap by index, takeAt, takeFirst, takeLast
  • Additional Qt operators -- +, <<, +=, stream << and >>
  • Unsupported types by Qt -- allocator_type, const_reverse_iterator, reverse_iterator
  • Unsupported accessors by Qt -- max_size, rbegin, rend
  • Unsupported constructors by Qt -- multi-value constructors
  • unsupported modifiers by Qt -- assign, muli-value inserts, STL's swaps
STL map and Qt QMap. These use nearly the same API as list and vector classes. They add the following.
  • STL types -- key_compare, key_type, mapped_type
  • STL search -- equal_range, find, lower_bound, upper_bound
  • Qt removes -- equal_range, key_compare
  • Qt renames -- lowerBound, upperBound
  • Qt adds -- constFind, insertMulti, key, keys, take, uniqueKeys, unite, values
  • Not applicable to map and QMap -- at, back, pop_back, pop_front, push_back, push_front, swap
  • Not applicable to QMap -- append, first, last, lastIndexOf, mid, move, prepend, removeAll, removeAt, removeFirst, removeLast, replace, squeeze, takeAt, takeFirst, takeLast
  • Not applicable to map -- assign
Qt QHash. STL extensions provide similar classes, e.g., Microsoft's stdext::hash_set. THey are nearly the same as QMap
  • Not applicable to Qhash -- lowerBound, unite, upperBound,
  • Qt adds -- squeeze
  • check... -- Throw error on failure
  • try... -- Return false on failure. Do not throw errors.
  • ...Temporarily -- lifetime depends on source. e.g., toByteArrayTemporarily
  • ...p -- indicates pointer-to.
  • end... -- points to one beyond the last available
  • private functions -- No syntactic indication. They may become public later on.
  • Error messages -- Preceed error messages with the name of the class throwing the error (e.g. "ClassName: ..."). If this is an internal error, use "ClassName inconsistent: ..."
  • parameter order -- qhRunId, dimension, coordinates, count.
  • toClass -- Convert into a Class object (makes a deep copy)
  • qRunId -- Requires Qh installed. Some routines allow 0 for limited info (e.g., operator<<)
  • Disable methods in derived classes -- If the default constructor, copy constructor, or copy assignment is disabled, it should be also disabled in derived classes (better error messages).
  • Constructor order -- default constructor, other constructors, copy constructor, copy assignment, destructor
qhull-2020.2/html/qhull.htm0000644060175106010010000004550213716271251014004 0ustar bbarber qhull -- convex hull and related structures

Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
To: synopsis • input • outputs • controls • options


[cone]qhull -- convex hull and related structures

The convex hull of a set of points is the smallest convex set containing the points. The Delaunay triangulation and furthest-site Delaunay triangulation are equivalent to a convex hull in one higher dimension. Halfspace intersection about a point is equivalent to a convex hull by polar duality.

The qhull program provides options to build these structures and to experiment with the process. Use the qconvex, qdelaunay, qhalf, and qvoronoi programs to build specific structures. You may use qhull instead. It takes the same options and uses the same code.

Example: rbox 1000 D3 | qhull C-1e-4 FO Ts
Compute the 3-d convex hull of 1000 random points. Centrums must be 10^-4 below neighboring hyperplanes. Print the options and precision constants. When done, print statistics. These options may be used with any of the Qhull programs.
 
Example: rbox 1000 D3 | qhull d Qbb R1e-4 Q0
Compute the 3-d Delaunay triangulation of 1000 random points. Randomly perturb all calculations by [0.9999,1.0001]. Do not correct precision problems. This leads to serious precision errors.

Use the following equivalences when calling qhull:

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

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

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

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

Copyright © 1995-2020 C.B. Barber


»qhull synopsis

qhull -- compute convex hulls and related structures.
    input (stdin): dimension, number of points, point coordinates
    comments start with a non-numeric character
    halfspace: use dim+1 and put offsets after coefficients

options:
    d    - Delaunay triangulation by lifting points to a paraboloid
    d Qu - furthest-site Delaunay triangulation (upper convex hull)
    v    - Voronoi diagram as the dual of the Delaunay triangulation
    v Qu - furthest-site Voronoi diagram
    H1,1 - Halfspace intersection about [1,1,0,...] via polar duality
    Qt   - triangulated output
    QJ   - joggled input instead of merged facets
    Tv   - verify result: structure, convexity, and point inclusion
    .    - concise list of all options
    -    - one-line description of each option
    -?   - this message
    -V   - version

Output options (subset):
    s    - summary of results (default)
    i    - vertices incident to each facet
    n    - normals with offsets
    p    - vertex coordinates (if 'Qc', includes coplanar points)
           if 'v', Voronoi vertices
    FA   - report total area and volume
    Fp   - halfspace intersections
    FS   - total area and volume
    Fx   - extreme points (convex hull vertices)
    G    - Geomview output (2-d, 3-d and 4-d)
    m    - Mathematica output (2-d and 3-d)
    o    - OFF format (if 'v', outputs Voronoi regions)
    QVn  - print facets that include point n, -n if not
    TI file - input file, may be enclosed in single quotes
    TO file - output file, may be enclosed in single quotes

examples:
    rbox D4 | qhull Tv                        rbox 1000 s | qhull Tv s FA
    rbox 10 D2 | qhull d QJ s i TO result     rbox 10 D2 | qhull v Qbb Qt p
    rbox 10 D2 | qhull d Qu QJ m              rbox 10 D2 | qhull v Qu QJ o
    rbox c d D2 | qhull Qc s f Fx | more      rbox c | qhull FV n | qhull H Fp
    rbox d D12 | qhull QR0 FA                 rbox c D7 | qhull FA TF1000
    rbox y 1000 W0 | qhull Qc                 rbox c | qhull n

»qhull input

The input data on stdin consists of:

  • dimension
  • number of points
  • point coordinates

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

Comments start with a non-numeric character. Error reporting is simpler if there is one point per line. Dimension and number of points may be reversed. For halfspace intersection, an interior point may be prepended (see qhalf input).

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

rbox c > data

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

qhull s n < data


Convex hull of 8 points in 3-d:

  Number of vertices: 8
  Number of facets: 6
  Number of non-simplicial facets: 6

Statistics for: RBOX c | QHULL s n

  Number of points processed: 8
  Number of hyperplanes created: 11
  Number of distance tests for qhull: 35
  Number of merged facets: 6
  Number of distance tests for merging: 84
  CPU seconds to compute hull (after input): 0.081

4
6
     0      0     -1   -0.5
     0     -1      0   -0.5
     1      0      0   -0.5
    -1      0      0   -0.5
     0      1      0   -0.5
     0      0      1   -0.5

»qhull outputs

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

 
General
qhull
compute the convex hull of the input points. See qconvex.
qhull d Qbb
compute the Delaunay triangulation by lifting the points to a paraboloid. Use option 'Qbb' to scale the paraboloid and improve numeric precision. See qdelaunay.
qhull v Qbb
compute the Voronoi diagram by computing the Delaunay triangulation. Use option 'Qbb' to scale the paraboloid and improve numeric precision. See qvoronoi.
qhull H
compute the halfspace intersection about a point via polar duality. The point is below the hyperplanes that defines the halfspace. See qhalf.

For a full list of output options see

»qhull controls

For a full list of control options see

»qhull options

qhull -- compute convex hulls and related structures.
    http://www.qhull.org

input (stdin):
    first lines: dimension and number of points (or vice-versa).
    other lines: point coordinates, best if one point per line
    comments:    start with a non-numeric character
    halfspaces:  use dim plus one and put offset after coefficients.
                 May be preceded by a single interior point ('H').

options:
    d    - Delaunay triangulation by lifting points to a paraboloid
    d Qu - furthest-site Delaunay triangulation (upper convex hull)
    Hn,n,... - halfspace intersection about point [n,n,0,...]
    Qc   - keep coplanar points with nearest facet
    Qi   - keep interior points with nearest facet
    QJ   - joggled input instead of merged facets
    Qt   - triangulated output
    v    - Voronoi diagram (dual of the Delaunay triangulation)
    v Qu - furthest-site Voronoi diagram

Qhull control options:
    Qa   - allow input with fewer or more points than coordinates
    Qbk:n   - scale coord k so that low bound is n
      QBk:n - scale coord k so that upper bound is n (QBk is 0.5)
    QbB  - scale input to unit cube centered at the origin
    Qbb  - scale last coordinate to [0,m] for Delaunay triangulations
    Qbk:0Bk:0 - remove k-th coordinate from input
    QJn  - randomly joggle input in range [-n,n]
    QRn  - random rotation (n=seed, n=0 time, n=-1 time/no rotate)
    Qs   - search all points for the initial simplex
    Qu   - for 'd' or 'v', compute upper hull without point at-infinity
              returns furthest-site Delaunay triangulation
    QVn  - good facet if it includes point n, -n if not
    Qx   - exact pre-merges (skips coplanar and angle-coplanar facets)
    Qz   - add point-at-infinity to Delaunay triangulation

Qhull extra options:
    Qf   - partition point to furthest outside facet
    Qg   - only build good facets (needs 'QGn', 'QVn', or 'PdD')
    QGn  - good facet if visible from point n, -n for not visible
    Qm   - only process points that would increase max_outside
    Qr   - process random outside points instead of furthest ones
    Qv   - test vertex neighbors for convexity
    Qw   - allow option warnings
    Q0   - turn off default premerge with 'C-0'/'Qx'
    Q1   - merge by mergetype/angle instead of mergetype/distance
    Q2   - merge all coplanar facets instead of merging independent sets
    Q3   - do not merge redundant vertices
    Q4   - avoid old->new merges
    Q5   - do not correct outer planes at end of qhull
    Q6   - do not pre-merge concave or coplanar facets
    Q7   - depth-first processing instead of breadth-first
    Q8   - do not process near-inside points
    Q9   - process furthest of furthest points
    Q10  - no special processing for narrow distributions
    Q11  - copy normals and recompute centrums for tricoplanar facets
    Q12  - allow wide facets and wide dupridge
    Q14  - merge pinched vertices that create a dupridge
    Q15  - check for duplicate ridges with the same vertices

T options:
    TFn  - report summary when n or more facets created
    TI file - input file, may be enclosed in single quotes
    TO file - output file, may be enclosed in single quotes
    Ts   - statistics
    Tv   - verify result: structure, convexity, and point inclusion
    Tz   - send all output to stdout

Trace options:
    T4   - trace at level n, 4=all, 5=mem/gauss, -1= events
    Ta   - annotate output with message codes
    TAn  - stop qhull after adding n vertices
     TCn - stop qhull after building cone for point n
     TVn - stop qhull after adding point n, -n for before
    Tc   - check frequently during execution
    Tf   - flush each qh_fprintf for debugging segfaults
    TPn  - turn on tracing when point n added to hull
     TP-1  turn on tracing after qh_buildhull and qh_postmerge
     TMn - turn on tracing at merge n
     TWn - trace merge facets when width > n
    TRn  - rerun qhull n times for statistics to adjust 'QJn'

Precision options:
    Cn   - radius of centrum (roundoff added).  Merge facets if non-convex
     An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex
           C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge
    En   - max roundoff error for distance computation
    Rn   - randomly perturb computations by a factor of [1-n,1+n]
    Vn   - min distance above plane for a visible facet (default 3C-n or En)
    Un   - max distance below plane for a new, coplanar point (default Vn)
    Wn   - min facet width for outside point (before roundoff, default 2Vn)

Output formats (may be combined; if none, produces a summary to stdout):
    f    - facet dump
    G    - Geomview output (see below)
    i    - vertices incident to each facet
    m    - Mathematica output (2-d and 3-d)
    n    - normals with offsets
    o    - OFF format (dim, points and facets; Voronoi regions)
    p    - vertex coordinates or Voronoi vertices (coplanar points if 'Qc')
    s    - summary (stderr)

More formats:
    Fa   - area for each facet
    FA   - compute total area and volume for option 's'
    Fc   - count plus coplanar points for each facet
           use 'Qc' (default) for coplanar and 'Qi' for interior
    FC   - centrum or Voronoi center for each facet
    Fd   - use cdd format for input (homogeneous with offset first)
    FD   - use cdd format for numeric output (offset first)
    FF   - facet dump without ridges
    Fi   - inner plane for each facet
           for 'v', separating hyperplanes for bounded Voronoi regions
    FI   - ID of each facet
    Fm   - merge count for each facet (511 max)
    FM   - Maple output (2-d and 3-d)
    Fn   - count plus neighboring facets for each facet
    FN   - count plus neighboring facets for each point
    Fo   - outer plane (or max_outside) for each facet
           for 'v', separating hyperplanes for unbounded Voronoi regions
    FO   - options and precision constants
    Fp   - dim, count, and intersection coordinates (halfspace only)
    FP   - nearest vertex and distance for each coplanar point
    FQ   - command used for qhull
    Fs   - summary: #int (8), dimension, #points, tot vertices, tot facets,
                      output: #vertices, #facets, #coplanars, #nonsimplicial
                    #real (2), max outer plane, min vertex
    FS   - sizes:   #int (0)
                    #real (2) tot area, tot volume
    Ft   - triangulation with centrums for non-simplicial facets (OFF format)
    Fv   - count plus vertices for each facet
           for 'v', Voronoi diagram as Voronoi vertices for pairs of sites
    FV   - average of vertices (a feasible point for 'H')
    Fx   - extreme points (in order for 2-d)

Geomview output (2-d, 3-d, and 4-d; 2-d Voronoi)
    Ga   - all points as dots
     Gp  -  coplanar points and vertices as radii
     Gv  -  vertices as spheres
    Gc   - centrums
    GDn  - drop dimension n in 3-d and 4-d output
    Gh   - hyperplane intersections
    Gi   - inner planes only
     Gn  -  no planes
     Go  -  outer planes only
    Gr   - ridges
    Gt   - for 3-d 'd', transparent outer ridges

Print options:
    PAn  - keep n largest facets by area
    Pdk:n - drop facet if normal[k] <= n (default 0.0)
    PDk:n - drop facet if normal[k] >= n
    PFn  - keep facets whose area is at least n
    Pg   - print good facets (needs 'QGn' or 'QVn')
    PG   - print neighbors of good facets
    PMn  - keep n facets with most merges
    Po   - force output.  If error, output neighborhood of facet
    Pp   - do not report precision problems

    .    - list of all options
    -    - one line descriptions of all options
    -?   - help with examples
    -V   - version

Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
To: synopsis • input • outputs • controls • options


The Geometry Center Home Page

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

qhull-2020.2/html/qhull.man0000644060175106010010000011446313500461230013757 0ustar bbarber.\" This is the Unix manual page for qhull, written in nroff, the standard .\" manual formatter for Unix systems. To format it, type .\" .\" nroff -man qhull.man .\" .\" This will print a formatted copy to standard output. If you want .\" to ensure that the output is plain ASCII, free of any control .\" characters that nroff uses for underlining etc, pipe the output .\" through "col -b": .\" .\" nroff -man qhull.man | col -b .\" .\" Warning: a leading quote "'" or dot "." will not format correctly .\" .TH qhull 1 "2003/12/30" "Geometry Center" .SH NAME qhull \- convex hull, Delaunay triangulation, Voronoi diagram, halfspace intersection about a point, hull volume, facet area .SH SYNOPSIS .nf qhull- compute convex hulls and related structures input (stdin): dimension, #points, point coordinates first comment (non-numeric) is listed in the summary halfspace: use dim plus one with offsets after coefficients options (qh-quick.htm): d - Delaunay triangulation by lifting points to a paraboloid d Qu - furthest-site Delaunay triangulation (upper convex hull) v - Voronoi diagram as the dual of the Delaunay triangulation v Qu - furthest-site Voronoi diagram H1,1 - Halfspace intersection about [1,1,0,...] via polar duality Qt - triangulated output QJ - joggled input instead of merged facets Tv - verify result: structure, convexity, and point inclusion . - concise list of all options - - one-line description of each option -? - this message -V - version Output options (subset): s - summary of results (default) i - vertices incident to each facet n - normals with offsets p - vertex coordinates (if 'Qc', includes coplanar points) if 'v', Voronoi vertices FA - report total area and volume Fp - halfspace intersections FS - total area and volume Fx - extreme points (convex hull vertices) G - Geomview output (2-d, 3-d and 4-d) m - Mathematica output (2-d and 3-d) o - OFF format (if 'v', outputs Voronoi regions) QVn - print facets that include point n, -n if not TI file - input file, may be enclosed in single quotes TO file - output file, may be enclosed in single quotes examples: rbox D4 | qhull Tv rbox 1000 s | qhull Tv s FA rbox 10 D2 | qhull d QJ s i TO result rbox 10 D2 | qhull v Qbb Qt p rbox 10 D2 | qhull d Qu QJ m rbox 10 D2 | qhull v Qu QJ o rbox c d D2 | qhull Qc s f Fx | more rbox c | qhull FV n | qhull H Fp rbox d D12 | qhull QR0 FA rbox c D7 | qhull FA TF1000 rbox y 1000 W0 | qhull Qc rbox c | qhull n .fi - html manual: html/index.htm - installation: README.txt - see also: COPYING.txt, REGISTER.txt, Changes.txt - WWW: - GIT: - news: - Geomview: - news group: - FAQ: - email: qhull@qhull.org - bug reports: qhull_bug@qhull.org The sections are: - INTRODUCTION - DESCRIPTION, a description of Qhull - IMPRECISION, how Qhull handles imprecision - OPTIONS - Input and output options - Additional input/output formats - Precision options - Geomview options - Print options - Qhull options - Trace options - BUGS - E-MAIL - SEE ALSO - AUTHORS - ACKNOWLEGEMENTS This man page briefly describes all Qhull options. Please report any mismatches with Qhull's html manual (html/index.htm). .PP .SH INTRODUCTION Qhull is a general dimension code for computing convex hulls, Delaunay triangulations, Voronoi diagram, furthest\[hy]site Voronoi diagram, furthest\[hy]site Delaunay triangulations, and halfspace intersections about a point. It implements the Quickhull algorithm for computing the convex hull. Qhull handles round\[hy]off errors from floating point arithmetic. It can approximate a convex hull. The program includes options for hull volume, facet area, partial hulls, input transformations, randomization, tracing, multiple output formats, and execution statistics. The program can be called from within your application. You can view the results in 2\[hy]d, 3\[hy]d and 4\[hy]d with Geomview. .PP .SH DESCRIPTION .PP The format of input is the following: first line contains the dimension, second line contains the number of input points, and point coordinates follow. The dimension and number of points can be reversed. Comments and line breaks are ignored. A comment starts with a non\[hy]numeric character and continues to the end of line. The first comment is reported in summaries and statistics. Error reporting is better if there is one point per line. .PP The default printout option is a short summary. There are many other output formats. .PP Qhull implements the Quickhull algorithm for convex hull. This algorithm combines the 2\[hy]d Quickhull algorithm with the n\[hy]d beneath\[hy]beyond algorithm [c.f., Preparata & Shamos '85]. It is similar to the randomized algorithms of Clarkson and others [Clarkson et al. '93]. The main advantages of Quickhull are output sensitive performance, reduced space requirements, and automatic handling of precision problems. .PP The data structure produced by Qhull consists of vertices, ridges, and facets. A vertex is a point of the input set. A ridge is a set of d vertices and two neighboring facets. For example in 3\[hy]d, a ridge is an edge of the polyhedron. A facet is a set of ridges, a set of neighboring facets, a set of incident vertices, and a hyperplane equation. For simplicial facets, the ridges are defined by the vertices and neighboring facets. When Qhull merges two facets, it produces a non\[hy]simplicial facet. A non\[hy]simplicial facet has more than d neighbors and may share more than one ridge with a neighbor. .PP .SH IMPRECISION .PP Since Qhull uses floating point arithmetic, roundoff error may occur for each calculation. This causes problems for most geometric algorithms. .PP Qhull automatically sets option 'C\-0' in 2\[hy]d, 3\[hy]d, and 4\[hy]d, or option 'Qx' in 5\[hy]d and higher. These options handle precision problems by merging facets. Alternatively, use option 'QJ' to joggle the input. .PP With 'C\-0', Qhull merges non\[hy]convex facets while constructing the hull. The remaining facets are clearly convex. With 'Qx', Qhull merges coplanar horizon facets, flipped facets, concave facets and duplicated ridges. It merges coplanar facets after constructing the hull. With 'Qx', coplanar points may be missed, but it appears to be unlikely. .PP To guarantee triangular output, joggle the input with option 'QJ'. Facet merging will not occur. .SH OPTIONS .PP To get a list of the most important options, execute 'qhull -?'. To get a complete list of options, execute 'qhull \-'. To get a complete, concise list of options, execute 'qhull .'. Options can be in any order. Capitalized options take an argument (except 'PG' and 'F' options). Single letters are used for output formats and precision constants. The other options are grouped into menus: output formats ('F'), Geomview output ('G'), printing ('P'), Qhull control ('Q'), and tracing ('T'). .TP Main options: .TP default Compute the convex hull of the input points. Report a summary of the result. .TP d Compute the Delaunay triangulation by lifting the input points to a paraboloid. The 'o' option prints the input points and facets. The 'QJ' option guarantees triangular output. The 'Ft' option prints a triangulation. It adds points (the centrums) to non\[hy]simplicial facets. .TP v Compute the Voronoi diagram from the Delaunay triangulation. The 'p' option prints the Voronoi vertices. The 'o' option prints the Voronoi vertices and the vertices in each Voronoi region. It lists regions in site ID order. The 'Fv' option prints each ridge of the Voronoi diagram. The first or zero'th vertex indicates the infinity vertex. Its coordinates are qh_INFINITE (\-10.101). It indicates unbounded Voronoi regions or degenerate Delaunay triangles. .TP Hn,n,... Compute halfspace intersection about [n,n,0,...]. The input is a set of halfspaces defined in the same format as 'n', 'Fo', and 'Fi'. Use 'Fp' to print the intersection points. Use 'Fv' to list the intersection points for each halfspace. The other output formats display the dual convex hull. The point [n,n,n,...] is a feasible point for the halfspaces, i.e., a point that is inside all of the halfspaces (Hx+b <= 0). The default coordinate value is 0. The input may start with a feasible point. If so, use 'H' by itself. The input starts with a feasible point when the first number is the dimension, the second number is "1", and the coordinates complete a line. The 'FV' option produces a feasible point for a convex hull. .TP d Qu Compute the furthest\[hy]site Delaunay triangulation from the upper convex hull. The 'o' option prints the input points and facets. The 'QJ' option guarantees triangular otuput. You can also use 'Ft' to triangulate via the centrums of non\[hy]simplicial facets. .TP v Qu Compute the furthest\[hy]site Voronoi diagram. The 'p' option prints the Voronoi vertices. The 'o' option prints the Voronoi vertices and the vertices in each Voronoi region. The 'Fv' option prints each ridge of the Voronoi diagram. The first or zero'th vertex indicates the infinity vertex at infinity. Its coordinates are qh_INFINITE (\-10.101). It indicates unbounded Voronoi regions and degenerate Delaunay triangles. .PP .TP Input/Output options: .TP f Print all facets and all fields of each facet. .TP G Output the hull in Geomview format. For imprecise hulls, Geomview displays the inner and outer hull. Geomview can also display points, ridges, vertices, coplanar points, and facet intersections. See below for a list of options. For Delaunay triangulations, 'G' displays the corresponding paraboloid. For halfspace intersection, 'G' displays the dual polytope. .TP i Output the incident vertices for each facet. Qhull prints the number of facets followed by the vertices of each facet. One facet is printed per line. The numbers are the 0\[hy]relative indices of the corresponding input points. The facets are oriented. In 4d and higher, Qhull triangulates non\[hy]simplicial facets. Each apex (the first vertex) is a created point that corresponds to the facet's centrum. Its index is greater than the indices of the input points. Each base corresponds to a simplicial ridge between two facets. To print the vertices without triangulation, use option 'Fv'. To print the centrum coordinates, use option 'Ft'. The centrum indices for option 'i' are one more than the centrum indices for option 'Ft'. .TP m Output the hull in Mathematica format. Qhull writes a Mathematica file for 2\[hy]d and 3\[hy]d convex hulls and for 2\[hy]d Delaunay triangulations. Qhull produces a list of objects that you can assign to a variable in Mathematica, for example: "list= << ". If the object is 2\[hy]d, it can be visualized by "Show[Graphics[list]] ". For 3\[hy]d objects the command is "Show[Graphics3D[list]]". .TP n Output the normal equation for each facet. Qhull prints the dimension (plus one), the number of facets, and the normals for each facet. The facet's offset follows its normal coefficients. .TP o Output the facets in OFF file format. Qhull prints the dimension, number of points, number of facets, and number of ridges. Then it prints the coordinates of the input points and the vertices for each facet. Each facet is on a separate line. The first number is the number of vertices. The remainder are the indices of the corresponding points. The vertices are oriented in 2\[hy]d, 3\[hy]d, and in simplicial facets. For 2\[hy]d Voronoi diagrams, the vertices are sorted by adjacency, but not oriented. In 3\[hy]d and higher, the Voronoi vertices are sorted by index. See the 'v' option for more information. .TP p Output the coordinates of each vertex point. Qhull prints the dimension, the number of points, and the coordinates for each vertex. With the 'Gc' and 'Gi' options, it also prints coplanar and interior points. For Voronoi diagrams, it prints the coordinates of each Voronoi vertex. .TP s Print a summary to stderr. If no output options are specified, a summary goes to stdout. The summary lists the number of input points, the dimension, the number of vertices in the convex hull, the number of facets in the convex hull, the number of good facets (if 'Pg'), and statistics. The last two statistics (if needed) measure the maximum distance from a point or vertex to a facet. The number in parenthesis (e.g., 2.1x) is the ratio between the maximum distance and the worst\[hy]case distance due to merging two simplicial facets. .PP .TP Precision options .TP An Maximum angle given as a cosine. If the angle between a pair of facet normals is greater than n, Qhull merges one of the facets into a neighbor. If 'n' is negative, Qhull tests angles after adding each point to the hull (pre\[hy]merging). If 'n' is positive, Qhull tests angles after constructing the hull (post\[hy]merging). Both pre\[hy] and post\[hy]merging can be defined. Option 'C0' or 'C\-0' is set if the corresponding 'Cn' or 'C\-n' is not set. If 'Qx' is set, then 'A\-n' and 'C\-n' are checked after the hull is constructed and before 'An' and 'Cn' are checked. .TP Cn Centrum radius. If a centrum is less than n below a neighboring facet, Qhull merges one of the facets. If 'n' is negative or '\-0', Qhull tests and merges facets after adding each point to the hull. This is called "pre\[hy]merging". If 'n' is positive, Qhull tests for convexity after constructing the hull ("post\[hy]merging"). Both pre\[hy] and post\[hy]merging can be defined. For 5\[hy]d and higher, 'Qx' should be used instead of 'C\-n'. Otherwise, most or all facets may be merged together. .TP En Maximum roundoff error for distance computations. .TP Rn Randomly perturb distance computations up to +/\- n * max_coord. This option perturbs every distance, hyperplane, and angle computation. To use time as the random number seed, use option 'QR\-1'. .TP Vn Minimum distance for a facet to be visible. A facet is visible if the distance from the point to the facet is greater than 'Vn'. Without merging, the default value for 'Vn' is the round\[hy]off error ('En'). With merging, the default value is the pre\[hy]merge centrum ('C\-n') in 2\[hy]d or 3\[hy]d, or three times that in other dimensions. If the outside width is specified ('Wn'), the maximum, default value for 'Vn' is 'Wn'. .TP Un Maximum distance below a facet for a point to be coplanar to the facet. The default value is 'Vn'. .TP Wn Minimum outside width of the hull. Points are added to the convex hull only if they are clearly outside of a facet. A point is outside of a facet if its distance to the facet is greater than 'Wn'. The normal value for 'Wn' is 'En'. If the user specifies pre\[hy]merging and does not set 'Wn', than 'Wn' is set to the premerge 'Cn' and maxcoord*(1\-An). .PP .TP Additional input/output formats .TP Fa Print area for each facet. For Delaunay triangulations, the area is the area of the triangle. For Voronoi diagrams, the area is the area of the dual facet. Use 'PAn' for printing the n largest facets, and option 'PFn' for printing facets larger than 'n'. The area for non\[hy]simplicial facets is the sum of the areas for each ridge to the centrum. Vertices far below the facet's hyperplane are ignored. The reported area may be significantly less than the actual area. .TP FA Compute the total area and volume for option 's'. It is an approximation for non\[hy]simplicial facets (see 'Fa'). .TP Fc Print coplanar points for each facet. The output starts with the number of facets. Then each facet is printed one per line. Each line is the number of coplanar points followed by the point ids. Option 'Qi' includes the interior points. Each coplanar point (interior point) is assigned to the facet it is furthest above (resp., least below). .TP FC Print centrums for each facet. The output starts with the dimension followed by the number of facets. Then each facet centrum is printed, one per line. .TP Fd Read input in cdd format with homogeneous points. The input starts with comments. The first comment is reported in the summary. Data starts after a "begin" line. The next line is the number of points followed by the dimension+1 and "real" or "integer". Then the points are listed with a leading "1" or "1.0". The data ends with an "end" line. For halfspaces ('Fd Hn,n,...'), the input format is the same. Each halfspace starts with its offset. The sign of the offset is the opposite of Qhull's convention. .TP FD Print normals ('n', 'Fo', 'Fi') or points ('p') in cdd format. The first line is the command line that invoked Qhull. Data starts with a "begin" line. The next line is the number of normals or points followed by the dimension+1 and "real". Then the normals or points are listed with the offset before the coefficients. The offset for points is 1.0. The offset for normals has the opposite sign. The data ends with an "end" line. .TP FF Print facets (as in 'f') without printing the ridges. .TP Fi Print inner planes for each facet. The inner plane is below all vertices. .TP Fi Print separating hyperplanes for bounded, inner regions of the Voronoi diagram. The first line is the number of ridges. Then each hyperplane is printed, one per line. A line starts with the number of indices and floats. The first pair lists adjacent input sites, the next d floats are the normalized coefficients for the hyperplane, and the last float is the offset. The hyperplane is oriented toward 'QVn' (if defined), or the first input site of the pair. Use 'Tv' to verify that the hyperplanes are perpendicular bisectors. Use 'Fo' for unbounded regions, and 'Fv' for the corresponding Voronoi vertices. .TP FI Print facet identifiers. .TP Fm Print number of merges for each facet. At most 511 merges are reported for a facet. See 'PMn' for printing the facets with the most merges. .TP FM Output the hull in Maple format. Qhull writes a Maple file for 2\[hy]d and 3\[hy]d convex hulls and for 2\[hy]d Delaunay triangulations. Qhull produces a '.mpl' file for displaying with display3d(). .TP Fn Print neighbors for each facet. The output starts with the number of facets. Then each facet is printed one per line. Each line is the number of neighbors followed by an index for each neighbor. The indices match the other facet output formats. A negative index indicates an unprinted facet due to printing only good facets ('Pg'). It is the negation of the facet's ID (option 'FI'). For example, negative indices are used for facets "at infinity" in the Delaunay triangulation. .TP FN Print vertex neighbors or coplanar facet for each point. The first line is the number of points. Then each point is printed, one per line. If the point is coplanar, the line is "1" followed by the facet's ID. If the point is not a selected vertex, the line is "0". Otherwise, each line is the number of neighbors followed by the corresponding facet indices (see 'Fn'). .TP Fo Print outer planes for each facet in the same format as 'n'. The outer plane is above all points. .TP Fo Print separating hyperplanes for unbounded, outer regions of the Voronoi diagram. The first line is the number of ridges. Then each hyperplane is printed, one per line. A line starts with the number of indices and floats. The first pair lists adjacent input sites, the next d floats are the normalized coefficients for the hyperplane, and the last float is the offset. The hyperplane is oriented toward 'QVn' (if defined), or the first input site of the pair. Use 'Tv' to verify that the hyperplanes are perpendicular bisectors. Use 'Fi' for bounded regions, and 'Fv' for the corresponding Voronoi vertices. .TP FO List all options to stderr, including the default values. Additional 'FO's are printed to stdout. .TP Fp Print points for halfspace intersections (option 'Hn,n,...'). Each intersection corresponds to a facet of the dual polytope. The "infinity" point [\-10.101,\-10.101,...] indicates an unbounded intersection. .TP FP For each coplanar point ('Qc') print the point ID of the nearest vertex, the point ID, the facet ID, and the distance. .TP FQ Print command used for qhull and input. .TP Fs Print a summary. The first line consists of the number of integers ("8"), followed by the dimension, the number of points, the number of vertices, the number of facets, the number of vertices selected for output, the number of facets selected for output, the number of coplanar points selected for output, number of simplicial, unmerged facets in output The second line consists of the number of reals ("2"), followed by the maxmimum offset to an outer plane and and minimum offset to an inner plane. Roundoff is included. Later versions of Qhull may produce additional integers or reals. .TP FS Print the size of the hull. The first line consists of the number of integers ("0"). The second line consists of the number of reals ("2"), followed by the total facet area, and the total volume. Later versions of Qhull may produce additional integers or reals. The total volume measures the volume of the intersection of the halfspaces defined by each facet. Both area and volume are approximations for non\[hy]simplicial facets. See option 'Fa'. .TP Ft Print a triangulation with added points for non\[hy]simplicial facets. The first line is the dimension and the second line is the number of points and the number of facets. The points follow, one per line, then the facets follow as a list of point indices. With option 'Qz', the points include the point\[hy]at\[hy]infinity. .TP Fv Print vertices for each facet. The first line is the number of facets. Then each facet is printed, one per line. Each line is the number of vertices followed by the corresponding point ids. Vertices are listed in the order they were added to the hull (the last one is first). .TP Fv Print all ridges of a Voronoi diagram. The first line is the number of ridges. Then each ridge is printed, one per line. A line starts with the number of indices. The first pair lists adjacent input sites, the remaining indices list Voronoi vertices. Vertex '0' indicates the vertex\[hy]at\[hy]infinity (i.e., an unbounded ray). In 3\[hy]d, the vertices are listed in order. See 'Fi' and 'Fo' for separating hyperplanes. .TP FV Print average vertex. The average vertex is a feasible point for halfspace intersection. .TP Fx List extreme points (vertices) of the convex hull. The first line is the number of points. The other lines give the indices of the corresponding points. The first point is '0'. In 2\[hy]d, the points occur in counter\[hy]clockwise order; otherwise they occur in input order. For Delaunay triangulations, 'Fx' lists the extreme points of the input sites. The points are unordered. .PP .TP Geomview options .TP G Produce a file for viewing with Geomview. Without other options, Qhull displays edges in 2\[hy]d, outer planes in 3\[hy]d, and ridges in 4\[hy]d. A ridge can be explicit or implicit. An explicit ridge is a dim\-1 dimensional simplex between two facets. In 4\[hy]d, the explicit ridges are triangles. When displaying a ridge in 4\[hy]d, Qhull projects the ridge's vertices to one of its facets' hyperplanes. Use 'Gh' to project ridges to the intersection of both hyperplanes. .TP Ga Display all input points as dots. .TP Gc Display the centrum for each facet in 3\[hy]d. The centrum is defined by a green radius sitting on a blue plane. The plane corresponds to the facet's hyperplane. The radius is defined by 'C\-n' or 'Cn'. .TP GDn Drop dimension n in 3\[hy]d or 4\[hy]d. The result is a 2\[hy]d or 3\[hy]d object. .TP Gh Display hyperplane intersections in 3\[hy]d and 4\[hy]d. In 3\[hy]d, the intersection is a black line. It lies on two neighboring hyperplanes (c.f., the blue squares associated with centrums ('Gc')). In 4\[hy]d, the ridges are projected to the intersection of both hyperplanes. .TP Gi Display inner planes in 2\[hy]d and 3\[hy]d. The inner plane of a facet is below all of its vertices. It is parallel to the facet's hyperplane. The inner plane's color is the opposite (1\-r,1\-g,1\-b) of the outer plane. Its edges are determined by the vertices. .TP Gn Do not display inner or outer planes. By default, Geomview displays the precise plane (no merging) or both inner and output planes (merging). Under merging, Geomview does not display the inner plane if the the difference between inner and outer is too small. .TP Go Display outer planes in 2\[hy]d and 3\[hy]d. The outer plane of a facet is above all input points. It is parallel to the facet's hyperplane. Its color is determined by the facet's normal, and its edges are determined by the vertices. .TP Gp Display coplanar points and vertices as radii. A radius defines a ball which corresponds to the imprecision of the point. The imprecision is the maximum of the roundoff error, the centrum radius, and maxcoord * (1\-An). It is at least 1/20'th of the maximum coordinate, and ignores post\[hy]merging if pre\[hy]merging is done. .TP Gr Display ridges in 3\[hy]d. A ridge connects the two vertices that are shared by neighboring facets. Ridges are always displayed in 4\[hy]d. .TP Gt A 3\[hy]d Delaunay triangulation looks like a convex hull with interior facets. Option 'Gt' removes the outside ridges to reveal the outermost facets. It automatically sets options 'Gr' and 'GDn'. .TP Gv Display vertices as spheres. The radius of the sphere corresponds to the imprecision of the data. See 'Gp' for determining the radius. .PP .TP Print options .TP PAn Only the n largest facets are marked good for printing. Unless 'PG' is set, 'Pg' is automatically set. .TP Pdk:n Drop facet from output if normal[k] <= n. The option 'Pdk' uses the default value of 0 for n. .TP PDk:n Drop facet from output if normal[k] >= n. The option 'PDk' uses the default value of 0 for n. .TP PFn Only facets with area at least 'n' are marked good for printing. Unless 'PG' is set, 'Pg' is automatically set. .TP Pg Print only good facets. A good facet is either visible from a point (the 'QGn' option) or includes a point (the 'QVn' option). It also meets the requirements of 'Pdk' and 'PDk' options. Option 'Pg' is automatically set for options 'd', 'PAn', 'PFn', and 'PMn'. .TP PG Print neighbors of good facets. .TP PMn Only the n facets with the most merges are marked good for printing. Unless 'PG' is set, 'Pg' is automatically set. .TP Po Force output despite precision problems. Verify ('Tv') does not check coplanar points. Flipped facets are reported and concave facets are counted. If 'Po' is used, points are not partitioned into flipped facets and a flipped facet is always visible to a point. Also, if an error occurs before the completion of Qhull and tracing is not active, 'Po' outputs a neighborhood of the erroneous facets (if any). .TP Pp Do not report precision problems. .PP .TP Qhull control options .TP Qa Allow input with fewer or more points than coordinates .TP Qbk:0Bk:0 Drop dimension k from the input points. This allows the user to take convex hulls of sub\[hy]dimensional objects. It happens before the Delaunay and Voronoi transformation. .TP QbB Scale the input points to fit the unit cube. After scaling, the lower bound will be \-0.5 and the upper bound +0.5 in all dimensions. For Delaunay and Voronoi diagrams, scaling happens after projection to the paraboloid. Under precise arithmetic, scaling does not change the topology of the convex hull. .TP Qbb Scale the last coordinate to [0, m] where m is the maximum absolute value of the other coordinates. For Delaunay and Voronoi diagrams, scaling happens after projection to the paraboloid. It reduces roundoff error for inputs with integer coordinates. Under precise arithmetic, scaling does not change the topology of the convex hull. .TP Qbk:n Scale the k'th coordinate of the input points. After scaling, the lower bound of the input points will be n. 'Qbk' scales to \-0.5. .TP QBk:n Scale the k'th coordinate of the input points. After scaling, the upper bound will be n. 'QBk' scales to +0.5. .TP Qc Keep coplanar points with the nearest facet. Output formats 'p', 'f', 'Gp', 'Fc', 'FN', and 'FP' will print the points. .TP Qf Partition points to the furthest outside facet. .TP Qg Only build good facets. With the 'Qg' option, Qhull will only build those facets that it needs to determine the good facets in the output. See 'QGn', 'QVn', and 'PdD' for defining good facets, and 'Pg' and 'PG' for printing good facets and their neighbors. .TP QGn A facet is good (see 'Qg' and 'Pg') if it is visible from point n. If n < 0, a facet is good if it is not visible from point n. Point n is not added to the hull (unless 'TCn' or 'TPn'). With rbox, use the 'Pn,m,r' option to define your point; it will be point 0 (QG0). .TP Qi Keep interior points with the nearest facet. Output formats 'p', 'f', 'Gp', 'FN', 'FP', and 'Fc' will print the points. .TP QJn Joggle each input coordinate by adding a random number in [\-n,n]. If a precision error occurs, then qhull increases n and tries again. It does not increase n beyond a certain value, and it stops after a certain number of attempts [see user.h]. Option 'QJ' selects a default value for n. The output will be simplicial. For Delaunay triangulations, 'QJn' sets 'Qbb' to scale the last coordinate (not if 'Qbk:n' or 'QBk:n' is set). \'QJn' is deprecated for Voronoi diagrams. See also 'Qt'. .TP Qm Only process points that would otherwise increase max_outside. Other points are treated as coplanar or interior points. .TP Qr Process random outside points instead of furthest ones. This makes Qhull equivalent to the randomized incremental algorithms. CPU time is not reported since the randomization is inefficient. .TP QRn Randomly rotate the input points. If n=0, use time as the random number seed. If n>0, use n as the random number seed. If n=\-1, don't rotate but use time as the random number seed. For Delaunay triangulations ('d' and 'v'), rotate about the last axis. .TP Qs Search all points for the initial simplex. .TP Qt Triangulated output. Triangulate all non\[hy]simplicial facets. \'Qt' is deprecated for Voronoi diagrams. See also 'Qt'. .TP Qv Test vertex neighbors for convexity after post\[hy]merging. To use the 'Qv' option, you also need to set a merge option (e.g., 'Qx' or 'C\-0'). .TP QVn A good facet (see 'Qg' and 'Pg') includes point n. If n<0, then a good facet does not include point n. The point is either in the initial simplex or it is the first point added to the hull. Option 'QVn' may not be used with merging. .TP Qw Allow option warnings. Otherwise Qhull returns an error after most option warnings .TP Qx Perform exact merges while building the hull. The "exact" merges are merging a point into a coplanar facet (defined by 'Vn', 'Un', and 'C\-n'), merging concave facets, merging duplicate ridges, and merging flipped facets. Coplanar merges and angle coplanar merges ('A\-n') are not performed. Concavity testing is delayed until a merge occurs. After the hull is built, all coplanar merges are performed (defined by 'C\-n' and 'A\-n'), then post\[hy]merges are performed (defined by 'Cn' and 'An'). .TP Qz Add a point "at infinity" that is above the paraboloid for Delaunay triangulations and Voronoi diagrams. This reduces precision problems and allows the triangulation of cospherical points. .PP .TP Qhull experiments and speedups .TP Q0 Turn off pre\[hy]merging as a default option. With 'Q0'/'Qx' and without explicit pre\[hy]merge options, Qhull ignores precision issues while constructing the convex hull. This may lead to precision errors. If so, a descriptive warning is generated. .TP Q1 With 'Q1', Qhull merges by mergetype/angle instead of mergetype/distance. .TP Q2 With 'Q2', Qhull merges all facets at once instead of using independent sets of merges and then retesting. .TP Q3 With 'Q3', Qhull does not remove redundant vertices. .TP Q4 With 'Q4', Qhull avoids merges of an old facet into a new facet. .TP Q5 With 'Q5', Qhull does not correct outer planes at the end. The maximum outer plane is used instead. .TP Q6 With 'Q6', Qhull does not pre\[hy]merge concave or coplanar facets. .TP Q7 With 'Q7', Qhull processes facets in depth\[hy]first order instead of breadth\[hy]first order. .TP Q8 With 'Q8' and merging, Qhull does not retain near\[hy]interior points for adjusting outer planes. 'Qc' will probably retain all points that adjust outer planes. .TP Q9 With 'Q9', Qhull processes the furthest of all outside sets at each iteration. .TP Q10 With 'Q10', Qhull does not use special processing for narrow distributions. .TP Q11 With 'Q11', Qhull copies normals and recompute centrums for tricoplanar facets. .TP Q12 With 'Q12', Qhull allows wide facets and wide dupridge. .TP Q14 With 'Q14', Qhull merges pinched vertices that create a dupridge. .TP Q15 With 'Q15', Qhull checks for duplicate ridges with the same vertices. .PP .TP Trace options .TP Tn Trace at level n. Qhull includes full execution tracing. 'T\-1' traces events. 'T1' traces the overall execution of the program. 'T2' and 'T3' trace overall execution and geometric and topological events. 'T4' traces the algorithm. 'T5' includes information about memory allocation and Gaussian elimination. .TP Ta Annotate output with codes that identify the corresponding qh_fprintf() statement. .TP TAn Stop Qhull after adding n vertices. .TP Tc Check frequently during execution. This will catch most inconsistency errors. .TP TCn Stop Qhull after building the cone of new facets for point n. The output for 'f' includes the cone and the old hull. See also 'TVn'. .TP Tf Flush output after each qh_fprintf. Use 'Tf' for debugging segfaults. See 'Tz' for redirecting stderr. .TP TFn Report progress whenever more than n facets are created During post\[hy]merging, 'TFn' reports progress after more than n/2 merges. .TP TI file Input data from 'file'. The filename may not include spaces or quotes. .TP TMn Turn on tracing at n'th merge. .TP TO file Output results to 'file'. The name may be enclosed in single quotes. .TP TPn Turn on tracing when point n is added to the hull. Trace partitions of point n. If used with TWn, turn off tracing after adding point n to the hull. .TP TP-1 Turn on tracing after qh_buildhull and qh_postmerge. .TP TRn Rerun qhull n times. Usually used with 'QJn' to determine the probability that a given joggle will fail. .TP Ts Collect statistics and print to stderr at the end of execution. .TP Tv Verify the convex hull. This checks the topological structure, facet convexity, and point inclusion. If precision problems occurred, facet convexity is tested whether or not 'Tv' is selected. Option 'Tv' does not check point inclusion if forcing output with 'Po', or if 'Q5' is set. For point inclusion testing, Qhull verifies that all points are below all outer planes (facet\->maxoutside). Point inclusion is exhaustive if merging or if the facet\[hy]point product is small enough; otherwise Qhull verifies each point with a directed search (qh_findbest). Point inclusion testing occurs after producing output. It prints a message to stderr unless option 'Pp' is used. This allows the user to interrupt Qhull without changing the output. .TP TVn Stop Qhull after adding point n. If n < 0, stop Qhull before adding point n. Output shows the hull at this time. See also 'TCn' .TP TWn Trace merge facets when the width is greater than n. .TP Tz Redirect stderr to stdout. See 'Tf' for flushing writes. .PP .SH BUGS Please report bugs to Brad Barber at qhull_bug@qhull.org. If Qhull does not compile, it is due to an incompatibility between your system and ours. The first thing to check is that your compiler is ANSI standard. If it is, check the man page for the best options, or find someone to help you. If you locate the cause of your problem, please send email since it might help others. If Qhull compiles but crashes on the test case (rbox D4), there's still incompatibility between your system and ours. Typically it's been due to mem.c and memory alignment. You can use qh_NOmem in mem.h to turn off memory management. Please let us know if you figure out how to fix these problems. If you do find a problem, try to simplify it before reporting the error. Try different size inputs to locate the smallest one that causes an error. You're welcome to hunt through the code using the execution trace as a guide. This is especially true if you're incorporating Qhull into your own program. When you do report an error, please attach a data set to the end of your message. This allows us to see the error for ourselves. Qhull is maintained part\[hy]time. .PP .SH E\[hy]MAIL Please send correspondence to qhull@qhull.org and report bugs to qhull_bug@qhull.org. Let us know how you use Qhull. If you mention it in a paper, please send the reference and an abstract. If you would like to get Qhull announcements (e.g., a new version) and news (any bugs that get fixed, etc.), let us know and we will add you to our mailing list. If you would like to communicate with other Qhull users, we will add you to the qhull_users alias. For Internet news about geometric algorithms and convex hulls, look at comp.graphics.algorithms and sci.math.num\-analysis .SH SEE ALSO rbox(1) Barber, C. B., D.P. Dobkin, and H.T. Huhdanpaa, "The Quickhull Algorithm for Convex Hulls," ACM Trans. on Mathematical Software, 22(4):469\[en]483, Dec. 1996. http://portal.acm.org/citation.cfm?doid=235815.235821 http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.117.405 Clarkson, K.L., K. Mehlhorn, and R. Seidel, "Four results on randomized incremental construction," Computational Geometry: Theory and Applications, vol. 3, p. 185\[en]211, 1993. Preparata, F. and M. Shamos, Computational Geometry, Springer\[hy]Verlag, New York, 1985. .PP .SH AUTHORS .nf C. Bradford Barber Hannu Huhdanpaa bradb@shore.net hannu@qhull.org .fi .SH ACKNOWLEDGEMENTS A special thanks to Albert Marden, Victor Milenkovic, the Geometry Center, Harvard University, and Endocardial Solutions, Inc. for supporting this work. Qhull 1.0 and 2.0 were developed under National Science Foundation grants NSF/DMS\[hy]8920161 and NSF\[hy]CCR\[hy]91\[hy]15793 750\[hy]7504. David Dobkin guided the original work at Princeton University. If you find it useful, please let us know. The Geometry Center is supported by grant DMS\[hy]8920161 from the National Science Foundation, by grant DOE/DE\[hy]FG02\[hy]92ER25137 from the Department of Energy, by the University of Minnesota, and by Minnesota Technology, Inc. Qhull is available from http://www.qhull.org qhull-2020.2/html/qhull.txt0000644060175106010010000014341113500461230014016 0ustar bbarber qhull(1) qhull(1) NAME qhull - convex hull, Delaunay triangulation, Voronoi dia- gram, halfspace intersection about a point, hull volume, facet area SYNOPSIS qhull- compute convex hulls and related structures input (stdin): dimension, #points, point coordinates first comment (non-numeric) is listed in the summary halfspace: use dim plus one with offsets after coefficients options (qh-quick.htm): d - Delaunay triangulation by lifting points to a paraboloid d Qu - furthest-site Delaunay triangulation (upper convex hull) v - Voronoi diagram as the dual of the Delaunay triangulation v Qu - furthest-site Voronoi diagram H1,1 - Halfspace intersection about [1,1,0,...] via polar duality Qt - triangulated output QJ - joggled input instead of merged facets Tv - verify result: structure, convexity, and point inclusion . - concise list of all options - - one-line description of each option -? - this message -V - version Output options (subset): s - summary of results (default) i - vertices incident to each facet n - normals with offsets p - vertex coordinates (if 'Qc', includes coplanar points) if 'v', Voronoi vertices FA - report total area and volume Fp - halfspace intersections FS - total area and volume Fx - extreme points (convex hull vertices) G - Geomview output (2-d, 3-d and 4-d) m - Mathematica output (2-d and 3-d) o - OFF format (if 'v', outputs Voronoi regions) QVn - print facets that include point n, -n if not TI file - input file, may be enclosed in single quotes TO file - output file, may be enclosed in single quotes examples: rbox D4 | qhull Tv rbox 1000 s | qhull Tv s FA rbox 10 D2 | qhull d QJ s i TO result rbox 10 D2 | qhull v Qbb Qt p rbox 10 D2 | qhull d Qu QJ m rbox 10 D2 | qhull v Qu QJ o rbox c d D2 | qhull Qc s f Fx | more rbox c | qhull FV n | qhull H Fp rbox d D12 | qhull QR0 FA rbox c D7 | qhull FA TF1000 rbox y 1000 W0 | qhull Qc rbox c | qhull n - html manual: html/index.htm - installation: README.txt - see also: COPYING.txt, REGISTER.txt, Changes.txt - WWW: - GIT: - news: - Geomview: - news group: - FAQ: - email: qhull@qhull.org - bug reports: qhull_bug@qhull.org Geometry Center 2019/05/03 1 qhull(1) qhull(1) The sections are: - INTRODUCTION - DESCRIPTION, a description of Qhull - IMPRECISION, how Qhull handles imprecision - OPTIONS - Input and output options - Additional input/output formats - Precision options - Geomview options - Print options - Qhull options - Trace options - BUGS - E-MAIL - SEE ALSO - AUTHORS - ACKNOWLEGEMENTS This man page briefly describes all Qhull options. Please report any mismatches with Qhull's html manual (html/index.htm). INTRODUCTION Qhull is a general dimension code for computing convex hulls, Delaunay triangulations, Voronoi diagram, furthest- site Voronoi diagram, furthest-site Delaunay triangula- tions, and halfspace intersections about a point. It implements the Quickhull algorithm for computing the con- vex hull. Qhull handles round-off errors from floating point arithmetic. It can approximate a convex hull. The program includes options for hull volume, facet area, partial hulls, input transformations, randomization, trac- ing, multiple output formats, and execution statistics. The program can be called from within your application. You can view the results in 2-d, 3-d and 4-d with Geomview. DESCRIPTION The format of input is the following: first line contains the dimension, second line contains the number of input points, and point coordinates follow. The dimension and number of points can be reversed. Comments and line breaks are ignored. A comment starts with a non-numeric character and continues to the end of line. The first comment is reported in summaries and statistics. Error reporting is better if there is one point per line. The default printout option is a short summary. There are many other output formats. Geometry Center 2019/05/03 2 qhull(1) qhull(1) Qhull implements the Quickhull algorithm for convex hull. This algorithm combines the 2-d Quickhull algorithm with the n-d beneath-beyond algorithm [c.f., Preparata & Shamos '85]. It is similar to the randomized algorithms of Clarkson and others [Clarkson et al. '93]. The main advantages of Quickhull are output sensitive performance, reduced space requirements, and automatic handling of pre- cision problems. The data structure produced by Qhull consists of vertices, ridges, and facets. A vertex is a point of the input set. A ridge is a set of d vertices and two neighboring facets. For example in 3-d, a ridge is an edge of the polyhedron. A facet is a set of ridges, a set of neighboring facets, a set of incident vertices, and a hyperplane equation. For simplicial facets, the ridges are defined by the vertices and neighboring facets. When Qhull merges two facets, it produces a non-simplicial facet. A non-simplicial facet has more than d neighbors and may share more than one ridge with a neighbor. IMPRECISION Since Qhull uses floating point arithmetic, roundoff error may occur for each calculation. This causes problems for most geometric algorithms. Qhull automatically sets option 'C-0' in 2-d, 3-d, and 4-d, or option 'Qx' in 5-d and higher. These options han- dle precision problems by merging facets. Alternatively, use option 'QJ' to joggle the input. With 'C-0', Qhull merges non-convex facets while con- structing the hull. The remaining facets are clearly con- vex. With 'Qx', Qhull merges coplanar horizon facets, flipped facets, concave facets and duplicated ridges. It merges coplanar facets after constructing the hull. With 'Qx', coplanar points may be missed, but it appears to be unlikely. To guarantee triangular output, joggle the input with option 'QJ'. Facet merging will not occur. OPTIONS To get a list of the most important options, execute 'qhull -?'. To get a complete list of options, execute 'qhull -'. To get a complete, concise list of options, execute 'qhull .'. Options can be in any order. Capitalized options take an argument (except 'PG' and 'F' options). Single letters are used for output formats and precision constants. The other options are grouped into menus: output formats ('F'), Geomview output ('G'), printing ('P'), Qhull control ('Q'), Geometry Center 2019/05/03 3 qhull(1) qhull(1) and tracing ('T'). Main options: default Compute the convex hull of the input points. Report a summary of the result. d Compute the Delaunay triangulation by lifting the input points to a paraboloid. The 'o' option prints the input points and facets. The 'QJ' option guarantees triangular output. The 'Ft' option prints a triangulation. It adds points (the centrums) to non-simplicial facets. v Compute the Voronoi diagram from the Delaunay tri- angulation. The 'p' option prints the Voronoi ver- tices. The 'o' option prints the Voronoi vertices and the vertices in each Voronoi region. It lists regions in site id order. The 'Fv' option prints each ridge of the Voronoi diagram. The first or zero'th vertex indicates the infinity vertex. Its coordinates are qh_INFINITE (-10.101). It indi- cates unbounded Voronoi regions or degenerate Delaunay triangles. Hn,n,... Compute halfspace intersection about [n,n,0,...]. The input is a set of halfspaces defined in the same format as 'n', 'Fo', and 'Fi'. Use 'Fp' to print the intersection points. Use 'Fv' to list the intersection points for each halfspace. The other output formats display the dual convex hull. The point [n,n,n,...] is a feasible point for the halfspaces, i.e., a point that is inside all of the halfspaces (Hx+b <= 0). The default coordinate value is 0. The input may start with a feasible point. If so, use 'H' by itself. The input starts with a feasi- ble point when the first number is the dimension, the second number is "1", and the coordinates com- plete a line. The 'FV' option produces a feasible point for a convex hull. d Qu Compute the furthest-site Delaunay triangulation from the upper convex hull. The 'o' option prints the input points and facets. The 'QJ' option guar- antees triangular otuput. You can also use facets. v Qu Compute the furthest-site Voronoi diagram. The 'p' option prints the Voronoi vertices. The 'o' option prints the Voronoi vertices and the vertices in Geometry Center 2019/05/03 4 qhull(1) qhull(1) each Voronoi region. The 'Fv' option prints each ridge of the Voronoi diagram. The first or zero'th vertex indicates the infinity vertex at infinity. Its coordinates are qh_INFINITE (-10.101). It indicates unbounded Voronoi regions and degenerate Delaunay triangles. Qt Triangulated output. Input/Output options: f Print all facets and all fields of each facet. G Output the hull in Geomview format. For imprecise hulls, Geomview displays the inner and outer hull. Geomview can also display points, ridges, vertices, coplanar points, and facet intersections. See below for a list of options. For Delaunay triangulations, 'G' displays the cor- responding paraboloid. For halfspace intersection, 'G' displays the dual polytope. i Output the incident vertices for each facet. Qhull prints the number of facets followed by the ver- tices of each facet. One facet is printed per line. The numbers are the 0-relative indices of the corresponding input points. The facets are oriented. In 4-d and higher, Qhull triangulates non-simpli- cial facets. Each apex (the first vertex) is a created point that corresponds to the facet's cen- trum. Its index is greater than the indices of the input points. Each base corresponds to a simpli- cial ridge between two facets. To print the ver- tices without triangulation, use option 'Fv'. To print the centrum coordinates, use option 'Ft'. The centrum indices for option 'i' are one more than the centrum indices for option 'Ft'. m Output the hull in Mathematica format. Qhull writes a Mathematica file for 2-d and 3-d convex hulls and for 2-d Delaunay triangulations. Qhull produces a list of objects that you can assign to a variable in Mathematica, for example: "list= << ". If the object is 2-d, it can be visualized by "Show[Graphics[list]] ". For 3-d objects the command is "Show[Graphics3D[list]]". n Output the normal equation for each facet. Qhull prints the dimension (plus one), the number of facets, and the normals for each facet. The facet's offset follows its normal coefficients. o Output the facets in OFF file format. Qhull prints the dimension, number of points, number of facets, and number of ridges. Then it prints the Geometry Center 2019/05/03 5 qhull(1) qhull(1) coordinates of the input points and the vertices for each facet. Each facet is on a separate line. The first number is the number of vertices. The remainder are the indices of the corresponding points. The vertices are oriented in 2-d, 3-d, and in simplicial facets. For 2-d Voronoi diagrams, the vertices are sorted by adjacency, but not oriented. In 3-d and higher, the Voronoi vertices are sorted by index. See the 'v' option for more information. p Output the coordinates of each vertex point. Qhull prints the dimension, the number of points, and the coordinates for each vertex. With the 'Gc' and 'Gi' options, it also prints coplanar and interior points. For Voronoi diagrams, it prints the coor- dinates of each Voronoi vertex. s Print a summary to stderr. If no output options are specified, a summary goes to stdout. The summary lists the number of input points, the dimension, the number of vertices in the convex hull, the number of facets in the convex hull, the number of good facets (if 'Pg'), and statistics. The last two statistics (if needed) measure the maximum distance from a point or vertex to a facet. The number in parenthesis (e.g., 2.1x) is the ratio between the maximum distance and the worst-case distance due to merging two simplicial facets. Precision options An Maximum angle given as a cosine. If the angle between a pair of facet normals is greater than n, Qhull merges one of the facets into a neighbor. If 'n' is negative, Qhull tests angles after adding each point to the hull (pre-merging). If 'n' is posi- tive, Qhull tests angles after constructing the hull (post-merging). Both pre- and post-merging can be defined. Option 'C0' or 'C-0' is set if the corresponding 'Cn' or 'C-n' is not set. If 'Qx' is set, then 'A- n' and 'C-n' are checked after the hull is con- structed and before 'An' and 'Cn' are checked. Cn Centrum radius. If a centrum is less than n below a neighboring facet, Qhull merges one of the facets. If 'n' is negative or '-0', Qhull tests and merges facets after adding each point to the hull. This is called "pre-merging". If 'n' is Geometry Center 2019/05/03 6 qhull(1) qhull(1) positive, Qhull tests for convexity after con- structing the hull ("post-merging"). Both pre- and post-merging can be defined. For 5-d and higher, 'Qx' should be used instead of 'C-n'. Otherwise, most or all facets may be merged together. En Maximum roundoff error for distance computations. Rn Randomly perturb distance computations up to +/- n * max_coord. This option perturbs every distance, hyperplane, and angle computation. To use time as the random number seed, use option 'QR-1'. Vn Minimum distance for a facet to be visible. A facet is visible if the distance from the point to the facet is greater than 'Vn'. Without merging, the default value for 'Vn' is the round-off error ('En'). With merging, the default value is the pre-merge centrum ('C-n') in 2-d or 3--d, or three times that in other dimensions. If the outside width is specified ('Wn'), the maximum, default value for 'Vn' is 'Wn'. Un Maximum distance below a facet for a point to be coplanar to the facet. The default value is 'Vn'. Wn Minimum outside width of the hull. Points are added to the convex hull only if they are clearly outside of a facet. A point is outside of a facet if its distance to the facet is greater than 'Wn'. The normal value for 'Wn' is 'En'. If the user specifies pre-merging and does not set 'Wn', than 'Wn' is set to the premerge 'Cn' and maxco- ord*(1-An). Additional input/output formats Fa Print area for each facet. For Delaunay triangula- tions, the area is the area of the triangle. For Voronoi diagrams, the area is the area of the dual facet. Use 'PAn' for printing the n largest facets, and option 'PFn' for printing facets larger than 'n'. The area for non-simplicial facets is the sum of the areas for each ridge to the centrum. Vertices far below the facet's hyperplane are ignored. The reported area may be significantly less than the actual area. Geometry Center 2019/05/03 7 qhull(1) qhull(1) FA Compute the total area and volume for option 's'. It is an approximation for non-simplicial facets (see 'Fa'). Fc Print coplanar points for each facet. The output starts with the number of facets. Then each facet is printed one per line. Each line is the number of coplanar points followed by the point ids. Option 'Qi' includes the interior points. Each coplanar point (interior point) is assigned to the facet it is furthest above (resp., least below). FC Print centrums for each facet. The output starts with the dimension followed by the number of facets. Then each facet centrum is printed, one per line. Fd Read input in cdd format with homogeneous points. The input starts with comments. The first comment is reported in the summary. Data starts after a "begin" line. The next line is the number of points followed by the dimension+1 and "real" or "integer". Then the points are listed with a leading "1" or "1.0". The data ends with an "end" line. For halfspaces ('Fd Hn,n,...'), the input format is the same. Each halfspace starts with its offset. The sign of the offset is the opposite of Qhull's convention. FD Print normals ('n', 'Fo', 'Fi') or points ('p') in cdd format. The first line is the command line that invoked Qhull. Data starts with a "begin" line. The next line is the number of normals or points followed by the dimension+1 and "real". Then the normals or points are listed with the offset before the coefficients. The offset for points is 1.0. The offset for normals has the opposite sign. The data ends with an "end" line. FF Print facets (as in 'f') without printing the ridges. Fi Print inner planes for each facet. The inner plane is below all vertices. Fi Print separating hyperplanes for bounded, inner regions of the Voronoi diagram. The first line is the number of ridges. Then each hyperplane is printed, one per line. A line starts with the num- ber of indices and floats. The first pair lists adjacent input sites, the next d floats are the normalized coefficients for the hyperplane, and the Geometry Center 2019/05/03 8 qhull(1) qhull(1) last float is the offset. The hyperplane is ori- ented toward 'QVn' (if defined), or the first input site of the pair. Use 'Tv' to verify that the hyperplanes are perpendicular bisectors. Use 'Fo' for unbounded regions, and 'Fv' for the corresponding Voronoi vertices. FI Print facet identifiers. Fm Print number of merges for each facet. At most 511 merges are reported for a facet. See 'PMn' for printing the facets with the most merges. FM Output the hull in Maple format. See 'm' Fn Print neighbors for each facet. The output starts with the number of facets. Then each facet is printed one per line. Each line is the number of neighbors followed by an index for each neighbor. The indices match the other facet output formats. A negative index indicates an unprinted facet due to printing only good facets ('Pg'). It is the negation of the facet's id (option 'FI'). For example, negative indices are used for facets "at infinity" in the Delaunay triangulation. FN Print vertex neighbors or coplanar facet for each point. The first line is the number of points. Then each point is printed, one per line. If the point is coplanar, the line is "1" followed by the facet's id. If the point is not a selected vertex, the line is "0". Otherwise, each line is the num- ber of neighbors followed by the corresponding facet indices (see 'Fn'). Fo Print outer planes for each facet in the same for- mat as 'n'. The outer plane is above all points. Fo Print separating hyperplanes for unbounded, outer regions of the Voronoi diagram. The first line is the number of ridges. Then each hyperplane is printed, one per line. A line starts with the num- ber of indices and floats. The first pair lists adjacent input sites, the next d floats are the normalized coefficients for the hyperplane, and the last float is the offset. The hyperplane is ori- ented toward 'QVn' (if defined), or the first input site of the pair. Use 'Tv' to verify that the hyperplanes are perpendicular bisectors. Use 'Fi' for bounded regions, and 'Fv' for the corresponding Voronoi vertices. FO List all options to stderr, including the default values. Additional 'FO's are printed to stdout. Fp Print points for halfspace intersections (option 'Hn,n,...'). Each intersection corresponds to a Geometry Center 2019/05/03 9 qhull(1) qhull(1) facet of the dual polytope. The "infinity" point [-10.101,-10.101,...] indicates an unbounded intersection. FP For each coplanar point ('Qc') print the point id of the nearest vertex, the point id, the facet id, and the distance. FQ Print command used for qhull and input. Fs Print a summary. The first line consists of the number of integers ("7"), followed by the dimen- sion, the number of points, the number of vertices, the number of facets, the number of vertices selected for output, the number of facets selected for output, the number of coplanar points selected for output. The second line consists of the number of reals ("2"), followed by the maxmimum offset to an outer plane and and minimum offset to an inner plane. Roundoff is included. Later versions of Qhull may produce additional integers or reals. FS Print the size of the hull. The first line con- sists of the number of integers ("0"). The second line consists of the number of reals ("2"), fol- lowed by the total facet area, and the total vol- ume. Later versions of Qhull may produce addi- tional integers or reals. The total volume measures the volume of the inter- section of the halfspaces defined by each facet. Both area and volume are approximations for non- simplicial facets. See option 'Fa'. Ft Print a triangulation with added points for non- simplicial facets. The first line is the dimension and the second line is the number of points and the number of facets. The points follow, one per line, then the facets follow as a list of point indices. With option points include the point-at-infinity. Fv Print vertices for each facet. The first line is the number of facets. Then each facet is printed, one per line. Each line is the number of vertices followed by the corresponding point ids. Vertices are listed in the order they were added to the hull (the last one is first). Fv Print all ridges of a Voronoi diagram. The first line is the number of ridges. Then each ridge is printed, one per line. A line starts with the num- ber of indices. The first pair lists adjacent Geometry Center 2019/05/03 10 qhull(1) qhull(1) input sites, the remaining indices list Voronoi vertices. Vertex '0' indicates the vertex-at- infinity (i.e., an unbounded ray). In 3-d, the vertices are listed in order. See 'Fi' and 'Fo' for separating hyperplanes. FV Print average vertex. The average vertex is a fea- sible point for halfspace intersection. Fx List extreme points (vertices) of the convex hull. The first line is the number of points. The other lines give the indices of the corresponding points. The first point is '0'. In 2-d, the points occur in counter-clockwise order; otherwise they occur in input order. For Delaunay triangulations, 'Fx' lists the extreme points of the input sites. The points are unordered. Geomview options G Produce a file for viewing with Geomview. Without other options, Qhull displays edges in 2-d, outer planes in 3-d, and ridges in 4-d. A ridge can be explicit or implicit. An explicit ridge is a dim-1 dimensional simplex between two facets. In 4-d, the explicit ridges are triangles. When displaying a ridge in 4-d, Qhull projects the ridge's vertices to one of its facets' hyperplanes. Use 'Gh' to project ridges to the intersection of both hyper- planes. Ga Display all input points as dots. Gc Display the centrum for each facet in 3-d. The centrum is defined by a green radius sitting on a blue plane. The plane corresponds to the facet's hyperplane. The radius is defined by 'C-n' or 'Cn'. GDn Drop dimension n in 3-d or 4-d. The result is a 2-d or 3-d object. Gh Display hyperplane intersections in 3-d and 4-d. In 3-d, the intersection is a black line. It lies on two neighboring hyperplanes (c.f., the blue squares associated with centrums ('Gc')). In 4-d, the ridges are projected to the intersection of both hyperplanes. Gi Display inner planes in 2-d and 3-d. The inner plane of a facet is below all of its vertices. It is parallel to the facet's hyperplane. The inner plane's color is the opposite (1-r,1-g,1-b) of the Geometry Center 2019/05/03 11 qhull(1) qhull(1) outer plane. Its edges are determined by the ver- tices. Gn Do not display inner or outer planes. By default, Geomview displays the precise plane (no merging) or both inner and output planes (merging). Under merging, Geomview does not display the inner plane if the the difference between inner and outer is too small. Go Display outer planes in 2-d and 3-d. The outer plane of a facet is above all input points. It is parallel to the facet's hyperplane. Its color is determined by the facet's normal, and its edges are determined by the vertices. Gp Display coplanar points and vertices as radii. A radius defines a ball which corresponds to the imprecision of the point. The imprecision is the maximum of the roundoff error, the centrum radius, and maxcoord * (1-An). It is at least 1/20'th of the maximum coordinate, and ignores post-merging if pre-merging is done. Gr Display ridges in 3-d. A ridge connects the two vertices that are shared by neighboring facets. Ridges are always displayed in 4-d. Gt A 3-d Delaunay triangulation looks like a convex hull with interior facets. Option 'Gt' removes the outside ridges to reveal the outermost facets. It automatically sets options 'Gr' and 'GDn'. Gv Display vertices as spheres. The radius of the sphere corresponds to the imprecision of the data. See 'Gp' for determining the radius. Print options PAn Only the n largest facets are marked good for printing. Unless 'PG' is set, 'Pg' is automati- cally set. Pdk:n Drop facet from output if normal[k] <= n. The option 'Pdk' uses the default value of 0 for n. PDk:n Drop facet from output if normal[k] >= n. The option 'PDk' uses the default value of 0 for n. PFn Only facets with area at least 'n' are marked good for printing. Unless 'PG' is set, 'Pg' is automat- ically set. Geometry Center 2019/05/03 12 qhull(1) qhull(1) Pg Print only good facets. A good facet is either visible from a point (the 'QGn' option) or includes a point (the 'QVn' option). It also meets the requirements of 'Pdk' and 'PDk' options. Option 'Pg' is automatically set for options 'd', 'PAn', 'PFn', and 'PMn' PG Print neighbors of good facets. PMn Only the n facets with the most merges are marked good for printing. Unless 'PG' is set, 'Pg' is automatically set. Po Force output despite precision problems. Verify ('Tv') does not check coplanar points. Flipped facets are reported and concave facets are counted. If 'Po' is used, points are not partitioned into flipped facets and a flipped facet is always visible to a point. Also, if an error occurs before the completion of Qhull and tracing is not active, 'Po' outputs a neighborhood of the erroneous facets (if any). Pp Do not report precision problems. Qhull control options Qa Allow input with fewer or more points than coordinates Qbk:0Bk:0 Drop dimension k from the input points. This allows the user to take convex hulls of sub-dimen- sional objects. It happens before the Delaunay and Voronoi transformation. QbB Scale the input points to fit the unit cube. After scaling, the lower bound will be -0.5 and the upper bound +0.5 in all dimensions. For Delaunay and Voronoi diagrams, scaling happens after projection to the paraboloid. Under precise arithmetic, scal- ing does not change the topology of the convex hull. Qbb Scale the last coordinate to [0, m] where m is the maximum absolute value of the other coordinates. For Delaunay and Voronoi diagrams, scaling happens after projection to the paraboloid. It reduces roundoff error for inputs with integer coordinates. Under precise arithmetic, scaling does not change the topology of the convex hull. Qbk:n Scale the k'th coordinate of the input points. After scaling, the lower bound of the input points will be n. 'Qbk' scales to -0.5. Geometry Center 2019/05/03 13 qhull(1) qhull(1) QBk:n Scale the k'th coordinate of the input points. After scaling, the upper bound will be n. 'QBk' scales to +0.5. Qc Keep coplanar points with the nearest facet. Out- put formats 'p', 'f', 'Gp', 'Fc', 'FN', and 'FP' will print the points. Qf Partition points to the furthest outside facet. Qg Only build good facets. With the 'Qg' option, Qhull will only build those facets that it needs to determine the good facets in the output. See 'QGn', 'QVn', and 'PdD' for defining good facets, and 'Pg' and 'PG' for printing good facets and their neighbors. QGn A facet is good (see 'Qg' and 'Pg') if it is visi- ble from point n. If n < 0, a facet is good if it is not visible from point n. Point n is not added to the hull (unless 'TCn' or 'TPn'). With rbox, use the 'Pn,m,r' option to define your point; it will be point 0 (QG0). Qi Keep interior points with the nearest facet. Out- put formats 'p', 'f', 'Gp', 'FN', 'FP', and 'Fc' will print the points. QJn Joggle each input coordinate by adding a random number in [-n,n]. If a precision error occurs, then qhull increases n and tries again. It does not increase n beyond a certain value, and it stops after a certain number of attempts [see user.h]. Option 'QJ' selects a default value for n. The output will be simplicial. For Delaunay triangula- tions, 'QJn' sets 'Qbb' to scale the last coordi- nate (not if 'Qbk:n' or 'QBk:n' is set). 'QJn' is deprecated for Voronoi diagrams. See also 'Qt'. Qm Only process points that would otherwise increase max_outside. Other points are treated as coplanar or interior points. Qr Process random outside points instead of furthest ones. This makes Qhull equivalent to the random- ized incremental algorithms. CPU time is not reported since the randomization is inefficient. QRn Randomly rotate the input points. If n=0, use time as the random number seed. If n>0, use n as the random number seed. If n=-1, don't rotate but use time as the random number seed. For Delaunay tri- angulations ('d' and 'v'), rotate about the last axis. Geometry Center 2019/05/03 14 qhull(1) qhull(1) Qs Search all points for the initial simplex. Qt Triangulated output. Triangulate non-simplicial facets. 'Qt' is deprecated for Voronoi diagrams. See also 'QJn' Qv Test vertex neighbors for convexity after post- merging. To use the 'Qv' option, you also need to set a merge option (e.g., 'Qx' or 'C-0'). QVn A good facet (see 'Qg' and 'Pg') includes point n. If n<0, then a good facet does not include point n. The point is either in the initial simplex or it is the first point added to the hull. Option 'QVn' may not be used with merging. Qw Allow option warnings. Otherwise Qhull returns an error after most option warnings. Qx Perform exact merges while building the hull. The "exact" merges are merging a point into a coplanar facet (defined by 'Vn', 'Un', and 'C-n'), merging concave facets, merging duplicate ridges, and merg- ing flipped facets. Coplanar merges and angle coplanar merges ('A-n') are not performed. Concav- ity testing is delayed until a merge occurs. After the hull is built, all coplanar merges are performed (defined by 'C-n' and 'A-n'), then post- merges are performed (defined by 'Cn' and 'An'). Qz Add a point "at infinity" that is above the paraboloid for Delaunay triangulations and Voronoi diagrams. This reduces precision problems and allows the triangulation of cospherical points. Qhull experiments and speedups Q0 Turn off pre-merging as a default option. With 'Q0'/'Qx' and without explicit pre-merge options, Qhull ignores precision issues while constructing the convex hull. This may lead to precision errors. If so, a descriptive warning is generated. Q1 With 'Q1', Qhull merges by mergetype/angle instead of mergetype/distance. Q2 With 'Q2', Qhull merges all facets at once instead of using independent sets of merges and then retesting. Q3 With 'Q3', Qhull does not remove redundant ver- tices. Q4 With 'Q4', Qhull avoids merges of an old facet into a new facet. Q5 With 'Q5', Qhull does not correct outer planes at the end. The maximum outer plane is used instead. Geometry Center 2019/05/03 15 qhull(1) qhull(1) Q6 With 'Q6', Qhull does not pre-merge concave or coplanar facets. Q7 With 'Q7', Qhull processes facets in depth-first order instead of breadth-first order. Q8 With 'Q8' and merging, Qhull does not retain near- interior points for adjusting outer planes. 'Qc' will probably retain all points that adjust outer planes. Q9 With 'Q9', Qhull processes the furthest of all out- side sets at each iteration. Q10 With 'Q10', Qhull does not use special processing for narrow distributions. Q11 With 'Q11', Qhull copies normals and recomputes centrums for tricoplanar facets. Q12 With 'Q12', Qhull allows wide facets and wide dupridge Q14 With 'Q14', Qhull merges pinched vertices that create a dupridge. Q15 With 'Q15', Qhull checks for duplicate ridges with the same vertices. Trace options Tn Trace at level n. Qhull includes full execution tracing. 'T-1' traces events. 'T1' traces the overall execution of the program. 'T2' and 'T3' trace overall execution and geometric and topologi- cal events. 'T4' traces the algorithm. 'T5' includes information about memory allocation and Gaussian elimination. Ta Annotate output with codes that identify the corresponding qh_fprintf() statement. TAn Stop Qhull after adding n vertices. Tc Check frequently during execution. This will catch most inconsistency errors. TCn Stop Qhull after building the cone of new facets for point n. The output for 'f' includes the cone and the old hull. See also 'TVn'. Tf Flush output after each qh_fprintf. Use 'Tf' for debugging segfaults. See 'Tz' for redirecting stderr. TFn Report progress whenever more than n facets are created During post-merging, 'TFn' reports progress after more than n/2 merges. TI file Input data from 'file'. The filename may not include spaces or quotes. TMn Turn on tracing at n'th merge. TO file Output results to 'file'. The name may be enclosed in single quotes. TPn Turn on tracing when point n is added to the hull. Trace partitions of point n. If used with TWn, turn off tracing after adding point n to the hull. TP-1 Turn on tracing after qh_buildhull and qh_postmerge. TRn Rerun qhull n times. Usually used with 'QJn' to determine the probability that a given joggle will fail. Ts Collect statistics and print to stderr at the end of execution. Tv Verify the convex hull. This checks the topologi- cal structure, facet convexity, and point inclu- sion. If precision problems occurred, facet con- vexity is tested whether or not 'Tv' is selected. Option 'Tv' does not check point inclusion if Geometry Center 2019/05/03 16 qhull(1) qhull(1) forcing output with 'Po', or if 'Q5' is set. For point inclusion testing, Qhull verifies that all points are below all outer planes (facet->max- outside). Point inclusion is exhaustive if merging or if the facet-point product is small enough; oth- erwise Qhull verifies each point with a directed search (qh_findbest). Point inclusion testing occurs after producing out- put. It prints a message to stderr unless option 'Pp' is used. This allows the user to interrupt Qhull without changing the output. TVn Stop Qhull after adding point n. If n < 0, stop Qhull before adding point n. Output shows the hull at this time. See also 'TCn' TWn Trace merge facets when the width is greater than n. Tz Redirect stderr to stdout. See 'Tf' for flushing writes. BUGS Please report bugs to Brad Barber at qhull_bug@qhull.org. If Qhull does not compile, it is due to an incompatibility between your system and ours. The first thing to check is that your compiler is ANSI standard. If it is, check the man page for the best options, or find someone to help you. If you locate the cause of your problem, please send email since it might help others. If Qhull compiles but crashes on the test case (rbox D4), there's still incompatibility between your system and ours. Typically it's been due to mem.c and memory align- ment. You can use qh_NOmem in mem.h to turn off memory management. Please let us know if you figure out how to fix these problems. If you do find a problem, try to simplify it before reporting the error. Try different size inputs to locate the smallest one that causes an error. You're welcome to hunt through the code using the execution trace as a guide. This is especially true if you're incorporating Qhull into your own program. When you do report an error, please attach a data set to the end of your message. This allows us to see the error for ourselves. Qhull is maintained part-time. Geometry Center 2019/05/03 17 qhull(1) qhull(1) E-MAIL Please send correspondence to qhull@qhull.org and report bugs to qhull_bug@qhull.org. Let us know how you use Qhull. If you mention it in a paper, please send the reference and an abstract. If you would like to get Qhull announcements (e.g., a new version) and news (any bugs that get fixed, etc.), let us know and we will add you to our mailing list. If you would like to communicate with other Qhull users, we will add you to the qhull_users alias. For Internet news about geometric algorithms and convex hulls, look at comp.graph- ics.algorithms and sci.math.num-analysis SEE ALSO rbox(1) Barber, C. B., D.P. Dobkin, and H.T. Huhdanpaa, "The Quickhull Algorithm for Convex Hulls," ACM Trans. on Math- ematical Software, 22(4):469-483, Dec. 1996. http://portal.acm.org/citation.cfm?doid=235815.235821 http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.117.405 Clarkson, K.L., K. Mehlhorn, and R. Seidel, "Four results on randomized incremental construction," Computational Geometry: Theory and Applications, vol. 3, p. 185-211, 1993. Preparata, F. and M. Shamos, Computational Geometry, Springer-Verlag, New York, 1985. AUTHORS C. Bradford Barber Hannu Huhdanpaa bradb@shore.net hannu@qhull.org ACKNOWLEDGEMENTS A special thanks to Albert Marden, Victor Milenkovic, the Geometry Center, Harvard University, and Endocardial Solu- tions, Inc. for supporting this work. Qhull 1.0 and 2.0 were developed under National Science Foundation grants NSF/DMS-8920161 and NSF-CCR-91-15793 750-7504. David Dobkin Geometry Center 2019/05/03 18 qhull(1) qhull(1) guided the original work at Princeton University. If you find it useful, please let us know. The Geometry Center was supported by grant DMS-8920161 from the National Science Foundation, by grant DOE/DE-FG02-92ER25137 from the Department of Energy, by the University of Minnesota, and by Minnesota Technology, Inc. Qhull is available from http://www.qhull.org Geometry Center 2019/05/03 19 qhull-2020.2/html/qh_findbestfacet-drielsma.pdf0000644060175106010010000014202013503037663017721 0ustar bbarber%PDF-1.4 % 4 0 obj <> endobj xref 4 60 0000000016 00000 n 0000001742 00000 n 0000001839 00000 n 0000002020 00000 n 0000002280 00000 n 0000002366 00000 n 0000002661 00000 n 0000002698 00000 n 0000005770 00000 n 0000008982 00000 n 0000013729 00000 n 0000018491 00000 n 0000023255 00000 n 0000027977 00000 n 0000028047 00000 n 0000028144 00000 n 0000032524 00000 n 0000036817 00000 n 0000036917 00000 n 0000037018 00000 n 0000037126 00000 n 0000037226 00000 n 0000037302 00000 n 0000037372 00000 n 0000037470 00000 n 0000037574 00000 n 0000037679 00000 n 0000037781 00000 n 0000037890 00000 n 0000037985 00000 n 0000038088 00000 n 0000038123 00000 n 0000038406 00000 n 0000038696 00000 n 0000038987 00000 n 0000039254 00000 n 0000039524 00000 n 0000039794 00000 n 0000040066 00000 n 0000040410 00000 n 0000040723 00000 n 0000041020 00000 n 0000041391 00000 n 0000041824 00000 n 0000042097 00000 n 0000042414 00000 n 0000042835 00000 n 0000043162 00000 n 0000043432 00000 n 0000043705 00000 n 0000044061 00000 n 0000044387 00000 n 0000044711 00000 n 0000045036 00000 n 0000045410 00000 n 0000045897 00000 n 0000046157 00000 n 0000046225 00000 n 0000046337 00000 n 0000001496 00000 n trailer <<6C986A5B1057744EB189FC0FDE6CB45F>]/Prev 49983>> startxref 0 %%EOF 63 0 obj <>stream hb``0c``du Y82:I xY&X8 80eL3/e3G&!& 81I5T800?`u߅Y- x L$&1=)"ja p n %p endstream endobj 5 0 obj <> endobj 6 0 obj <> endobj 7 0 obj <>/ExtGState 8 0 R/Font<>/Pattern 9 0 R/ProcSet[/PDF/Text]>> endobj 8 0 obj <>/ca1.00<>>> endobj 9 0 obj <> endobj 10 0 obj [/Pattern/DeviceRGB] endobj 11 0 obj <>stream HֻlgW;{9KcUk~ys9^uO^~>}{ϟ?v?/p__OǾӏ<7?c{˶eoaw2X7?u^oX؟u]wz=_y_~;zN=r^}nfv]/<ߝͿmےk\X?g_[㭾}=og(|e(Y?@@Y>Pخ)]uyu_^ʪDY!QCDYd=$rH(CDY e9$zH({ov{{r?uRکʵcv\;Uv!c6NYv)˵c6NYکʵc6NYvr͵c6NYzݺ?nv~+K\\rTrɍ}.\rdrɕ#%WK\\rTrɑ+%GK,\Y.9^rezɕs^Gq՞ ((AթQ6SS,Sc3525:52525:525:5fjPujejujejujejejujejujsuj?uYzZac6æ,l1l2l̎aSac6ÆlMY 6e6f3l2l̎aSac6æ,lMY 6e6f3l2l2lfؐzD!ugYgTYfYgTYfT(ΨQTQeQcUEUUEUEU633,33,33,3,33,33̟3,3j3ymt e u e u e LH&Ӂ6ygCfBfCeCeBdCdBcC3d:ņ2Ą:Æ2„:22:2:y:2>k(sKhSws}^{}xuؑuڕeܑuޕeuẹ+GձW7|e|d}e}e~d~edeȚȚʒʒʒ>q,yl߮. e f$$&H%HM0;DU$$&H5HM(K0 a6A,AlDY$$&H%HM(K0 a6A,AlDY?W  e f$~kYGYYGYYGYYGYG揲TecQAQQAQAQ6,,,,,̟,c?ʒ?Ț?ʒ?ʒ?Zn^u֫m.RBRBRBRBRR6lZ U[KYZاMkjk)Kk!kk)Kk!kk)Kk)Kk!kk)Kk!kk)jk)KkOGce*elNYʎٔ);e);fSvRv̦e*e(;U);fSvZv̦씥M1Sc6e,e(;U);fSvRv̦씥M1Sc6e,e̟+elYˎٔ);fSvRv̦8RvuoZvZvRvZvRvZvRvZvRvZvRvʦPM١j)K);T-;e);d-;e);d-;e);e);d-;e);d-;e\-;e);cSCֲSSCֲSCzyݑՎxqG*DՎTD֎TD֎TD֎TD֎TT6l:U;RY:ا########MGjG*KG"kG*KG"kG*KG*KG"kG*KG"kG*jG*KGtt$vtt$vt$v+2r __le{eVeVe&ZQ5ZMj*KDD+FDD+FD+FVTVeVdVeVdVeVeVdVeVdVe\VeVchUhEhUhUhEhUhEhU6ъ˖h]ooVf̎hUhe6Ѫ,lUYDD+VeVf̎hUhevDD+VdVf&ZM*K2hUhevDD+VeVf&ZM*K2hUheϕhe6ъlUYD+VeVf̎hU{ ~i"#k"+K"+DFDVDFDVDFDVDFDVDFDVDV6lUYY'%5%%5%5M"j"+K"#k"+K"#k"+K"+K"#k"+K"#k"+j"+K"$$2&$$2&$2&IdTMdeuZ֯\aee,elUZYYZYYZYYZYYZYZٔ5)kT-ke)kcVFֲVVFֲVFֲV6ee,ee,ee,e,ee,ee̟e,emSRZRRZRZʦQqGכd_?'șM+K3 gv9 re rf&ȕ%șM+K3 gv9#U%șM#k3 W g6Al\Y9#U%șM+K3 W g6Al\Y939 rd rf&șM+K3 W gv9 reh>+n endstream endobj 12 0 obj <>stream H=kѭQQUlp }>Mmi(FqQWOOoy$6/{ZXz\A^eWu>.t?xֱGk]Z:fuyW{xֱ:wuWkZ|Zs_mm:}$=|{g5ήyΙxKk|q3KxօkK{m,m&?#gkϱ};Ӽs윎ز;od9od9,翱>7?GYGV翩>':7?rYc}#TrYc}#,翱>7?2_}#Ou#od97?GV翩>7?97>>,翱>GV翩>7?GXrYduYGGXr#od9S}#od9,?GX},?,翱>GXrYGX?g3?Ͽs|k|XR[m>5 ߿d2,JYJEYgJ(RARQV,JYJEY *eRARQ,T)eU*ƺTU K(RQV,JYJEٳTPTU K(RARQVJYJEY 2_)eU*ƺTU K(RQV,JYJEٳTPTU K|T)Dz;Ώg gS=1b?8"d"cEEƺU.B.2],]dYXwt"d"dEU.B.""d"cEEEƺu!.2],]dYXwtt"d"cE}u!K{ut"d"d"cEEƺU.B.2]s]dO]옖Oܟ%ħ䔱)d)cSȒS*LuN!KNB29,9es YrX)SS*LuN!KN{䔱)d)d)cSȒS:UNB29,9es Yr YrX䔱)d:%r YrX䔱)d)cS*LuN!KN}Y%);uN!KN!{ǿʯw_瘰ۯuvxSV, YMYśgJ)xCxSV, YMYě7exCxS7T7eo:ޔU!K)xSV, YM3P%ޔU!K)xCxSV YMYě2_7eo:ޔU!K)xSV, YM3P%ޔU}:)oo*ޔU!n>|śثu!KCCVgYX74n>di>c||ƺUCVgYثu!K!KC3͇T74n>di>c|||ƺu!͇,G||ƺu!KCVg[ўYX744n>dtoIk"W*"K*TDT4֩,RT"NEdIEcȒ:%u*"K*"T4թRT""W*"K*TDTDT4֩,hSYNEdIEcȒ:%%u*"K*TDSYR+%u*"K*"K*TDT4֩RTٗ=e"NEdIEdIEcȒƲ[gw6OuraTV, Y SYgaJa*DTV, Y SY&*LeDT,LT)LeUƺ0Ua"Ka*TV, Y Sٳ0Q0Ua"Ka*DTV Y SY&2_)LeUƺ0Ua"Ka*TV, Y Sٳ0?P_U)Ld)LeURʪ0Ua"Ka*Dp0}O:^z\ -Sc^a,ajYX)) SS:L%Lu"K0E05a,aT) SS^a,ajYYX)Sd:L%Lu"K0E0E05a,ajSd Sb0E05a,a,ajYX) ӟ/S{Sc:L%L%Lu"K0EvOoٱG9ks+g%gu"KEEV9ksYrX,䬱YdYcȒ:g%gUΚEV9ksYr+g%gu"K"KE59rT,䬱YdYcȒȒ:g%gu"9,9K앳Ȓ:g%g%gu"K90ݮW"KE59,9,9ksYrX,YScm8$ҹ~cr-8ܙ] Lbcy񾽌-+96ydYq|ji=Y|=go!ccާ?8'-dll56~4>[c~cʮwl {.>[cZ|HƂ=_`{k} 㠼Wu~hcm:ɣu[0ngk<c{k?}n_ci?˟kKy7΋kӺ`mci];XZߑzOƒ}a'~}l5e?&M̀iXؙXJ iH endstream endobj 13 0 obj <>stream HnE1E%5"gݓ($6Q}5Dz_>mx^[~ܕa7foӗ^{mB/y)Iج+F,[Y?k=0~?ws-vOv,N\6ݏZ\ mEx,#G]2mˎBbYYcX:[F°aj,[au >o }l-W9 @[/;WF+VV2Z R o i.@[~ָڊE0φ2tg$:[:[xZg߅ JK8[.CZ=2Xd J5%@"sdƱ?wҠeZ.do~٥?3ȮBf2:Ȯ$[zLd[gٹ?uL";Id7s/]چ\Ry~#)^jrm=}Ǧ\0e%/r$ת 2vN\6?_R$۪JY$m%%&ޘZ\l95ieHk=M-t^nkl0lѣu >o }l-W9H'dmesemUhVdmg[{do~hKf+Ж}65blB賡 -R:h+)ު:w!-eei1NEːV eiMH+q`-|]o }l-W9H'dmesemUhVdmg[{do~hKf+G ml:[9lh+CgzN2ʫE u]Hz DZdiѸ2#E"pDZS$Ҋ_E&Ͽ ٴ'$q d"g&ɐ]dV5t&]]Idn$s=&ԙDv> @v?ElmU. Mϑ֢E OY{n~e OF~Ro26N\6ݏZ>emeXY$ݣ%&=&ޘZ\E+$|R, ])2M-@>[Ex SˆD0:[tv:$eB~5[G oŕA @[\@[2ZA-hk/@[+[6 G ml:[9lh+CgzN2ʫExu]Hz DZdiѸ2#EpDZS$Ҋ_E&Ͽg ٴ'$q d"g&O}2dW!3t IdWWg-=&ۭ3\ϟ:u&~ϽDvQ:[ghrK=HmsdEy1VFEgktajِFg.Ю5\qyXۏfh᭸2A8!h+[ +hRF+em%hk>#xF[]2[賡q-[g:G mel^IF[yu7tVѿ i1P//Hq"-\zd.HkXxDMxB7}Bϟǎ@&K=f3]dV5t&]]Idn$s=&딥Gg ٍKdu!Wԃd6=G#Uk3g/^˜\M֬î<.ׯ6.cGJUωKe.ll{cF/kۏ`2w{g4x,|Nxckrc̖VF8/\`2M-賵Z:[40lEhٚkCQv,[uV\y -[ϕ U)d2Z R o/: ćxMZt8ʛވhJb:$xF[2[lVly{VwN2ڊE置tF.B} V 2Ɓny iU` V )wYCR#xJk<3|֘ d gD/~K,RCgՙdg S:ȮBB ;k-d^ ;OibCwɸ.FF+aw6/at&`V|nಆ-:D?)=99qi3]):fY;[ujcf뗛$tȯ|S0£Ȏ2[FQG1$M9jc -~neko-LkGle:[} fV-W q-G[Q9]y -+ߒrunx̖-OmUl9ڲwC[m:[hˏG mly$:[t:[x+KgkBZ,`Ҫ-cHǐV }kR4޻u Nٹ?g@ Fg t"5t&]^Id$3Bv:[ȮϽ@v:[Ćk5]a]ޭJYn2: dz 5&.Ke&#ЙDvyu&g S@n?Ul!;k-d^ ;OibCwɸ.FF+aV:Zx˯ U2Zgsj -aߒrunx̖-OmUl9ڲwC[m:[hˏ G mlѰ$:[4:[x+KgkBZ,`Ҫ-cHǐVw6un>k5]a]ޭJYn2: dz 5&.Ke&#ЙDvyu&g S@n?Ul!;k-d^ ;OibCwɸ.FF+aV<2Zi&m=%Î}P $ǫ捻GoF;˿fev<똍:Ə{m^>stream Hdl 惙^ ~_Q5 SNcyё=XV±ʴ2[2eN7YcBm:[F߭mejlbyrر_?ޚ Vlق wVJkem%hk#xdmwC[:[h+V\KIfy^- -UuBZ,cei1N6X|5J~/Dv=2n,\2ݔم?3Ldzg" ɬfjL":n3n-dzLdש\>:[n^"(3 9R/yY.VB[e\3"ɵ1'$:|^.X|z> ;˯cǪ^XJ1@%ƶQcq۪cm5}rL+X/X]S 2[NϔIi&Z wSg Wnkl1Fg ٵla.!A\}> :Zx+ r0Nhʖ-phڪ m@[{hZlrk.@[~ָڊE12t(g$:[:[xZgυX`%=Ƌ8~.' VW{Md@rpDvSKdz8v\2]3sL*d&3jMdns&zHGg ٍ~Kdu!]E2o# ѪY UhVyٽ2Zv|C:ƞ\O0^29,AzurXՓf-_wv?j '|X~1n$J<U``kr8Wf9d$e~9<F߭b0>al1u0 >Ďl-W9'dme semUhVdmw[{doVV-?nhk\g m٢wC[:[uV^- -UuBZ,cktFŵښȮ";Cv=2,\2ݔم?3Ldzg" ɬfjȲKdWWg -&ۭ\:u.Jg cCNԋd6G#Uk@FVm{e m/td=E?6z`ӽfWߧG|/lw ^_-ǎUhbKmpoX~ -n$J<U``kr8Wf9d$e~5<F߭b0>Z`l\C|;[uV\`0 -?[0ϕ U) 2Z R o F[]2[軡q-[g>?G melIF[yu7tVџ iP sq>abЙIkk"^2r @r&pDvSKdz8v\2]3sL*d&!.]]-dns&Bv>:[n^"(3 9R/yYh+VB[e*ґ?YO_^}r~~zubXՋd!t/K m05Զ_C ~{ XTU;CpBZa)r~+}NGϯxPB *Euv[K\9*Ev"l*Ȩ: EUpQ\`ĝ! T->S0! TT)B"D! TR ) \EE]"E;q"T[=G eѽVyEEyU7TpQJQТ8ͯ 4z5/@`kD!OƠCGD%?U"PaƱ"zR퇙cj=LV!2_U)B`K퇉v!0Wa"N"RF=n%R): KmS^<"DX"Dj+BTh Lp\_Ƭ}͍/O|W~'^~/咬(ni{ 8ńIV鬪wi tcQŲ}~RDs_<$[/rɹ2[NϔI̬CRmE^諵/3-2u:6T"7u0 >?:Zx+ r^o r\@[2ZAޖ MF+Ж#xdmWC[:[h+E٢쟭lQoljwj} NiTދd ;@&kOdGcȮG Ld7%...9K*dBvuu3n-dzLdש|tǽDvQ:[g y o^${d<2Zed mՖ*uVڲJIdclհ*/_-Uhc`yKݏ:J}Xq}ioyK<+̉V+Z"Nl9gLd*:?$ze8F"OkڗyM:l:[uHW }l-W9Whc2Z*e<-hkV-K}5Gf+omul򣯆uVl-sVǀuV^-7tVn5>4zkE2 Old ٵ'#1d#Qj@&Ldz2RȮBf+I -dWWg ٙ?BvDv:[Gg ٍ~KduؐVE2o/G#UAFVmZh!-hY4M;'>^}*N9NN'Pyjy쬪O .ylv?*YVOhc뗇$O{[at^8`N]q:Wf9;d$Si!9<ԓ9yzSg:[n^"(3ĆuVf9K*TdBkueК}2n(rL)|dǵDkQ2PguC a!<*OeT AVy*uS!Vy*I##kI3^c>stream HnM_'  CS^Ȳs+K;ٝ^O>zjܕX7f^ye^}"kveZeg uLW. ZewYe=2[g+VV,?n׸[gmw2tuVޟٲug>?ll??Lr~Ȏz,Dvm2d @& Ld7%Dvn2XX !W! &5t]]-dgvl!;7ddש|t֘VbC[|zY/,GFl@FVmZh!-kB[DGN&[<կo:Zx+ r'd-?[hڪ bVm2Z,[m%hˏB[u軡 -&Aqi|O͵ W:L7t&g')_6c^6 d"6d9/!H&.nJ~B? V"YzȮBf+I -dWWg ٙ&ۭ\?ul!--5H+Jg !Wɼ>VB[ek+Uhk|e m_FKYw 5[ CU ӓ'>W<Ty rS m*O,0P.dեʏBPe {! (f-hΑA|O͵]T 2L7d1[ ?dBjDkm*s 2MpDkS'Z L*MR'3gd &dZ](fr?hm ZsL)|dZ(3DZR BPyT6 T AVy*uS!Vy*'[>O({k,387 -Uhe@|K.ݏZrq|rYIbz& x'h+2tG~Mb{Sgԭwk_f:[L,"yu0 >o:Zx+ r'dme$2Z*e -hkV-K}7Gf+omuluVl-9nh+gfb>.iwN\9sL2iЙw:G.dBl Dvm2| @2xpYv.39`%K̜*dBvuug":[3VBZ{trJK# m*,*U[Fֽ2Zv_hZFEi银Ir>(O{kCe:}/ѡ2%G-C%j^}s,-/sӹ2[Ohei&o:Zx+ r'dme2Z+e<-hkV-K}7Gf+omuluVl-ƀ9?ftk؇m>^&]$L2>Йw:G.dBl Dvm2| 3JpDvS Hdz e٥fDv2[YMjl!:[3n-zHSg il!ǽDZQ:[g oHhmhڪ-U^^B[;/e-Uhk4=>ZI4|ncP.۫_aK6)CHe`yK.ݏZJe9Zz&y׽#0z^8`N]rq:Wf˙<=$C=7u}eE>IJa-]gkr獲B?~5[G oŕAVlق<=WF#*e<-hkV-K}7I+K' XkS(@IdireF[2[gC[m:[hˏk@g۴؇->|8 יd}G]$ø$ҙ}!;ǚА dW[?/!jV&ȮS~\pM+]3^?٥lErtg S:[HHBg iYl!׽@Z:[ y o^$cj=2V\܇dmJ5#hmJuI\4|5} |/|=ch,c|,OGJu1YgN:ҦWHQ"O]?,/u{T5#^M+dW8iS -8z@aT} [&ճLFEէrc>2OGe *Orʓ#(Ijʓ#UAυN@92%#J(GPvs!6(+P2SyƇۆN L#CbdY%e1[ q<Ja*su U4N-7@kr k*MB:h-]*H(#ֶ'=BO&@O2PZ =z򔁺! r3%DPqUrPyJG)-׌S"OK)ԑ$]rY|ij#({_z_pF ㅲ:d>4ӕXcv1v>V<_.#?M_sg%OAs̖FL{KH6|I#s'tll&5 Jle:[=tHWr>:ZxGى2Z{s-J emφNl92mJ-G[vlmrn-> O~{oLdտt3ɚqIqI|3yBv5!Ȯ ;_Cv2X]M+]ٹ? V gD/~Kي,RCg l!@Zt3VҲBZ{1O?^)GHc<]):fW@kgcUژ":#1Te`H+Jy1*YjWcf뗋$Oȏ|]`fySps9yzKH|e8FNl:[s8lMEl,!!N0vo[>2N^r%ߛwdm;^em- i-[mUMrM % ({p;_%kәDw~t&YgCw:_љd}O&M! endstream endobj 16 0 obj <>stream HnmKE1AU_@ )"s~5܉eiTXcV|cY}oXV?"æl1{Ϗ0vȍB=6X.^ڼBcS]/ ׭ǎr,XƎYUlenuuvJ}^[gIk:[S棳5fiElo o걶# mѪY UhVyٽ2ZvϿjB[껡-ZY?k=_~_9V|ۺO,tɱ~*U9Z޹HH<_]Sp9wctOOYctOolѧ5n},c_uv:$i7bBxkފ+ @[}zV-zG]W@[{hZl<ȧF4t=o8]d;?:n\g֙0G eLr|8[]^I7t&] ٱP !Ȯq"; _!,R.nJ~B?qDvϟcHBf+i -UWg i-}L[g i>&BZ>:[Hk^"(3_NɼmYh+VB[e*C~Vhiߣ"5TM(W:3o}牋Cz`yKmP=ֶbEҧGⱘ]9nע\zX>Ers}zSg>wktg[El5!N;[uV\OOhʖ-sem;z2hKF+J}7{e6.&;>ji/~ܥm\uLu&]lIs]$LJ/ՙpCgU˾cJC+]/DvCv=2X,\+ݔم>&2XR?33VVV:[HZHkr}Lթ|tǽDZQ:[gп[y9VZ2Zjh+Uhk mѪx-wC[ߣ"5MW:3}9C#(O,tɱ~* ɱ1n\$}[~$U~ov-ZNܭǎs}zZH1F٢Okm--Y&Ɔ#lѧ:[suH>oĎl-W92Z{ \@[L2Z 4.F4 j>b=2vt%3ΏיDwu&9>wCw:ֿtWg w:[G/dB=6 V"^2Ɖ(|9zd8JY V")$ }Lei>fg" 5tV]-3n-HSg il!я{tΠ9R$sd<2Z6 d mՖ*/WFZ-Uhk'y~b"76s__p察;ӯ-?Rzq5l豶sw.b-?zX]S6wcO4_Oyh1XnklQ216FgblٚkCB/y#v,Ǐfh᭸2A1 -[Phڢ@e h-e~] M`ț7}@w+w{d&߹N 뒙 tG ݍL:軡 Ig_+.8w:[G/dB=6 V"^2Ɖ(|9zd8Y V")$ }LNei>fg" 5tV]-3n-HSg il!YFZDؠ9R$sd<2Z6 d mՖ*/WFZ-Uhk'yd"̈76__L察BP|?Rzq5l豶sw.b-?zX]S6wcOzCQ7u(}v[Kgb|d7:[c\szc?~5[G oŕAVlނb6 V"6c._Cv=2XV V")$ &2XRHBf+ҪLvl!-g"N-壳׍tΠy o^${d<2Ze2Zjh׺WFڲ*I\jD֫fNڦ\zǫ;j_Oj^Im}r$\?)&>Vk e'1~zR@#nlp5nLg{cÁptHvuH>?'fh᭸2A - ;Q, G6k*tGwy2Hww{d&߹N 뒙 tG ݍL:9n.CgB,@wyu(7t]c>6 V"6c"1d#f`%Қ_@"gR`%Jfg" :[H2&ڭ\:u_7Ҋ:)zKhmhڪ-U^^B[;_hZFC"N'mIJ|=Jmd>X,z'1Mp6FXv+Z[;+HMRIm}eE=ı9:[$\:$\ puV\ NhlݙFvͯ{ڻd:[HkLH+Jg VE2o/G#UY UhVy{e m퐟-kB[[t-D֫Nڦzǫ;⾿,cژ&I~R@ M^}-OAܭO hc$i&6F⣩wk_f:[$ܳLEµl]CBa?7[G oŕAwlݙa6~.@w3 \@w$>v2Hww{d&߹N 뒙 tG ݍ˺{u:[9n.CgBN2˫Eu !4dٵ'"1#f`%Қ_@"gR`%Jfg" :[H2&ڭ\:u_7Ҋ:)zKhmhڪ-U^^B[;_hZF{$ry~Gh“i|c{Q+]h{@T1wZű0jjM]|ʗ1~z\#nlU5nLgzcstvuHH>?'fhѰ~֝_>i{ڻ;!#.[~&Aĝ+#(.RF26@wnnd;uKf2Н}7t7bl軡 -:.:Bv,džАJ&cHǐV .HkJ~BI/?.H+9K*dl!:[HHkr&BZ>:[HkLH+Jg VE2o/G#UY UhVy{e m퐟-kB[[t-D֫BOڦ8zǫtYz sm̝VxDZ_XKQ endstream endobj 17 0 obj <> endobj 18 0 obj <> endobj 19 0 obj <>stream H1, Ҷ xZW!gC ZGWv?ov/UJ/󲕯nk}y庙\'N>ǿ^՞z./9=6+b˱5ruXl}lY21ֶu:WmkLf>F5D__ޮ_pk\FҭVL|ۚ+# IwݒttwLFѝ;-3n맍*e9ۣzl;?:[eG ݅l]st]\l, ٱP5CC+Vq -CZ2X|` ǭf͖ :=Ke" l!:[HHz Uvl!64Sx+"#mhh%#WF+q'ڲJuI\;~<ݼ;зyKROj|c}QukiΪGZ̍ZxXv=6+k1FՔ'\1nl1j/3-FճL5Ũwm&Ub׏5\@m}q1H/3e$EH:#n;FJIGwd$Y2~Rf}7t[g ٢軡p-dtWgf~]g el~_Hz2Xdi1Ҫ+e )@ -gg` F\ ilEBZyu3)-HBg iBZmq#-Oi/VE2n-G&ڊJ;,JGF+w{em-+D[=nvhռnm(O)'qނ;v-ߛ6zz VQԮS̎G͊`cJ4| V1:te qIGwQ9Cg IgܒttwLFѝ;-n맍*ewCwuН-r ٢+IFwquu]Xǚ!HL8_!j,o@ZrMy V g}\ ilEBZyu3)-HBg iBZmq#-Oi/VE2no,E[12Zi2ZhuVOe%h|G#}׭m_^3<#XOn-ߛ6zz(jW%]^rYV1@ZϠ)ϖ z@Z2[uV^-ez uJg imҪBZuV~HSgk)(`D[ydrWF+q'ڲJu#aV6||yo)\-kn-g cJ-Fz,y?./9{جxLŘScJ-zV[ex[u͖kh0'[ߵu5?r}t$)~2N鍒͙se$eH:㖌cY2[~Rf}7t[g ٢軡p-JdtWg{]g oel~_Hz2Xdi1Ҫ` )@ -[͚-H+Ke" l!:[HHz Uvl!64Sx+Bmhh%#;׽2Z?іViv|tءU < _^ao {Kn.ZǔZ̍uXvb=zlV96Jw{ϝ+ԺϟAlLI|4ɹKHIj| Ot kiY{\exZ&e]u~7O--wfےm:Ʒc|Җo-Cm[1^.ؔ\%-1&i#y \*a86 ?~1d-I+6ߖU%>$ϟ.i ےےf[ҲZSǔ@{~ iVԮ Bڊ-xZ!mux?o27/EXa1K㈟li]l`J~sL?%0 v !u*&noY9&Zzy^0&%&.K^*|:O&1/{?`CfxZ2y<-z2:|'ޖw?mnޖIwmIwmI[tMryrudi7ߖΓ|[/IKrlJxX.ig쒖^ٺXrIk~.iqsl\u?] ?ߖoKҪV|[VOmIZmmIZ-iYm)cJr~ = ? O+jxZ!mEӊeo<H[u7l?fwӁhB*kbf!5Ա0R>9vjbY;5 YGB*kb5 YeحYX,NR,IJf)vjbYYHeR,IJf)vjbY;5KS˚ةYeRYeحYX,NR,IJf)vjbYYHeR,IJf)vjbY;5KS˚ةYeRf!5KeԭYX,NR,IJfR SY ?Y)o2f)2Kvb Y R,eR,eRe"3K!Yʰ,Xf)nB,a7K!vQ7K!Yʰ,eReB,a7K!Yʰf)2K,eReB,a7K!Yʰ;Yʨ,eRe2f)2K!Yʰ,eR,eR,EgB,a7K!Y R,}m:C{ Y R,Xf)nB,a7K!Y Y Y R}f)2Kvb,eRe2f)N2fw? 0b endstream endobj 20 0 obj <>stream H׽EWXbNN,N,R!{ۄ`ij6E~߿~}[y?^QFz_l5ג_6^?d5m=uھGkuGF8e˳lg#oUǹ#w<򞶶75Oul*-[GE6>lJ;ɶh-ZeVE(|nn?lݲgVZ[SvSزU*Z%mN<-[jKn糱ehf+hg}+vV;V:mvF~>yV $ov^Բx"O^rvJ2&Za+lxjTwa~c=>n?-{[5𰽟m9'[3~vԖF>ʾÐ}j+tC<ٻh:G`  FOs?zmƾi|v{aМuЖAi~1m}Ҟn<:V[Иo7? ߦASj mit?1n}EӤIvGJ,is ic0ݡvf"w}[۾غWϟSSZ@D}aH{lOs>:fK~{#w< wU뗛"֓֙[O+H{2xL_Ga0(z=svÐΕ߬m\KVeG;o[|<ʰ*Z z`n%F99ͳkAIfm|>G|K{/}i/_?|{'JrO>w函O{O>.ŗJf0;慘zW6}Ojg+O֫emC`qOYo}ߧ!bi,4ovn ×} U?÷).?D u.l(nڪn٪}AoT9-KnCqj˺[OM@+xK[OMv".n=.3)3.=#~q:/矯0O}ܷwV]ce|slCql-S.ɒ,d@4,E/hY!:A!V̨X+ %Mq2^!uX}۰:bYE>{WX"3k)B, :sRzWXmkֻ"*atf!VƗѪ9QerRXRpߪeuX1 5ػƶsZ+GK^b:WIJCqֽ"Ξ" Hy턮!VN)Z+El v)B,ѧ-yr2.F/z9}ǵ7""Xk{9y=n]Tiqw\x>n ^qך k'>zƶCUhȼk`;iN >RIJF­"˜FkYg̛d> endobj 22 0 obj <> endobj 23 0 obj <> endobj 24 0 obj <> endobj 25 0 obj <> endobj 26 0 obj <> endobj 27 0 obj <> endobj 28 0 obj <> endobj 29 0 obj <> endobj 30 0 obj <> endobj 31 0 obj <> endobj 32 0 obj <> endobj 33 0 obj <> endobj 34 0 obj <> endobj 35 0 obj <>stream H*2TT2P0P04Tp<P0KP(mke`ei rA 1e !2@N0W @|c endstream endobj 36 0 obj <>stream H$1 0C"G+PtP7! ΍0JONpf䌜 +hU/~VePL# `: endstream endobj 37 0 obj <>stream H$1 0C"G( 88Jt!NgQ:fY \+**Dls'Ƽ.>ϣ endstream endobj 38 0 obj <>stream H*2TT2P0P04Tp<P0KD(kVS` endstream endobj 39 0 obj <>stream H*2TT2P0P04Tp<P0KD(kQ" r endstream endobj 40 0 obj <>stream H*2TT2P0P04Tp<P0KD(ke R @js X endstream endobj 41 0 obj <>stream H*2TT2P0P04Tp<P0KD(k65P)2r = endstream endobj 42 0 obj <>stream HD0 DwL6Q|CPuk+$ص"x+%VZ.jdx({]]|J:՘JgJD#=k鉏Z75Șx=osٓG` X1} endstream endobj 43 0 obj <>stream H*2TT2P0P04Tp<P0KD(k65PRFFz&,deng5,b$@`9H6 &, ` @ endstream endobj 44 0 obj <>stream H*2TT2P0P04Tp<P0KD(k65P)2r \C dN.L…5j6X`7 endstream endobj 45 0 obj <>stream H\10 Ewip^u`@l0(,\;vڡV;HF'TU>UƵ5=ƓIm&fZF߅OٌŸ`i;](!jKݐT{,;8O=||#FF endstream endobj 46 0 obj <>stream H郞 d}e endstream endobj 47 0 obj <>stream H*2TT2P0P04Tp<P0KD(kVS!" ~0W @ٗ endstream endobj 48 0 obj <>stream H4= 0 !- 88J+M3}Ir8A ރ܊bX7Ʈ32٠~y[}%o=XK@3M 0o" endstream endobj 49 0 obj <>stream H<10 Ew'@cw@b@ 0(,\ǮZՑ…';퍽\ǵ/7oJ~gމzur!A]{}SpdKI ւ3)X)fEM *uI#``GIcgi$XM3<<>stream H*2TT2P0P04Tp<P0KD(kejD XBH*d.CC=# * V r@PH5DH4 lB0W @hU endstream endobj 51 0 obj <>stream H*2TT2P0P04Tp<P0KD(mdkVS` B endstream endobj 52 0 obj <>stream H*2TT2P0P04Tp<P0KD(mdkQ" r B endstream endobj 53 0 obj <>stream HL;@ D{bN+6aD((P@R(ֶf&`邗J|UיqƨTօ4b$"n.=̨!9i=ϩ8T}.Wj͑䶋=!wo8Ӊ~ 6 endstream endobj 54 0 obj <>stream H>stream HD1 0 E!)ApqA.^$-^^n CX&\uǼ0V]"2Enʔbc\WM(U?Po>I'f endstream endobj 56 0 obj <>stream H<= P b<ba!vZ( x}"|aHp aw7k01,+c#0~4EVroOcr]H ܪr( ĨTq^(& endstream endobj 57 0 obj <>stream H< 1E[[M ;Dwp$MQ8F' >Q5= .kt;)FaevrXFi2JhI\Ro43U@a [Za AE`~O`~Sh.m)KtqC 0m: endstream endobj 58 0 obj <>stream HDQ9NA v_@"@ @$|jv*ʻ\d?dM2ߌYnmy\<,i8F)lo|[;kynߠNT<_^8 cExO>ԛ{SFl>xoh&_Ud٫Dڡ֞*DŽz8!s\C\\ǪQ:le1#H:cӱ7 a{%a(Zx@p}=eE8s}M} 0 endstream endobj 59 0 obj <>stream H2TT2P0P26P.sm @iZP`MȊR endstream endobj 60 0 obj <> endobj 61 0 obj <> endobj 62 0 obj <> endobj 1 0 obj <> endobj 2 0 obj <>stream 2017-09-16T12:11:28 ROOT Version 6.11/01 2019-06-20T22:23:47-04:00 2019-06-20T22:23:47-04:00 ROOT application/pdf interp.pdf uuid:5a0a749c-0ec5-49f5-8f02-83b10051cbd1 uuid:7a8c6e60-5003-413f-a3dc-66390846b898 endstream endobj 3 0 obj <> endobj xref 0 4 0000000000 65535 f 0000046414 00000 n 0000046465 00000 n 0000049835 00000 n trailer <<6C986A5B1057744EB189FC0FDE6CB45F>]>> startxref 116 %%EOF qhull-2020.2/html/qvoronoi.htm0000644060175106010010000007005613716271251014535 0ustar bbarber qvoronoi -- Voronoi diagram Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
To: synopsis • input • outputs • controls • graphics • notes • conventions • options

[voronoi]qvoronoi -- Voronoi diagram

The Voronoi diagram is the nearest-neighbor map for a set of points. Each region contains those points that are nearer one input site than any other input site. It has many useful properties and applications. See the survey article by Aurenhammer ['91] and the detailed introduction by O'Rourke ['94]. The Voronoi diagram is the dual of the Delaunay triangulation.

Example: rbox 10 D3 | qvoronoi s o TO result
Compute the 3-d Voronoi diagram of 10 random points. Write a summary to the console and the Voronoi vertices and regions to 'result'. The first vertex of the result indicates unbounded regions.
 
Example: rbox r y c G0.1 D2 | qvoronoi s o TO result
Compute the 2-d Voronoi diagram of a triangle and a small square. Write a summary to the console and Voronoi vertices and regions to 'result'. Report a single Voronoi vertex for cocircular input sites. The first vertex of the result indicates unbounded regions. The origin is the Voronoi vertex for the square.
 
Example: rbox r y c G0.1 D2 | qvoronoi Fv TO result
Compute the 2-d Voronoi diagram of a triangle and a small square. Write a summary to the console and the Voronoi ridges to 'result'. Each ridge is the perpendicular bisector of a pair of input sites. Vertex "0" indicates unbounded ridges. Vertex "8" is the Voronoi vertex for the square.
 
Example: rbox r y c G0.1 D2 | qvoronoi Fi
Print the bounded, separating hyperplanes for the 2-d Voronoi diagram of a triangle and a small square. Note the four hyperplanes (i.e., lines) for Voronoi vertex "8". It is at the origin.

Qhull computes the Voronoi diagram via the Delaunay triangulation. Each Voronoi vertex is the circumcenter of a facet of the Delaunay triangulation. Each Voronoi region corresponds to a vertex (i.e., input site) of the Delaunay triangulation.

Qhull outputs the Voronoi vertices for each Voronoi region. With option 'Fv', it lists all ridges of the Voronoi diagram with the corresponding pairs of input sites. With options 'Fi' and 'Fo', it lists the bounded and unbounded separating hyperplanes. You can also output a single Voronoi region for further processing [see graphics].

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

See Qhull FAQ (local) - Delaunay and Voronoi diagram questions.

The 'qvonoroi' program is equivalent to 'qhull v Qbb'. It disables the following Qhull options: d n v Qbb QbB Qf Qg Qm Qr Qv Qx Qz TR E V Fa FA FC FD FS Ft FV Gt Q0,etc.

Copyright © 1995-2020 C.B. Barber

Voronoi image by KOOK Architecture, Silvan Oesterle and Michael Knauss.


»qvoronoi synopsis

qvoronoi -- compute the Voronoi diagram.
    input (stdin): dimension, number of points, point coordinates
    comments start with a non-numeric character

options (qvoronoi.htm):
    Qu   - compute furthest-site Voronoi diagram
    Tv   - verify result: structure, convexity, and in-circle test
    .    - concise list of all options
    -    - one-line description of all options
    -?   - this message
    -V   - version

output options (subset):
    Fi   - separating hyperplanes for bounded regions, 'Fo' for unbounded
    FN   - count and Voronoi vertices for each Voronoi region
    Fv   - Voronoi diagram as Voronoi vertices between adjacent input sites
    G    - Geomview output (2-d only)
    o    - OFF file format (dim, Voronoi vertices, and Voronoi regions)
    p    - Voronoi vertices
    QVn  - Voronoi vertices for input point n, -n if not
    s    - summary of results (default)
    TI file - input file, may be enclosed in single quotes
    TO file - output file, may be enclosed in single quotes

examples:
rbox c P0 D2 | qvoronoi s o         rbox c P0 D2 | qvoronoi Fi
rbox c P0 D2 | qvoronoi Fo          rbox c P0 D2 | qvoronoi Fv
rbox c P0 D2 | qvoronoi s Qu Fv     rbox c P0 D2 | qvoronoi Qu Fo
rbox c G1 d D2 | qvoronoi s p       rbox c P0 D2 | qvoronoi s Fv QV0

»qvoronoi input

The input data on stdin consists of:
  • dimension
  • number of points
  • point coordinates

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

For example, this is four cocircular points inside a square. Their Voronoi diagram has nine vertices and eight regions. Notice the Voronoi vertex at the origin, and the Voronoi vertices (on each axis) for the four sides of the square.

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

qvoronoi s p < data


Voronoi diagram by the convex hull of 8 points in 3-d:

  Number of Voronoi regions: 8
  Number of Voronoi vertices: 9
  Number of non-simplicial Voronoi vertices: 1

Statistics for: RBOX s 4 W0 c D2 | QVORONOI s p

  Number of points processed: 8
  Number of hyperplanes created: 18
  Number of facets in hull: 10
  Number of distance tests for qhull: 33
  Number of merged facets: 2
  Number of distance tests for merging: 102
  CPU seconds to compute hull (after input): 0.094

2
9
4.217546450968612e-17 1.735507986399734
-8.402566836762659e-17 -1.364368854147395
0.3447488772716865 -0.6395484723719818
1.719446929853986 2.136555906154247e-17
0.4967882915039657 0.68662371396699
-1.729928876283549 1.343733067524222e-17
-0.8906163241424728 -0.4594150543829102
-0.6656840313875723 0.5003013793414868
-7.318364664277155e-19 -1.188217818408333e-16

» qvoronoi outputs

These options control the output of Voronoi diagrams.

 
Voronoi vertices
p
print the coordinates of the Voronoi vertices. The first line is the dimension. The second line is the number of vertices. Each remaining line is a Voronoi vertex.
Fn
list the neighboring Voronoi vertices for each Voronoi vertex. The first line is the number of Voronoi vertices. Each remaining line starts with the number of neighboring vertices. Negative vertices (e.g., -1) indicate vertices outside of the Voronoi diagram. In the circle-in-box example, the Voronoi vertex at the origin has four neighbors.
FN
list the Voronoi vertices for each Voronoi region. The first line is the number of Voronoi regions. Each remaining line starts with the number of Voronoi vertices. Negative indices (e.g., -1) indicate vertices outside of the Voronoi diagram. In the circle-in-box example, the four bounded regions are defined by four Voronoi vertices.
 
 
Voronoi regions
o
print the Voronoi regions in OFF format. The first line is the dimension. The second line is the number of vertices, the number of input sites, and "1". The third line represents the vertex-at-infinity. Its coordinates are "-10.101". The next lines are the coordinates of the Voronoi vertices. Each remaining line starts with the number of Voronoi vertices in a Voronoi region. In 2-d, the vertices are listed in adjacency order (unoriented). In 3-d and higher, the vertices are listed in numeric order. In the circle-in-square example, each bounded region includes the Voronoi vertex at the origin. Lines consisting of 0 indicate coplanar input sites or 'Qz'.
Fi
print separating hyperplanes for inner, bounded Voronoi regions. The first number is the number of separating hyperplanes. Each remaining line starts with 3+dim. The next two numbers are adjacent input sites. The next dim numbers are the coefficients of the separating hyperplane. The last number is its offset. Use 'Tv' to verify that the hyperplanes are perpendicular bisectors. It will list relevant statistics to stderr.
Fo
print separating hyperplanes for outer, unbounded Voronoi regions. The first number is the number of separating hyperplanes. Each remaining line starts with 3+dim. The next two numbers are adjacent input sites on the convex hull. The next dim numbers are the coefficients of the separating hyperplane. The last number is its offset.
 
 
Input sites
Fv
list ridges of Voronoi vertices for pairs of input sites. The first line is the number of ridges. Each remaining line starts with two plus the number of Voronoi vertices in the ridge. The next two numbers are two adjacent input sites. The remaining numbers list the Voronoi vertices. As with option 'o', a 0 indicates the vertex-at-infinity and an unbounded, separating hyperplane. The perpendicular bisector (separating hyperplane) of the input sites is a flat through these vertices. In the circle-in-square example, the ridge for each edge of the square is unbounded.
Fc
list coincident input sites for each Voronoi vertex. The first line is the number of vertices. The remaining lines start with the number of coincident sites and deleted vertices. Deleted vertices indicate highly degenerate input (see'Fs'). A coincident site is assigned to one Voronoi vertex. Do not use 'QJ' with 'Fc'; the joggle will separate coincident sites.
FP
print coincident input sites with distance to nearest site (i.e., vertex). The first line is the number of coincident sites. Each remaining line starts with the point ID of an input site, followed by the point ID of a coincident point, its vertex, and distance. Includes deleted vertices which indicate highly degenerate input (see'Fs'). Do not use 'QJ' with 'FP'; the joggle will separate coincident sites.
 
 
General
s
print summary of the Voronoi diagram. Use 'Fs' for numeric data.
i
list input sites for each Delaunay region. Use option 'Pp' to avoid the warning. The first line is the number of regions. The remaining lines list the input sites for each region. The regions are oriented. In the circle-in-square example, the cocircular region has four edges. In 3-d and higher, report cospherical sites by adding extra points.
G
Geomview output for 2-d Voronoi diagrams.

» qvoronoi controls

These options provide additional control:

Qu
compute the furthest-site Voronoi diagram.
QRn
randomly rotate the input with a random seed of n. If n=0, the seed is the time. If n=-1, use time for the random seed, but do not rotate the input.
QVn
select Voronoi vertices for input site n
Qz
add a point above the paraboloid to reduce precision errors. Use it for nearly cocircular/cospherical input (e.g., 'rbox c | qvoronoi Qz').
Tv
verify result
TI file
input data from file. The filename may not use spaces or quotes.
TO file
output results to file. Use single quotes if the filename contains spaces (e.g., TO 'file with spaces.txt'
TFn
report progress after constructing n facets
PDk:1
include upper and lower facets in the output. Set k to the last dimension (e.g., 'PD2:1' for 2-d inputs).
f
facet dump. Print the data structure for each facet (i.e., Voronoi vertex).

» qvoronoi graphics

In 2-d, Geomview output ('G') displays a Voronoi diagram with extra edges to close the unbounded Voronoi regions. To view the unbounded rays, enclose the input points in a square.

You can also view individual Voronoi regions in 3-d. To view the Voronoi region for site 3 in Geomview, execute

qvoronoi <data QV3 p | qconvex s G >output

The qvoronoi command returns the Voronoi vertices for input site 3. The qconvex command computes their convex hull. This is the Voronoi region for input site 3. Its hyperplane normals (qconvex 'n') are the same as the separating hyperplanes from options 'Fi' and 'Fo' (up to roundoff error).

See the Delaunay and Voronoi examples for 2-d and 3-d examples. Turn off normalization (on Geomview's 'obscure' menu) when comparing the Voronoi diagram with the corresponding Delaunay triangulation.

»qvoronoi notes

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

See Voronoi graphics for computing the convex hull of a Voronoi region.

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

Unbounded regions can be confusing. For example, 'rbox c | qvoronoi Qz o' produces the Voronoi regions for the vertices of a cube centered at the origin. All regions are unbounded. The output is

3
2 9 1
-10.101 -10.101 -10.101
     0      0      0
2 0 1
2 0 1
2 0 1
2 0 1
2 0 1
2 0 1
2 0 1
2 0 1
0

The first line is the dimension. The second line is the number of vertices and the number of regions. There is one region per input point plus a region for the point-at-infinity added by option 'Qz'. The next two lines lists the Voronoi vertices. The first vertex is the infinity vertex. It is indicate by the coordinates -10.101. The second vertex is the origin. The next nine lines list the regions. Each region lists two vertices -- the infinity vertex and the origin. The last line is "0" because no region is associated with the point-at-infinity. A "0" would also be listed for nearly incident input sites.

To use option 'Fv', add an interior point. For example,

rbox c P0 | qvoronoi Fv
20
5 0 7 1 3 5
5 0 3 1 4 5
5 0 5 1 2 3
5 0 1 1 2 4
5 0 6 2 3 6
5 0 2 2 4 6
5 0 4 4 5 6
5 0 8 5 3 6
5 1 2 0 2 4
5 1 3 0 1 4
5 1 5 0 1 2
5 2 4 0 4 6
5 2 6 0 2 6
5 3 4 0 4 5
5 3 7 0 1 5
5 4 8 0 6 5
5 5 6 0 2 3
5 5 7 0 1 3
5 6 8 0 6 3
5 7 8 0 3 5

The output consists of 20 ridges and each ridge lists a pair of input sites and a triplet of Voronoi vertices. The first eight ridges connect the origin ('P0'). The remainder list the edges of the cube. Each edge generates an unbounded ray through the midpoint. The corresponding separating planes ('Fo') follow each pair of coordinate axes.

Options 'Qt' (triangulated output) and 'QJ' (joggled input) are deprecated. They may produce unexpected results. If you use these options, cocircular and cospherical input sites will produce duplicate or nearly duplicate Voronoi vertices. See also Merged facets or joggled input.

»qvoronoi conventions

The following terminology is used for Voronoi diagrams in Qhull. The underlying structure is a Delaunay triangulation from a convex hull in one higher dimension. Facets of the Delaunay triangulation correspond to vertices of the Voronoi diagram. Vertices of the Delaunay triangulation correspond to input sites. They also correspond to regions of the Voronoi diagram. See convex hull conventions, Delaunay conventions, and Qhull's data structures.

  • input site - a point in the input (one dimension lower than a point on the convex hull)
  • point - a point has d+1 coordinates. The last coordinate is the sum of the squares of the input site's coordinates
  • coplanar point - a nearly incident input site
  • vertex - a point on the paraboloid. It corresponds to a unique input site.
  • point-at-infinity - a point added above the paraboloid by option 'Qz'
  • Delaunay facet - a lower facet of the paraboloid. The last coefficient of its normal is clearly negative.
  • Voronoi vertex - the circumcenter of a Delaunay facet
  • Voronoi region - the Voronoi vertices for an input site. The region of Euclidean space nearest to an input site.
  • Voronoi diagram - the graph of the Voronoi regions. It includes the ridges (i.e., edges) between the regions.
  • vertex-at-infinity - the Voronoi vertex that indicates unbounded Voronoi regions in 'o' output format. Its coordinates are -10.101.
  • good facet - a Voronoi vertex with optional restrictions by 'QVn', etc.

»qvoronoi options

qvoronoi -- compute the Voronoi diagram
    http://www.qhull.org

input (stdin):
    first lines: dimension and number of points (or vice-versa).
    other lines: point coordinates, best if one point per line
    comments:    start with a non-numeric character

options:
    Qu   - compute furthest-site Voronoi diagram

Qhull control options:
    Qa   - allow input with fewer or more points than coordinates
    QRn  - random rotation (n=seed, n=0 time, n=-1 time/no rotate)
    Qs   - search all points for the initial simplex
    Qz   - add point-at-infinity to Voronoi diagram

Qhull extra options:
    QGn  - Voronoi vertices if visible from point n, -n if not
    QVn  - Voronoi vertices for input point n, -n if not
    Qw   - allow option warnings
    Q12  - allow wide facets and wide dupridge
    Q14  - merge pinched vertices that create a dupridge

T options:
    TFn  - report summary when n or more facets created
    TI file - input file, may be enclosed in single quotes
    TO file - output file, may be enclosed in single quotes
    Ts   - statistics
    Tv   - verify result: structure, convexity, and in-circle test
    Tz   - send all output to stdout

Trace options:
    T4   - trace at level n, 4=all, 5=mem/gauss, -1= events
    Ta   - annotate output with message codes
    TAn  - stop qhull after adding n vertices
     TCn - stop qhull after building cone for point n
     TVn - stop qhull after adding point n, -n for before
    Tc   - check frequently during execution
    Tf   - flush each qh_fprintf for debugging segfaults
    TPn  - turn on tracing when point n added to hull
     TMn - turn on tracing at merge n
     TWn - trace merge facets when width > n

Precision options:
    Cn   - radius of centrum (roundoff added).  Merge facets if non-convex
     An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex
           C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge
    Rn   - randomly perturb computations by a factor of [1-n,1+n]
    Wn   - min facet width for non-coincident point (before roundoff)

Output formats (may be combined; if none, summary to stdout):
    p    - Voronoi vertices
    s    - summary to stderr
    f    - facet dump
    i    - Delaunay regions (use 'Pp' to avoid warning)
    o    - OFF format (dim, Voronoi vertices, and Voronoi regions)

More formats:
    Fc   - count plus coincident points (by Voronoi vertex)
    Fd   - use cdd format for input (homogeneous with offset first)
    FD   - use cdd format for output (offset first)
    FF   - facet dump without ridges
    Fi   - separating hyperplanes for bounded Voronoi regions
    FI   - ID for each Voronoi vertex
    Fm   - merge count for each Voronoi vertex (511 max)
    Fn   - count plus neighboring Voronoi vertices for each Voronoi vertex
    FN   - count and Voronoi vertices for each Voronoi region
    Fo   - separating hyperplanes for unbounded Voronoi regions
    FO   - options and precision constants
    FP   - nearest point and distance for each coincident point
    FQ   - command used for qvoronoi
    Fs   - summary: #int (8), dimension, #points, tot vertices, tot facets,
                    for output: #Voronoi regions, #Voronoi vertices,
                                #coincident points, #non-simplicial regions
                    #real (2), max outer plane and min vertex
    Fv   - Voronoi diagram as Voronoi vertices between adjacent input sites
    Fx   - extreme points of Delaunay triangulation (on convex hull)

Geomview output (2-d only)
    Ga   - all points as dots
     Gp  -  coplanar points and vertices as radii
     Gv  -  vertices as spheres
    Gc   - centrums
    GDn  - drop dimension n in 3-d and 4-d output
    Gh   - hyperplane intersections
    Gi   - inner planes only
     Gn  -  no planes
     Go  -  outer planes only
    Gr   - ridges

Print options:
    PAn  - keep n largest Voronoi vertices by 'area'
    Pdk:n - drop facet if normal[k] <= n (default 0.0)
    PDk:n - drop facet if normal[k] >= n
    PFn  - keep Voronoi vertices whose 'area' is at least n
    Pg   - print good Voronoi vertices (needs 'QGn' or 'QVn')
    PG   - print neighbors of good Voronoi vertices
    PMn  - keep n Voronoi vertices with most merges
    Po   - force output.  If error, output neighborhood of facet
    Pp   - do not report precision problems

    .    - list of all options
    -    - one line descriptions of all options
    -?   - help with examples
    -V   - version

Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
To: synopsis • input • outputs • controls • graphics • notes • conventions • options


The Geometry Center Home Page

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

qhull-2020.2/html/qvoron_f.htm0000644060175106010010000004237313716271251014513 0ustar bbarber qvoronoi Qu -- furthest-site Voronoi diagram Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
To: synopsis • input • outputs • controls • graphics • notes • conventions • options

[delaunay]qvoronoi Qu -- furthest-site Voronoi diagram

The furthest-site Voronoi diagram is the furthest-neighbor map for a set of points. Each region contains those points that are further from one input site than any other input site. See the survey article by Aurenhammer ['91] and the brief introduction by O'Rourke ['94]. The furthest-site Voronoi diagram is the dual of the furthest-site Delaunay triangulation.

Example: rbox 10 D2 | qvoronoi Qu s o TO result
Compute the 2-d, furthest-site Voronoi diagram of 10 random points. Write a summary to the console and the Voronoi regions and vertices to 'result'. The first vertex of the result indicates unbounded regions. Almost all regions are unbounded.
Example: rbox r y c G1 D2 | qvoronoi Qu s Fn TO result
Compute the 2-d furthest-site Voronoi diagram of a square and a small triangle. Write a summary to the console and the Voronoi vertices for each input site to 'result'. The origin is the only furthest-site Voronoi vertex. The negative indices indicate vertices-at-infinity.

Qhull computes the furthest-site Voronoi diagram via the furthest-site Delaunay triangulation. Each furthest-site Voronoi vertex is the circumcenter of an upper facet of the Delaunay triangulation. Each furthest-site Voronoi region corresponds to a vertex of the Delaunay triangulation (i.e., an input site).

See Qhull FAQ (local) - Delaunay and Voronoi diagram questions.

The 'qvonoroi' program is equivalent to 'qhull v Qbb'. It disables the following Qhull options: d n m v H U Qb QB Qc Qf Qg Qi Qm Qr Qv Qx TR E V Fa FA FC Fp FS Ft FV Gt Q0,etc.

Copyright © 1995-2020 C.B. Barber


»furthest-site qvoronoi synopsis

See qvoronoi synopsis. The same program is used for both constructions. Use option 'Qu' for furthest-site Voronoi diagrams.

»furthest-site qvoronoi input

The input data on stdin consists of:

  • dimension
  • number of points
  • point coordinates

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

For example, this is a square containing four random points. Its furthest-site Voronoi diagram has on vertex and four unbounded, separating hyperplanes (i.e., the coordinate axes)

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

qvoronoi Qu s Fo < data


Furthest-site Voronoi vertices by the convex hull of 8 points in 3-d:

  Number of Voronoi regions: 8
  Number of Voronoi vertices: 1
  Number of non-simplicial Voronoi vertices: 1

Statistics for: RBOX c 4 D2 | QVORONOI Qu s Fo

  Number of points processed: 8
  Number of hyperplanes created: 20
  Number of facets in hull: 11
  Number of distance tests for qhull: 34
  Number of merged facets: 1
  Number of distance tests for merging: 107
  CPU seconds to compute hull (after input):  0

4
5 4 5      0      1      0
5 4 6      1      0      0
5 5 7      1      0      0
5 6 7      0      1      0

» furthest-site qvoronoi outputs

These options control the output of furthest-site Voronoi diagrams.

 
furthest-site Voronoi vertices
p
print the coordinates of the furthest-site Voronoi vertices. The first line is the dimension. The second line is the number of vertices. Each remaining line is a furthest-site Voronoi vertex. The points-in-square example has one furthest-site Voronoi vertex at the origin.
Fn
list the neighboring furthest-site Voronoi vertices for each furthest-site Voronoi vertex. The first line is the number of Voronoi vertices. Each remaining line starts with the number of neighboring vertices. Negative indices (e.g., -1) indicate vertices outside of the Voronoi diagram. In the points-in-square example, the Voronoi vertex at the origin has four neighbors-at-infinity.
FN
list the furthest-site Voronoi vertices for each furthest-site Voronoi region. The first line is the number of Voronoi regions. Each remaining line starts with the number of Voronoi vertices. Negative indices (e.g., -1) indicate vertices outside of the Voronoi diagram. In the points-in-square example, all regions share the Voronoi vertex at the origin.
 
 
furthest-site Voronoi regions
o
print the furthest-site Voronoi regions in OFF format. The first line is the dimension. The second line is the number of vertices, the number of input sites, and "1". The third line represents the vertex-at-infinity. Its coordinates are "-10.101". The next lines are the coordinates of the furthest-site Voronoi vertices. Each remaining line starts with the number of Voronoi vertices in a Voronoi region. In 2-d, the vertices are listed in adjacency order (unoriented). In 3-d and higher, the vertices are listed in numeric order. In the points-in-square example, each unbounded region includes the Voronoi vertex at the origin. Lines consisting of 0 indicate interior input sites.
Fi
print separating hyperplanes for inner, bounded furthest-site Voronoi regions. The first number is the number of separating hyperplanes. Each remaining line starts with 3+dim. The next two numbers are adjacent input sites. The next dim numbers are the coefficients of the separating hyperplane. The last number is its offset. The are no bounded, separating hyperplanes for the points-in-square example.
Fo
print separating hyperplanes for outer, unbounded furthest-site Voronoi regions. The first number is the number of separating hyperplanes. Each remaining line starts with 3+dim. The next two numbers are adjacent input sites on the convex hull. The next dim numbers are the coefficients of the separating hyperplane. The last number is its offset. The points-in-square example has four unbounded, separating hyperplanes.
 
 
Input sites
Fv
list ridges of furthest-site Voronoi vertices for pairs of input sites. The first line is the number of ridges. Each remaining line starts with two plus the number of Voronoi vertices in the ridge. The next two numbers are two adjacent input sites. The remaining numbers list the Voronoi vertices. As with option 'o', a 0 indicates the vertex-at-infinity and an unbounded, separating hyperplane. The perpendicular bisector (separating hyperplane) of the input sites is a flat through these vertices. In the points-in-square example, the ridge for each edge of the square is unbounded.
 
 
General
s
print summary of the furthest-site Voronoi diagram. Use 'Fs' for numeric data.
i
list input sites for each furthest-site Delaunay region. Use option 'Pp' to avoid the warning. The first line is the number of regions. The remaining lines list the input sites for each region. The regions are oriented. In the points-in-square example, the square region has four input sites. In 3-d and higher, report cospherical sites by adding extra points.
G
Geomview output for 2-d furthest-site Voronoi diagrams.

» furthest-site qvoronoi controls

These options provide additional control:

Qu
must be used.
QRn
randomly rotate the input with a random seed of n. If n=0, the seed is the time. If n=-1, use time for the random seed, but do not rotate the input.
QVn
select furthest-site Voronoi vertices for input site n
Tv
verify result
TI file
input data from file. The filename may not use spaces or quotes.
TO file
output results to file. Use single quotes if the filename contains spaces (e.g., TO 'file with spaces.txt'
TFn
report progress after constructing n facets
PDk:1
include upper and lower facets in the output. Set k to the last dimension (e.g., 'PD2:1' for 2-d inputs).
f
facet dump. Print the data structure for each facet (i.e., furthest-site Voronoi vertex).

» furthest-site qvoronoi graphics

In 2-d, Geomview output ('G') displays a furthest-site Voronoi diagram with extra edges to close the unbounded furthest-site Voronoi regions. All regions will be unbounded. Since the points-in-box example has only one furthest-site Voronoi vertex, the Geomview output is one point.

See the Delaunay and Voronoi examples for a 2-d example. Turn off normalization (on Geomview's 'obscure' menu) when comparing the furthest-site Voronoi diagram with the corresponding Voronoi diagram.

»furthest-site qvoronoi notes

See Voronoi notes.

»furthest-site qvoronoi conventions

The following terminology is used for furthest-site Voronoi diagrams in Qhull. The underlying structure is a furthest-site Delaunay triangulation from a convex hull in one higher dimension. Upper facets of the Delaunay triangulation correspond to vertices of the furthest-site Voronoi diagram. Vertices of the furthest-site Delaunay triangulation correspond to input sites. They also define regions of the furthest-site Voronoi diagram. All vertices are extreme points of the input sites. See qconvex conventions, furthest-site delaunay conventions, and Qhull's data structures.

  • input site - a point in the input (one dimension lower than a point on the convex hull)
  • point - a point has d+1 coordinates. The last coordinate is the sum of the squares of the input site's coordinates
  • vertex - a point on the upper facets of the paraboloid. It corresponds to a unique input site.
  • furthest-site Delaunay facet - an upper facet of the paraboloid. The last coefficient of its normal is clearly positive.
  • furthest-site Voronoi vertex - the circumcenter of a furthest-site Delaunay facet
  • furthest-site Voronoi region - the region of Euclidean space further from an input site than any other input site. Qhull lists the furthest-site Voronoi vertices that define each furthest-site Voronoi region.
  • furthest-site Voronoi diagram - the graph of the furthest-site Voronoi regions with the ridges (edges) between the regions.
  • infinity vertex - the Voronoi vertex for unbounded furthest-site Voronoi regions in 'o' output format. Its coordinates are -10.101.
  • good facet - an furthest-site Voronoi vertex with optional restrictions by 'QVn', etc.

»furthest-site qvoronoi options

See qvoronoi options. The same program is used for both constructions. Use option 'Qu' for furthest-site Voronoi diagrams.

Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
To: synopsis • input • outputs • controls • graphics • notes • conventions • options


The Geometry Center Home Page

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

qhull-2020.2/html/rbox.htm0000644060175106010010000002277313716271251013636 0ustar bbarber rbox -- generate point distributions

Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
To: synopsis • outputs • examples • notes • options


[CONE]rbox -- generate point distributions

rbox generates random or regular points according to the options given, and outputs the points to stdout. The points are generated in a cube, unless 's', 'x', or 'y' are given.

»rbox synopsis

rbox- generate various point distributions.  Default is random in cube.

args (any order, space separated):
  3000    number of random points in cube, lens, spiral, sphere or grid
  D3      dimension 3-d
  c       add a unit cube to the output ('c G2.0' sets size)
  d       add a unit diamond to the output ('d G2.0' sets size)
  l       generate a regular 3-d spiral
  r       generate a regular polygon, ('r s Z1 G0.1' makes a cone)
  s       generate cospherical points
  x       generate random points in simplex, may use 'r' or 'Wn'
  y       same as 'x', plus simplex
  Cn,r,m  add n nearly coincident points within radius r of m points
  Pn,m,r  add point [n,m,r] first, pads with 0

  Ln      lens distribution of radius n.  Also 's', 'r', 'G', 'W'.
  Mn,m,r  lattice (Mesh) rotated by [n,-m,0], [m,n,0], [0,0,r], ...
          '27 M1,0,1' is {0,1,2} x {0,1,2} x {0,1,2}.  Try 'M3,4 z'.
  W0.1    random distribution within 0.1 of the cube's or sphere's surface
  Z0.5 s  random points in a 0.5 disk projected to a sphere
  Z0.5 s G0.6 same as Z0.5 within a 0.6 gap

  Bn      bounding box coordinates, default 0.5
  h       output as homogeneous coordinates for cdd
  n       remove command line from the first line of output
  On      offset coordinates by n
  t       use time as the random number seed (default is command line)
  tn      use n as the random number seed
  z       print integer coordinates, default 'Bn' is 1e+06

»rbox outputs

The format of the output is the following: first line contains the dimension and a comment, second line contains the number of points, and the following lines contain the points, one point per line. Points are represented by their coordinate values.

For example, rbox c 10 D2 generates

2 RBOX c 10 D2
14
-0.4999921736307369 -0.3684622117955817
0.2556053225468894 -0.0413498678629751
0.0327672376602583 -0.2810408135699488
-0.452955383763607 0.17886471718444
0.1792964061529342 0.4346928963760779
-0.1164979223315585 0.01941637230982666
0.3309653464993139 -0.4654278894564396
-0.4465383649305798 0.02970019358182344
0.1711493843897706 -0.4923018137852678
-0.1165843490665633 -0.433157762450313
  -0.5   -0.5
  -0.5    0.5
   0.5   -0.5
   0.5    0.5

»rbox examples

       rbox 10
              10 random points in the unit cube centered  at  the
              origin.

       rbox 10 s D2
              10 random points on a 2-d circle.

       rbox 100 W0
              100 random points on the surface of a cube.

       rbox 1000 s D4
              1000 random points on a 4-d sphere.

       rbox c D5 O0.5
              a 5-d hypercube with one corner at the origin.

       rbox d D10
              a 10-d diamond.

       rbox x 1000 r W0
              100 random points on the surface of a fixed simplex

       rbox y D12
              a 12-d simplex.

       rbox l 10
              10 random points along a spiral

       rbox l 10 r
              10 regular points  along  a  spiral  plus  two  end
              points

       rbox 1000 L10000 D4 s
              1000 random points on the surface of a narrow lens.

           rbox 1000 L100000 s G1e-6
                  1000 random points near the edge of a narrow lens

       rbox c G2 d G3
              a cube with coordinates +2/-2 and  a  diamond  with
              coordinates +3/-3.

       rbox 64 M3,4 z
              a  rotated,  {0,1,2,3} x {0,1,2,3} x {0,1,2,3} lat-
              tice (Mesh) of integer points.

       rbox P0 P0 P0 P0 P0
              5 copies of the origin in 3-d.  Try 'rbox P0 P0  P0
              P0 P0 | qhull QJ'.

       r 100 s Z1 G0.1
              two  cospherical  100-gons plus another cospherical
              point.

       100 s Z1
              a cone of points.

       100 s Z1e-7
              a narrow cone of points with many precision errors.

»rbox notes

Some combinations of arguments generate odd results.

»rbox options

       n      number of points

       Dn     dimension n-d (default 3-d)

       Bn     bounding box coordinates (default 0.5)

       l      spiral distribution, available only in 3-d

       Ln     lens  distribution  of  radius n.  May be used with
              's', 'r', 'G', and 'W'.

       Mn,m,r lattice  (Mesh)  rotated  by  {[n,-m,0],   [m,n,0],
              [0,0,r],  ...}.   Use  'Mm,n'  for a rigid rotation
              with r = sqrt(n^2+m^2).  'M1,0'  is  an  orthogonal
              lattice.   For  example,  '27  M1,0'  is  {0,1,2} x
              {0,1,2} x {0,1,2}.

       s      cospherical points randomly generated in a cube and
              projected to the unit sphere

       x      simplicial  distribution.   It  is fixed for option
              'r'.  May be used with 'W'.

       y      simplicial distribution plus a simplex.   Both  'x'
              and 'y' generate the same points.

       Wn     restrict  points  to distance n of the surface of a
              sphere or a cube

       c      add a unit cube to the output

       c Gm   add a cube with all combinations of +m  and  -m  to
              the output

       d      add a unit diamond to the output.

       d Gm   add a diamond made of 0, +m and -m to the output

       Cn,r,m add n nearly coincident points within radius r of m points

       Pn,m,r add point [n,m,r] to the output first.  Pad coordi-
              nates with 0.0.

       n      Remove the command line from the first line of out-
              put.

       On     offset the data by adding n to each coordinate.

       t      use  time  in  seconds  as  the  random number seed
              (default is command line).

       tn     set the random number seed to n.

       z      generate integer coordinates.  Use 'Bn'  to  change
              the  range.   The  default  is 'B1e6' for six-digit
              coordinates.  In R^4, seven-digit coordinates  will
              overflow hyperplane normalization.

       Zn s   restrict points to a disk about the z+ axis and the
              sphere (default Z1.0).  Includes the opposite pole.
              'Z1e-6'  generates  degenerate  points under single
              precision.

       Zn Gm s
              same as Zn with an empty center (default G0.5).

       r s D2 generate a regular polygon

       r s Z1 G0.1
              generate a regular cone

Up: Home page for Qhull (local)
Up: Qhull manual: contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
To: synopsis • outputs • examples • notes • options


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: Sept. 25, 1995 --- Last modified: August 12, 1998

qhull-2020.2/html/rbox.man0000644060175106010010000001044512641775761013625 0ustar bbarber.\" This is the Unix manual page for rbox, written in nroff, the standard .\" manual formatter for Unix systems. To format it, type .\" .\" nroff -man rbox.man .\" .\" This will print a formatted copy to standard output. If you want .\" to ensure that the output is plain ascii, free of any control .\" characters that nroff uses for underlining etc, pipe the output .\" through "col -b": .\" .\" nroff -man rbox.man | col -b .\" .TH rbox 1 "August 10, 1998" "Geometry Center" .SH NAME rbox \- generate point distributions for qhull .SH SYNOPSIS Command "rbox" (w/o arguments) lists the options. .SH DESCRIPTION .PP rbox generates random or regular points according to the options given, and outputs the points to stdout. The points are generated in a cube, unless 's' or 'k' option is given. The format of the output is the following: first line contains the dimension and a comment, second line contains the number of points, and the following lines contain the points, one point per line. Points are represented by their coordinate values. .SH EXAMPLES .TP rbox 10 10 random points in the unit cube centered at the origin. .TP rbox 10 s D2 10 random points on a 2\[hy]d circle. .TP rbox 100 W0 100 random points on the surface of a cube. .TP rbox 1000 s D4 1000 random points on a 4\[hy]d sphere. .TP rbox c D5 O0.5 a 5\[hy]d hypercube with one corner at the origin. .TP rbox d D10 a 10\[hy]d diamond. .TP rbox x 1000 r W0 100 random points on the surface of a fixed simplex .TP rbox y D12 a 12\[hy]d simplex. .TP rbox l 10 10 random points along a spiral .TP rbox l 10 r 10 regular points along a spiral plus two end points .TP rbox 1000 L10000 D4 s 1000 random points on the surface of a narrow lens. .TP rbox c G2 d G3 a cube with coordinates +2/\-2 and a diamond with coordinates +3/\-3. .TP rbox 64 M3,4 z a rotated, {0,1,2,3} x {0,1,2,3} x {0,1,2,3} lattice (Mesh) of integer points. 'rbox 64 M1,0' is orthogonal. .TP rbox P0 P0 P0 P0 P0 5 copies of the origin in 3\-d. Try 'rbox P0 P0 P0 P0 P0 | qhull QJ'. .TP r 100 s Z1 G0.1 two cospherical 100\-gons plus another cospherical point. .TP 100 s Z1 a cone of points. .TP 100 s Z1e\-7 a narrow cone of points with many precision errors. .SH OPTIONS .TP n number of points .TP Dn dimension n\[hy]d (default 3\[hy]d) .TP Bn bounding box coordinates (default 0.5) .TP l spiral distribution, available only in 3\[hy]d .TP Ln lens distribution of radius n. May be used with 's', 'r', 'G', and 'W'. .TP Mn,m,r lattice (Mesh) rotated by {[n,\-m,0], [m,n,0], [0,0,r], ...}. Use 'Mm,n' for a rigid rotation with r = sqrt(n^2+m^2). 'M1,0' is an orthogonal lattice. For example, '27 M1,0' is {0,1,2} x {0,1,2} x {0,1,2}. '27 M3,4 z' is a rotated integer lattice. .TP s cospherical points randomly generated in a cube and projected to the unit sphere .TP x simplicial distribution. It is fixed for option 'r'. May be used with 'W'. .TP y simplicial distribution plus a simplex. Both 'x' and 'y' generate the same points. .TP Wn restrict points to distance n of the surface of a sphere or a cube .TP c add a unit cube to the output .TP c Gm add a cube with all combinations of +m and \-m to the output .TP d add a unit diamond to the output. .TP d Gm add a diamond made of 0, +m and \-m to the output .TP Cn,r,m add n nearly coincident points within radius r of m points .TP Pn,m,r add point [n,m,r] to the output first. Pad coordinates with 0.0. .TP n Remove the command line from the first line of output. .TP On offset the data by adding n to each coordinate. .TP t use time in seconds as the random number seed (default is command line). .TP tn set the random number seed to n. .TP z generate integer coordinates. Use 'Bn' to change the range. The default is 'B1e6' for six\[hy]digit coordinates. In R^4, seven\[hy]digit coordinates will overflow hyperplane normalization. .TP Zn s restrict points to a disk about the z+ axis and the sphere (default Z1.0). Includes the opposite pole. 'Z1e\-6' generates degenerate points under single precision. .TP Zn Gm s same as Zn with an empty center (default G0.5). .TP r s D2 generate a regular polygon .TP r s Z1 G0.1 generate a regular cone .SH BUGS Some combinations of arguments generate odd results. Report bugs to qhull_bug@qhull.org, other correspondence to qhull@qhull.org .SH SEE ALSO qhull(1) .SH AUTHOR .nf C. Bradford Barber bradb@shore.net .fi qhull-2020.2/html/rbox.txt0000644060175106010010000001214212641610441013644 0ustar bbarber rbox(1) rbox(1) NAME rbox - generate point distributions for qhull SYNOPSIS Command "rbox" (w/o arguments) lists the options. DESCRIPTION rbox generates random or regular points according to the options given, and outputs the points to stdout. The points are generated in a cube, unless 's' or given. The format of the output is the following: first line contains the dimension and a comment, second line contains the num- ber of points, and the following lines contain the points, one point per line. Points are represented by their coor- dinate values. EXAMPLES rbox 10 10 random points in the unit cube centered at the origin. rbox 10 s D2 10 random points on a 2-d circle. rbox 100 W0 100 random points on the surface of a cube. rbox 1000 s D4 1000 random points on a 4-d sphere. rbox c D5 O0.5 a 5-d hypercube with one corner at the origin. rbox d D10 a 10-d diamond. rbox x 1000 r W0 100 random points on the surface of a fixed simplex rbox y D12 a 12-d simplex. rbox l 10 10 random points along a spiral rbox l 10 r 10 regular points along a spiral plus two end points rbox 1000 L10000 D4 s 1000 random points on the surface of a narrow lens. rbox c G2 d G3 a cube with coordinates +2/-2 and a diamond with Geometry Center August 10, 1998 1 rbox(1) rbox(1) coordinates +3/-3. rbox 64 M3,4 z a rotated, {0,1,2,3} x {0,1,2,3} x {0,1,2,3} lat- tice (Mesh) of integer points. rbox P0 P0 P0 P0 P0 5 copies of the origin in 3-d. Try 'rbox P0 P0 P0 P0 P0 | qhull QJ'. r 100 s Z1 G0.1 two cospherical 100-gons plus another cospherical point. 100 s Z1 a cone of points. 100 s Z1e-7 a narrow cone of points with many precision errors. OPTIONS n number of points Dn dimension n-d (default 3-d) Bn bounding box coordinates (default 0.5) l spiral distribution, available only in 3-d Ln lens distribution of radius n. May be used with 's', 'r', 'G', and 'W'. Mn,m,r lattice (Mesh) rotated by {[n,-m,0], [m,n,0], [0,0,r], ...}. Use 'Mm,n' for a rigid rotation with r = sqrt(n^2+m^2). 'M1,0' is an orthogonal lattice. For example, '27 M1,0' is {0,1,2} x {0,1,2} x {0,1,2}. s cospherical points randomly generated in a cube and projected to the unit sphere x simplicial distribution. It is fixed for option 'r'. May be used with 'W'. y simplicial distribution plus a simplex. Both 'x' and 'y' generate the same points. Wn restrict points to distance n of the surface of a sphere or a cube c add a unit cube to the output c Gm add a cube with all combinations of +m and -m to the output Geometry Center August 10, 1998 2 rbox(1) rbox(1) d add a unit diamond to the output. d Gm add a diamond made of 0, +m and -m to the output Cn,r,m add n nearly coincident points within radius r of m points Pn,m,r add point [n,m,r] to the output first. Pad coordi- nates with 0.0. n Remove the command line from the first line of out- put. On offset the data by adding n to each coordinate. t use time in seconds as the random number seed (default is command line). tn set the random number seed to n. z generate integer coordinates. Use 'Bn' to change the range. The default is 'B1e6' for six-digit coordinates. In R^4, seven-digit coordinates will overflow hyperplane normalization. Zn s restrict points to a disk about the z+ axis and the sphere (default Z1.0). Includes the opposite pole. 'Z1e-6' generates degenerate points under single precision. Zn Gm s same as Zn with an empty center (default G0.5). r s D2 generate a regular polygon r s Z1 G0.1 generate a regular cone BUGS Some combinations of arguments generate odd results. Report bugs to qhull_bug@qhull.org, other correspon- dence to qhull@qhull.org SEE ALSO qhull(1) AUTHOR C. Bradford Barber bradb@shore.net Geometry Center August 10, 1998 3 qhull-2020.2/index.htm0000644060175106010010000003601613723515773013032 0ustar bbarber Qhull code for Convex Hull, Delaunay Triangulation, Voronoi Diagram, and Halfspace Intersection about a Point URL: http://www.qhull.orgNewsScholarImagesGitHub
To: DownloadReadmeManualProgramsOptionsFAQCodeFunctions


Qhull

[CONE]
Qhull computes the convex hull, Delaunay triangulation, Voronoi diagram, halfspace intersection about a point, furthest-site Delaunay triangulation, and furthest-site Voronoi diagram. The source code runs in 2-d, 3-d, 4-d, and higher dimensions. Qhull implements the Quickhull algorithm for computing the convex hull. It handles roundoff errors from floating point arithmetic. It computes volumes, surface areas, and approximations to the convex hull.

Qhull does not support triangulation of non-convex surfaces, mesh generation of non-convex objects, medium-sized inputs in 9-D and higher, alpha shapes, weighted Voronoi diagrams, Voronoi volumes, or constrained Delaunay triangulations,

If you call Qhull from your program, please use reentrant Qhull (libqhull_r or libqhullstatic_r). If you use Qhull 2003.1, please upgrade or apply poly.c-qh_gethash.patch.


Introduction

Qhull Documentation and Support

Related URLs

FAQs and Newsgroups


The program includes options for input transformations, randomization, tracing, multiple output formats, and execution statistics. The program can be called from within your application.

You can view the results in 2-d, 3-d and 4-d with Geomview. An alternative is VTK.

For an article about Qhull, download from ACM or CiteSeer:

Barber, C.B., Dobkin, D.P., and Huhdanpaa, H.T., "The Quickhull algorithm for convex hulls," ACM Trans. on Mathematical Software, 22(4):469-483, Dec 1996, http://www.qhull.org

Abstract:

The convex hull of a set of points is the smallest convex set that contains the points. This article presents a practical convex hull algorithm that combines the two-dimensional Quickhull Algorithm with the general dimension Beneath-Beyond Algorithm. It is similar to the randomized, incremental algorithms for convex hull and Delaunay triangulation. We provide empirical evidence that the algorithm runs faster when the input contains non-extreme points, and that it uses less memory.

Computational geometry algorithms have traditionally assumed that input sets are well behaved. When an algorithm is implemented with floating point arithmetic, this assumption can lead to serious errors. We briefly describe a solution to this problem when computing the convex hull in two, three, or four dimensions. The output is a set of "thick" facets that contain all possible exact convex hulls of the input. A variation is effective in five or more dimensions.


Up: Past Software Projects of the Geometry Center
URL: http://www.qhull.orgNewsScholarImagesGitHub
To: DownloadReadmeManualProgramsOptionsFAQCodeFunctions


[HOME] The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 17 1995 --- qhull-2020.2/Makefile0000644060175106010010000012517713724316115012646 0ustar bbarber# Unix Makefile for reentrant libqhull, qhull, and rbox (default gcc/g++) # # make help # See README.txt # For qhulltest of the C++ interface, use Qt project file at src/qhull-all.pro # For static builds, a simple alternative is src/libqhull_r/Makefile # # Variables # DESTDIR directory for staged installs (GNU Makefile standards) # PREFIX install directory for 'make install' (default /usr/local) # BINDIR sub-directory where to copy executables # DOCDIR sub-directory where to copy html documentation # INCDIR sub-directory where to copy headers # LIBDIR sub-directory where to copy libraries # MANDIR sub-directory where to copy manual pages # PCDIR sub-directory where to copy pkg-config files # PRINTMAN command for printing manual pages # PRINTC command for printing C files # CC ANSI C or C++ compiler # CC_OPTS1 options used to compile .c files # CC_OPTS2 options used to link .o files # CC_OPTS3 options to build shared libraries # CXX ANSI C++ compiler # CXX_OPTS1 options used to compile .cpp files # CXX_OPTS2 options used to link .o files # CC_WARNINGS warnings for .c programs # CXX_WARNINGS warnings for .cpp programs # SO file extension for libqhull_r (so-$VERSION or dll) # SONAME_EXT SONAME extension for libqhull_r (so-$SOVERSION) # # LIBQHULLS_RBOX_OBJS .o files for linking # LIBQHULLR_HDRS non-reentrant .h files # LIBQHULLR_HDRS reentrant .h files # CFILES .c files for printing # CXXFILES .cpp files for printing # TESTFILES .cpp test files for printing # DOCFILES documentation files # FILES miscellaneous files for printing # HTMFILES documentation source files # TFILES .txt versions of html files # FILES all other files # LIBQHULLS_RBOX_OBJS specifies the object files of libqhullstatic.a # # Results # rbox Generates points sets for qhull, qconvex, etc. # qhull Computes convex hull and related structures with reentrant libqhullstatic_r # qconvex, qdelaunay, qhalf, qvoronoi # Specializations of qhull for each geometric structure # Built with non-reentrant libqhullstatic (somewhat faster) # libqhull_r.so Shared library with reentrant code # libqhullstatic.a Non-reentrant static library with static qh_qh struct # Called 'static' to avoid naming conflicts # libqhullstatic_r.a Reentrant, static library # libqhullcpp.a C++ static library with libqhullstatic_r.a # testqset Standalone test program for non-reentrant qset.c with mem.c # testqset_r Standalone test program for reentrant qset_r.c with mem_r.c # user_eg An example of the reentrant, shared library qhull_r # user_eg2 An example of the reentrant, static library libqhullstatic_r # user_eg3 An example of the C++ interface with libqhullcpp and libqhullstatic_r # # Targets # make Build Qhull using gcc or another compiler # make all # make SO=dll For mingw on Windows, use SO=dll. It builds dlls # make M32=-m32 Build 32-bit Qhull on a 64-bit host (less memory) # make M32=-m32 FPIC= Build 32-bit Qhull on 64-bit host without '-fpic' (maybe faster) # make bin/qvoronoi Produce bin/qvoronoi (etc.) # make qhullx Produce qhull, qconvex etc. without using library # # make benchmark Benchmark of qhull precision and performance # make benchmark 2>&1 | tee eg/q_benchmark.x # make clean Remove object files # make cleanall Remove generated files, build/*.dlr/, buildqt/, and buildvc/ # make doc Print documentation # make help # make install Copy results and documentation to BINDIR, DOCDIR, INCDIR, LIBDIR, MANDIR, PCDOC # For debug libraries, please append '_d' (e.g., libqhull_rd) # make uninstall Delete Qhull files from BINDIR, DOCDIR, INCDIR, LIBDIR, MANDIR, PCDOC # make new Rebuild qhull and rbox from source # make printall Print all files # make qtest Quick test of rbox and qhull # make test Quick test of qhull programs # make testall Test programs for manual review with eg/q_test-ok.txt # Windows -- make cleanall SO=dll all; cp lib/libqhull*.dll bin/ # make testall >eg/q_test.x 2>&1 # make testall 2>&1 | tee eg/q_test.x # Build the C++ qhulltest with Qt # # $Id: //main/2019/qhull/Makefile#36 $ # Do not replace tabs with spaces. Needed for build rules # Unix line endings (\n) PREFIX ?= /usr/local BINDIR ?= bin INCDIR ?= include LIBDIR ?= lib DOCDIR ?= share/doc/qhull MANDIR ?= share/man/man1 PCDIR ?= $(LIBDIR)/pkgconfig ABS_BINDIR = $(DESTDIR)$(PREFIX)/$(BINDIR) ABS_INCDIR = $(DESTDIR)$(PREFIX)/$(INCDIR) ABS_LIBDIR = $(DESTDIR)$(PREFIX)/$(LIBDIR) ABS_DOCDIR = $(DESTDIR)$(PREFIX)/$(DOCDIR) ABS_MANDIR = $(DESTDIR)$(PREFIX)/$(MANDIR) ABS_PCDIR = $(DESTDIR)$(PREFIX)/$(PCDIR) # Define qhull_VERSION in CMakeLists.txt, Makefile, and qhull-warn.pri # Truncated version in qhull-exports.def, qhull_p-exports.def, qhull_r-exports.def # libqhull_r.so -- reentrant Qhull with qh_qhT passed as an argument. qhull_VERSION=$(shell grep 'set.qhull_VERSION ' CMakeLists.txt | grep -o '[0-9.]\+' || echo 0unknown) qhull_SOVERSION=$(shell grep 'set.qhull_SOVERSION ' CMakeLists.txt | grep -o '[0-9.]\+' || echo 0unknown) SO = so.$(qhull_VERSION) SONAME_EXT = so.$(qhull_SOVERSION) # On MinGW, # make SO=dll # Copy lib/libqhull_r.dll to bin/ # 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, -O3 for optimization, -g for debugging, -pg for profiling # see below for gcc's CC_WARNINGS and CXX_WARNINGS # Qhull uses less memory for 32-bit builds on 64-bit hosts # Enable 32-bit builds with 'make M32=-m32' # M32 = -m32 # -fpic is required for linking to shared libraries # -fpic may be slower for 32-bit builds on 64-bit hosts # Disable -fpic with 'make FPIC=' FPIC = -fpic CC = gcc CC_OPTS1 = -O3 -ansi -Isrc/ $(CC_WARNINGS) $(M32) $(FPIC) CXX = g++ # libqhullcpp must be listed before libqhull_r, otherwise libqhull_r pulls in userprintf_r.c CXX_OPTS1 = -std=c++98 -O3 -Isrc/ $(CXX_WARNINGS) $(M32) $(FPIC) # for shared library link CC_OPTS3 = # for Sun's cc compiler, -fast or O2 for optimization, -g for debugging, -Xc for ANSI #CC = cc #CC_OPTS1 = -Xc -v -fast # for Silicon Graphics cc compiler, -O2 for optimization, -g for debugging #CC = cc #CC_OPTS1 = -ansi -O2 # for Next cc compiler with fat executable #CC = cc #CC_OPTS1 = -ansi -O2 -arch m68k -arch i386 -arch hppa # For loader, ld, CC_OPTS2 = $(CC_OPTS1) CXX_OPTS2 = $(CXX_OPTS1) # Warnings for gcc # [gcc 8.1 from may'2018] Compiles without error (-Werror) # gcc -pedantic not used due to -Woverlength-strings. Maximum string length is less than 2000 # g++ -pedantic not used due to 'long long' warning. CC_WARNINGS = -Wall -Wcast-qual -Wextra -Wwrite-strings -Wshadow -Wsign-conversion -Wconversion CXX_WARNINGS = -Wall -Wcast-qual -Wextra -Wwrite-strings -Wno-sign-conversion -Wshadow -Wconversion # All warnings for gcc # Ignore these gcc warnings (-f*, Fortran only, Go only, ObjC only, Qhull issues) ##Ignore warnings that occur in Qhull and appear to be OK # NOT_QHULL_WARN="aggregate-return|float-equal|format-nonliteral|format-signedness|old-style-cast|padded|redundant-decls|long-long|strict-overflow|switch-enum|traditional|traditional-conversion|unsafe-loop-optimizations|unsuffixed-float-constants|useless-cast|zero-as-null-pointer-constant" ##Ignore warnings that require an operand. Include them specifically if needed. Pattern may be a substring # NOT_EQUAL_WARN="format-overflow<|normalized=[^> ]*>|larger-than=|larger-than-|abi=|array-bounds=|aligned-new=|catch-value=|format=|format-overflow=|format-truncation=|implicit-fallthrough=|normalized=[^.]|placement-new=[^.]|shift-overflow=[^.]|stack-usage=|strict-aliasing=|strict-overflow=|stringop-overflow=[^.]|unused-const-variable=[^.]" ##Ignore warnings that are GCC specific and occur in Qhull # NOT_GCC_WARN="abi-tag|effc[+][+]|missing-format-attribute|missing-noreturn|namespaces|suggest-attribute|suggest-attribute=(format|malloc|noreturn|pure)|suggest-final-methods|suggest-final-types|suggest-override|templates" ## -Wstringop-truncation -- known issue Bug c++/85700 ##Ignore the above warnings and warnings specific to Fortran, ObjC, etc # NOT_CC_CXX_WARN="$NOT_GCC_WARN|$NOT_QHULL_WARN|aliasing|align-commons|ampersand|argument-mismatch|array-temporaries|assign-intercept|c-binding-type|character-truncation|compare-reals|conversion-extra|do-subscript|function-elimination|implicit-interface|implicit-procedure|integer-division|intrinsic-shadow|intrinsics-std|line-truncation|property-assign-default|protocol|real-q-constant|realloc-lhs|realloc-lhs-all|selector|shadow-ivar|strict-selector-match|surprising|tabs|target-lifetime|undeclared-selector|undefined-do-loop|underflow|unused-dummy-argument|use-without-only|zerotrip" ##Ignore these warnings and warnings for CC but not CXX and vice versa # NOT_CC_WARNINGS="$NOT_CC_CXX_WARN|c[+][+][0-9xz]*-compat|abi-tag|argument-mismatch|catch-value|class-memaccess|conditionally-supported|conversion-null|ctor-dtor-privacy|delete-incomplete|delete-non-virtual-dtor|effc++|extra-semi|inherited-variadic-ctor|invalid-offsetof|literal-suffix|multiple-inheritance|namespaces|noexcept|noexcept-type|non-template-friend|non-virtual-dtor|overloaded-virtual|placement-new|pmf-conversions|register|reorder|sign-promo|sized-deallocation|strict-null-sentinel|subobject-linkage|suggest-override|synth|templates|terminate|useless-cast|virtual-inheritance|virtual-move-assign|zero-as-null-pointer-constant" # NOT_CXX_WARNINGS="$NOT_CC_CXX_WARN|c[+][+]-compat|bad-function-cast|c90-c99-compat|c99-c11-compat|declaration-after-statement|designated-init|discarded-array-qualifiers|discarded-qualifiers|duplicate-decl-specifier|implicit|implicit-function-declaration|implicit-int|incompatible-pointer-types|int-conversion|jump-misses-init|missing-parameter-type|missing-prototypes|nested-externs|old-style-declaration|old-style-definition|override-init|override-init-side-effects|pointer-sign|pointer-to-int-cast|strict-prototypes" # NOT_CXX_WARNINGS="$NOT_CXX_WARNINGS|sign-conversion" ##List of gcc warnings for CC_WARNINGS, excluding NOT_CC_WARNINGS and NOT_EQUAL_WARN, to bin/x.cc # (echo -n -Wformat-overflow; echo " "; gcc --help=warnings) | sed -nr 's/^ *(-W[^ ]*) .*/\1/p' | sort -u | grep -vE "[-]W\$|-W(all|extra|$NOT_CC_WARNINGS)\$|$NOT_EQUAL_WARN" >bin/x.cc ##List gcc warnings for CXX_WARNINGS, excluding NOT_CXX_WARNINGS and NOT_EQUAL_WARN, bin/x.ccx ## -Wno-sign-conversion due to 'int' vs. 'size_t' for indexing, boolT, countT, and size_t returns ##..-Wno-old-style-cast due to warnings for libqhull_r macros ## Test CXX_WARNINGS with -Wsign-conversion and -Wold-style-cast # (echo -n -Wno-old-style-cast -Wno-sign-conversion -Wformat-overflow; echo " "; gcc --help=warnings) | sed -nr 's/^ *(-W[^ ]*) .*/\1/p' | sort -u | grep -vE "[-]W\$|-W(all|extra|sign-conversion|$NOT_CXX_WARNINGS)\$|$NOT_EQUAL_WARN" >bin/x.cxx ##List of mismatched gcc warnings for NOT_CC_CXX_WARN, NOT_CC_WARNINGS, and NOT_CXX_WARNINGS to bin/x.1 # make cleanall SO=dll qhullx 2>&1 | grep "not for C" | sort -u > bin/x.1 ##Test gcc warnings on Windows with mingw gcc to bin/x.2 # make cleanall SO=dll qhullx >bin/x.2 2>&1 # libqhull and libqhull_r # make cleanall SO=dll bin/user_eg3 >bin/x.2 2>&1 # libqhullcpp # make cleanall SO=dll all >bin/x.2 2>&1 ##Summary list of warnings to bin/x.1 for review # grep -vE 'Tools/mingw|mingw-w64|short unsigned int:9|string length .([0-9][0-9][0-9]|1[0-7][0-9][0-9]). is greater|from src/' bin/x.2 | grep -E -A6 'warning:|: error:' >bin/x.1 ## [gcc 8.1 from may'2018] Compiles OK with these CC_WARNINGS and CXX_WARNINGS # CC_WARNINGS = -Wformat-overflow -Wabi -Waddress -Waggressive-loop-optimizations -Walloc-zero -Walloca -Warray-bounds -Wattribute-alias -Wattributes -Wbad-function-cast -Wbool-compare -Wbool-operation -Wbuiltin-declaration-mismatch -Wbuiltin-macro-redefined -Wc90-c99-compat -Wc99-c11-compat -Wcast-align -Wcast-align=strict -Wcast-function-type -Wcast-qual -Wchar-subscripts -Wchkp -Wclobbered -Wcomment -Wcomments -Wconversion -Wcoverage-mismatch -Wcpp -Wdangling-else -Wdate-time -Wdeclaration-after-statement -Wdeprecated -Wdeprecated-declarations -Wdesignated-init -Wdisabled-optimization -Wdiscarded-array-qualifiers -Wdiscarded-qualifiers -Wdiv-by-zero -Wdouble-promotion -Wduplicate-decl-specifier -Wduplicated-branches -Wduplicated-cond -Wempty-body -Wendif-labels -Wenum-compare -Werror-implicit-function-declaration -Werror=implicit-function-declaration -Wexpansion-to-defined -Wfloat-conversion -Wformat -Wformat-contains-nul -Wformat-extra-args -Wformat-security -Wformat-truncation -Wformat-y2k -Wformat-zero-length -Wframe-address -Wfree-nonheap-object -Whsa -Wif-not-aligned -Wignored-attributes -Wignored-qualifiers -Wimplicit -Wimplicit-fallthrough -Wimplicit-function-declaration -Wimplicit-int -Wincompatible-pointer-types -Winit-self -Winline -Wint-conversion -Wint-in-bool-context -Wint-to-pointer-cast -Winvalid-memory-model -Winvalid-pch -Wjump-misses-init -Wlogical-not-parentheses -Wlogical-op -Wlto-type-mismatch -Wmain -Wmaybe-uninitialized -Wmemset-elt-size -Wmemset-transposed-args -Wmisleading-indentation -Wmissing-attributes -Wmissing-braces -Wmissing-declarations -Wmissing-field-initializers -Wmissing-include-dirs -Wmissing-parameter-type -Wmissing-prototypes -Wmultichar -Wmultistatement-macros -Wnarrowing -Wnested-externs -Wnonnull -Wnonnull-compare -Wnormalized -Wnull-dereference -Wodr -Wold-style-declaration -Wold-style-definition -Wopenmp-simd -Woverflow -Woverlength-strings -Woverride-init -Woverride-init-side-effects -Wpacked -Wpacked-bitfield-compat -Wpacked-not-aligned -Wparentheses -Wpedantic -Wpedantic-ms-format -Wpointer-arith -Wpointer-compare -Wpointer-sign -Wpointer-to-int-cast -Wpragmas -Wpsabi -Wrestrict -Wreturn-local-addr -Wreturn-type -Wscalar-storage-order -Wsequence-point -Wshadow -Wshadow-compatible-local -Wshadow-local -Wshadow=compatible-local -Wshadow=global -Wshadow=local -Wshift-count-negative -Wshift-count-overflow -Wshift-negative-value -Wshift-overflow -Wsign-compare -Wsign-conversion -Wsizeof-array-argument -Wsizeof-pointer-div -Wsizeof-pointer-memaccess -Wstack-protector -Wstrict-aliasing -Wstrict-prototypes -Wstringop-overflow -Wstringop-truncation -Wsuggest-attribute=cold -Wsuggest-attribute=const -Wswitch -Wswitch-bool -Wswitch-default -Wswitch-unreachable -Wsync-nand -Wsystem-headers -Wtautological-compare -Wtrampolines -Wtrigraphs -Wtype-limits -Wundef -Wuninitialized -Wunknown-pragmas -Wunreachable-code -Wunused -Wunused-but-set-parameter -Wunused-but-set-variable -Wunused-const-variable -Wunused-function -Wunused-label -Wunused-local-typedefs -Wunused-macros -Wunused-parameter -Wunused-result -Wunused-value -Wunused-variable -Wvarargs -Wvariadic-macros -Wvector-operation-performance -Wvla -Wvolatile-register-var -Wwrite-strings # CXX_WARNINGS = -Wno-old-style-cast -Wno-sign-conversion -Wformat-overflow -Wabi -Waddress -Waggressive-loop-optimizations -Walloc-zero -Walloca -Warray-bounds -Wattribute-alias -Wattributes -Wbool-compare -Wbool-operation -Wbuiltin-declaration-mismatch -Wbuiltin-macro-redefined -Wc++0x-compat -Wc++11-compat -Wc++14-compat -Wc++17-compat -Wc++1z-compat -Wcast-align -Wcast-align=strict -Wcast-function-type -Wcast-qual -Wcatch-value -Wchar-subscripts -Wchkp -Wclass-memaccess -Wclobbered -Wcomment -Wcomments -Wconditionally-supported -Wconversion -Wconversion-null -Wcoverage-mismatch -Wcpp -Wctor-dtor-privacy -Wdangling-else -Wdate-time -Wdelete-incomplete -Wdelete-non-virtual-dtor -Wdeprecated -Wdeprecated-declarations -Wdisabled-optimization -Wdiv-by-zero -Wdouble-promotion -Wduplicated-branches -Wduplicated-cond -Wempty-body -Wendif-labels -Wenum-compare -Werror-implicit-function-declaration -Werror=implicit-function-declaration -Wexpansion-to-defined -Wextra-semi -Wfloat-conversion -Wformat -Wformat-contains-nul -Wformat-extra-args -Wformat-security -Wformat-truncation -Wformat-y2k -Wformat-zero-length -Wframe-address -Wfree-nonheap-object -Whsa -Wif-not-aligned -Wignored-attributes -Wignored-qualifiers -Wimplicit-fallthrough -Winherited-variadic-ctor -Winit-self -Winline -Wint-in-bool-context -Wint-to-pointer-cast -Winvalid-memory-model -Winvalid-offsetof -Winvalid-pch -Wliteral-suffix -Wlogical-not-parentheses -Wlogical-op -Wlto-type-mismatch -Wmain -Wmaybe-uninitialized -Wmemset-elt-size -Wmemset-transposed-args -Wmisleading-indentation -Wmissing-attributes -Wmissing-braces -Wmissing-declarations -Wmissing-field-initializers -Wmissing-include-dirs -Wmultichar -Wmultiple-inheritance -Wmultistatement-macros -Wnarrowing -Wnoexcept -Wnoexcept-type -Wnon-template-friend -Wnon-virtual-dtor -Wnonnull -Wnonnull-compare -Wnormalized -Wnull-dereference -Wodr -Wopenmp-simd -Woverflow -Woverlength-strings -Woverloaded-virtual -Wpacked -Wpacked-bitfield-compat -Wpacked-not-aligned -Wparentheses -Wpedantic -Wpedantic-ms-format -Wplacement-new -Wpmf-conversions -Wpointer-arith -Wpointer-compare -Wpragmas -Wpsabi -Wregister -Wreorder -Wrestrict -Wreturn-local-addr -Wreturn-type -Wscalar-storage-order -Wsequence-point -Wshadow -Wshadow-compatible-local -Wshadow-local -Wshadow=compatible-local -Wshadow=global -Wshadow=local -Wshift-count-negative -Wshift-count-overflow -Wshift-negative-value -Wshift-overflow -Wsign-compare -Wsign-promo -Wsized-deallocation -Wsizeof-array-argument -Wsizeof-pointer-div -Wsizeof-pointer-memaccess -Wstack-protector -Wstrict-aliasing -Wstrict-null-sentinel -Wstringop-overflow -Wstringop-truncation -Wsubobject-linkage -Wsuggest-attribute=cold -Wsuggest-attribute=const -Wswitch -Wswitch-bool -Wswitch-default -Wswitch-unreachable -Wsync-nand -Wsynth -Wsystem-headers -Wtautological-compare -Wterminate -Wtrampolines -Wtrigraphs -Wtype-limits -Wundef -Wuninitialized -Wunknown-pragmas -Wunreachable-code -Wunused -Wunused-but-set-parameter -Wunused-but-set-variable -Wunused-const-variable -Wunused-function -Wunused-label -Wunused-local-typedefs -Wunused-macros -Wunused-parameter -Wunused-result -Wunused-value -Wunused-variable -Wvarargs -Wvariadic-macros -Wvector-operation-performance -Wvirtual-inheritance -Wvirtual-move-assign -Wvla -Wvolatile-register-var -Wwrite-strings # Default targets for make all: bin-lib bin/rbox bin/qconvex bin/qdelaunay bin/qhalf bin/qvoronoi bin/qhull bin/testqset \ bin/testqset_r qtest bin/user_eg2 bin/user_eg3 bin/user_eg qconvex-prompt help: head -n 88 Makefile bin-lib: mkdir -p bin mkdir -p lib @echo "if user_eg or the shared library build fails, other targets remain OK" # Remove intermediate files for all builds # Deletes eg/*.x, *.x, and *.tmp clean: rm -f src/*/*.o src/qhulltest/RoadTest.h.cpp build/*/*/*.o build/*/*.o rm -f src/*/*.obj build/*/*/*.obj build/*/*/*/*/*.obj build/*/*.obj rm -f src/*/gmon.out bin/*.idb lib/*.idb build-cmake/*/*.idb rm -f eg/*.x *.x *.tmp rm -f build/*/*/*.a build/*/*/*.rsp build/moc/*.moc rm -f build-cmake/*/*.obj build-cmake/*/*/*.obj build-cmake/*/*.ilk @echo Remove linked C files from libqhull/ and libqhull_r/ rm -f src/libqhull/rbox.c src/libqhull/qconvex.c src/libqhull/qdelaun.c rm -f src/libqhull/qhalf.c src/libqhull/qvoronoi.c src/libqhull/testqset.c rm -f src/libqhull/unix.c src/libqhull/user_eg.c src/libqhull/user_eg2.c rm -f src/libqhull_r/rbox_r.c src/libqhull_r/qconvex_r.c src/libqhull_r/qdelaun_r.c rm -f src/libqhull_r/qhalf_r.c src/libqhull_r/qvoronoi_r.c src/libqhull_r/testqset_r.c rm -f src/libqhull_r/unix_r.c src/libqhull_r/user_eg_r.c src/libqhull_r/user_eg2_r.c rm -f src/libqhull_r/user_eg3_r.c # Remove intermediate files and targets for all builds # DevStudio prevents build/qhull.ncb deletes cleanall: clean rm -rf build/*.dir/ -rm -rf build/qhull.ncb rm -rf buildvc/ rm -rf buildqt/ rm -rf build-qhull-all*/ rm -rf src/qhull_qh/ rm -rf gmon.out bin/gmon.out rm -f bin/qconvex bin/qdelaunay bin/qhalf bin/qvoronoi bin/qhull rm -f bin/rbox core bin/core bin/user_eg bin/user_eg2 bin/user_eg3 rm -f bin/testqset bin/testqset_r bin/qhulltest rm -f bin/libqhull* bin/qhull*.dll bin/*.exe bin/*.pdb lib/*.pdb rm -f build/*.dll build/*.exe build/*.a build/*.exp rm -f build/*.lib build/*.pdb build/*.idb build/qhull-no-qt.sln rm -f build-cmake/*/*.dll build-cmake/*/*.exe build-cmake/*/*.exp rm -f build-cmake/*/*.lib build-cmake/*/*.pdb rm -f eg/eg.* eg/t*.tmp rm -f lib/libqhull* lib/qhull*.lib lib/qhull*.exp lib/qhull*.dll rm -f src/libqhull*/*.exe src/libqhull*/libqhullstatic*.a src/libqhull*/core rm -f src/libqhull*/qconvex src/libqhull*/qdelaunay src/libqhull*/qhalf rm -f src/libqhull*/qvoronoi src/libqhull*/qhull src/libqhull*/rbox rm -f src/libqhull*/user_eg src/libqhull*/user_eg2 src/libqhull*/user_eg3 doc: $(PRINTMAN) $(TXTFILES) $(DOCFILES) install: bin/qconvex bin/qdelaunay bin/qhalf bin/qhull bin/qvoronoi bin/rbox mkdir -p $(ABS_BINDIR) mkdir -p $(ABS_DOCDIR) mkdir -p $(ABS_DOCDIR)/src mkdir -p $(ABS_INCDIR)/libqhull mkdir -p $(ABS_INCDIR)/libqhull_r mkdir -p $(ABS_INCDIR)/libqhullcpp mkdir -p $(ABS_LIBDIR) mkdir -p $(ABS_MANDIR) mkdir -p $(ABS_PCDIR) cp bin/qconvex $(ABS_BINDIR) cp bin/qdelaunay $(ABS_BINDIR) cp bin/qhalf $(ABS_BINDIR) cp bin/qhull $(ABS_BINDIR) cp bin/qvoronoi $(ABS_BINDIR) cp bin/rbox $(ABS_BINDIR) cp -p html/qhull.man $(ABS_MANDIR)/qhull.1 cp -p html/rbox.man $(ABS_MANDIR)/rbox.1 cp -p README.txt REGISTER.txt Announce.txt COPYING.txt index.htm $(ABS_DOCDIR)/ cp -pr html $(ABS_DOCDIR)/ cp -p src/Changes.txt $(ABS_DOCDIR)/src/ cp -P lib/* $(ABS_LIBDIR) cp src/libqhull/DEPRECATED.txt src/libqhull/*.h $(ABS_INCDIR)/libqhull cp src/libqhull_r/*.h $(ABS_INCDIR)/libqhull_r cp src/libqhullcpp/*.h $(ABS_INCDIR)/libqhullcpp cp src/qhulltest/*.h $(ABS_INCDIR)/libqhullcpp for lib in qhullstatic qhullstatic_r qhull_r qhullcpp; \ do sed \ -e 's#@qhull_VERSION@#$(qhull_VERSION)#' \ -e 's#@CMAKE_INSTALL_PREFIX@#$(PREFIX)#' \ -e 's#@LIB_INSTALL_DIR@#$(LIBDIR)#' \ -e 's#@INCLUDE_INSTALL_DIR@#$(INCDIR)#' \ -e 's#@LIBRARY_NAME@#'$$lib'#' \ -e 's#@LIBRARY_DESCRIPTION@#'$$lib'#' \ build/qhull.pc.in > $(ABS_PCDIR)/$$lib.pc; \ done uninstall: -(cd $(ABS_BINDIR) && rm -f qconvex qdelaunay qhalf qhull qvoronoi rbox) -(cd $(ABS_BINDIR) && rm -f qconvex.exe qdelaunay.exe qhalf.exe qhull.exe qvoronoi.exe rbox.exe libqhull*.dll) -(cd $(ABS_MANDIR) && rm -f qhull.1 rbox.1) -(cd $(ABS_DOCDIR) && rm -f README.txt REGISTER.txt Announce.txt COPYING.txt index.htm src/Changes.txt) -(cd $(ABS_DOCDIR) && rm -rf html) -(cd $(ABS_LIBDIR) && rm -f libqhull*.a libqhull*.dll libqhull*.so* qhull*.lib qhull*.exp) -(cd $(ABS_INCDIR) && rm -rf libqhull_r libqhull libqhullcpp) -(cd $(ABS_PCDIR) && rm -f qhullstatic.pc qhullstatic_r.pc qhull_r.pc qhullcpp.pc) -rmdir $(ABS_DOCDIR)/src -rmdir $(ABS_DOCDIR) new: cleanall all printall: doc printh printc printf printh: $(PRINTC) $(LIBQHULL_HDRS) $(PRINTC) $(LIBQHULLR_HDRS) $(PRINTC) $(LIBQHULLCPP_HDRS) printc: $(PRINTC) $(CFILES) $(PRINTC) $(CXXFILES) $(PRINTC) $(TESTFILES) printf: $(PRINTC) $(FILES) # for Windows, do not depend on bin/qhull,etc. qtest: @echo ============================================ @echo == make qtest ============================== @echo ============================================ @echo -n "== " @date @echo @echo ============================================ @echo == Test non-reentrant qset.c with mem.c ==== @echo ============================================ -bin/testqset 10000 @echo @echo ============================================ @echo == Test reentrant qset_r.c with mem_r.c ==== @echo ============================================ -bin/testqset_r 10000 @echo @echo ============================================ @echo == Run the qhull smoketest ==== @echo ============================================ -bin/rbox D4 | bin/qhull Tv # for Windows, do not depend on bin/qhull,etc. test: qtest @echo ============================================ @echo == make test, after running qtest ========== @echo ============================================ @echo @echo ============================== @echo ========= rbox/qhull ======= @echo ============================== -bin/rbox D4 | bin/qhull Tv @echo @echo ============================== @echo ========= qconvex ============ @echo ============================== -bin/rbox 10 | bin/qconvex Tv @echo @echo ============================== @echo ========= qdelaunay ========== @echo ============================== -bin/rbox 10 | bin/qdelaunay Tv @echo @echo ============================== @echo ========= qhalf ============== @echo ============================== -bin/rbox 10 | bin/qconvex FQ FV n Tv | bin/qhalf Tv @echo @echo ============================== @echo ========= qvoronoi =========== @echo ============================== -bin/rbox 10 | bin/qvoronoi Tv @echo @echo ================================= @echo ========= user_eg =============== @echo == if fails under Windows ======= @echo == cp lib/libqhull_r.dll bin/ == @echo ================================= -bin/user_eg @echo @echo ============================== @echo ========= user_eg2 =========== @echo ============================== -bin/user_eg2 @echo @echo ============================== @echo ========= user_eg3 =========== @echo ============================== -bin/user_eg3 -bin/user_eg3 rbox "10 D2" "2 D2" qhull "s p" facets # make testall >eg/q_test.x 2>&1 testall: test @echo ================================================ @echo == make testall, after running qtest and test == @echo ================================================ @echo -n "== " @date @echo eg/q_eg eg/q_egtest bash -c eg/q_test -eg/q_benchmark test 1 1 1 1 # make benchmark >eg/q_benchmark.x 2>&1 benchmark: @echo ============================================ @echo == make benchmark ========================== @echo == eg/qtest.sh ========================== @echo ============================================ @echo -n "== " @date @echo -eg/q_benchmark -10 -10 -10 -10 # last command for 'make all' qconvex-prompt: bin/qconvex bin/rbox bin/qconvex -? @echo @echo ============================================ @echo == Run the qconvex smoketest @echo ============================================ bin/rbox D4 | bin/qconvex Tv @echo @echo ============================================ @echo == To enable user_eg @echo == @echo == Windows -- make SO=dll @echo '== cp -p lib/libqhull*.dll bin' @echo == @echo == Unix/Macintosh -- make @echo '== export LD_LIBRARY_PATH=$$PWD/lib:$$LD_LIBRARY_PATH' @echo ============================================ @echo @echo ============================================ @echo == To smoketest qhull programs @echo '== make test' @echo ============================================ @echo @echo ============================================ @echo == To run qhull tests for manual review with eg/q_test-ok.txt @echo '== make testall >eg/q_test.x 2>&1' @echo '== make testall 2>&1 | tee eg/q_test.x' @echo ============================================ @echo @echo ============================================ @echo == To install qhull or show help @echo '== make help' @echo '== make install' @echo ============================================ @echo # libqhull is source files for non-reentrant Qhull # libqhull_r is source files and a shared library for reentrant Qhull L= src/libqhull LR= src/libqhull_r # libqhullstatic is a static library for non-reentrant Qhull # libqhullstatic_r is a static library for reentrant Qhull LS= src/libqhullstatic LSR= src/libqhullstatic_r # libqhullcpp is a static library for C++ files and libqhull_r # qhulltest is a Qt test of libqhullcpp LCPP= src/libqhullcpp TCPP= src/qhulltest LIBQHULL_HDRS = $(L)/user.h $(L)/libqhull.h $(L)/qhull_a.h $(L)/geom.h \ $(L)/io.h $(L)/mem.h $(L)/merge.h $(L)/poly.h $(L)/random.h \ $(L)/qset.h $(L)/stat.h LIBQHULLR_HDRS = $(LR)/user_r.h $(LR)/libqhull_r.h $(LR)/qhull_ra.h $(LR)/geom_r.h \ $(LR)/io_r.h $(LR)/mem_r.h $(LR)/merge_r.h $(LR)/poly_r.h $(LR)/random_r.h \ $(LR)/qset_r.h $(LR)/stat_r.h # LIBQHULLS_OBJS and LIBQHULLSR_OBJS ordered by frequency of execution with # small files at end. Better locality. LIBQHULLS_OBJS= $(LS)/global.o $(LS)/stat.o $(LS)/geom2.o $(LS)/poly2.o \ $(LS)/merge.o $(LS)/libqhull.o $(LS)/geom.o $(LS)/poly.o \ $(LS)/qset.o $(LS)/mem.o $(LS)/random.o LIBQHULLS_USER_OBJS = $(LIBQHULLS_OBJS) $(LS)/usermem.o $(LS)/userprintf.o \ $(LS)/io.o $(LS)/user.o LIBQHULLS_RBOX_OBJS = $(LIBQHULLS_USER_OBJS) $(LS)/rboxlib.o $(LS)/userprintf_rbox.o LIBQHULLSR_OBJS = $(LSR)/global_r.o $(LSR)/stat_r.o $(LSR)/geom2_r.o $(LSR)/poly2_r.o \ $(LSR)/merge_r.o $(LSR)/libqhull_r.o $(LSR)/geom_r.o $(LSR)/poly_r.o \ $(LSR)/qset_r.o $(LSR)/mem_r.o $(LSR)/random_r.o LIBQHULLSR_USER_OBJS = $(LIBQHULLSR_OBJS) $(LSR)/usermem_r.o $(LSR)/userprintf_r.o \ $(LSR)/io_r.o $(LSR)/user_r.o LIBQHULLSR_RBOX_OBJS = $(LIBQHULLSR_USER_OBJS) $(LSR)/rboxlib_r.o $(LSR)/userprintf_rbox_r.o LIBQHULLCPP_HDRS = $(LCPP)/RoadError.h $(LCPP)/RoadLogEvent.h $(LCPP)/Coordinates.h \ $(LCPP)/QhullHyperplane.h $(LCPP)/functionObjects.h $(LCPP)/PointCoordinates.h \ $(LCPP)/Qhull.h $(LCPP)/QhullError.h $(LCPP)/QhullFacet.h \ $(LCPP)/QhullFacetList.h $(LCPP)/QhullFacetSet.h $(LCPP)/QhullIterator.h \ $(LCPP)/QhullLinkedList.h $(LCPP)/QhullPoint.h $(LCPP)/QhullPoints.h \ $(LCPP)/QhullPointSet.h $(LCPP)/QhullQh.h $(LCPP)/QhullRidge.h \ $(LCPP)/QhullSet.h $(LCPP)/QhullSets.h $(LCPP)/QhullStat.h $(LCPP)/QhullUser.h \ $(LCPP)/QhullVertex.h $(LCPP)/QhullVertexSet.h $(LCPP)/RboxPoints.h LIBQHULLCPP_OBJS = $(LCPP)/RoadError.o $(LCPP)/RoadLogEvent.o $(LCPP)/Coordinates.o \ $(LCPP)/PointCoordinates.o $(LCPP)/Qhull.o $(LCPP)/QhullFacet.o \ $(LCPP)/QhullFacetList.o $(LCPP)/QhullFacetSet.o \ $(LCPP)/QhullHyperplane.o $(LCPP)/QhullPoint.o $(LCPP)/QhullPoints.o \ $(LCPP)/QhullPointSet.o $(LCPP)/QhullQh.o $(LCPP)/QhullRidge.o \ $(LCPP)/QhullSet.o $(LCPP)/QhullStat.o $(LCPP)/QhullUser.o \ $(LCPP)/QhullVertex.o $(LCPP)/QhullVertexSet.o $(LCPP)/RboxPoints.o # CFILES for non-reentrant Qhull, ordered alphabetically after libqhull.c CFILES= src/qhull/unix.c $(L)/libqhull.c $(L)/geom.c $(L)/geom2.c $(L)/global.c $(L)/io.c \ $(L)/mem.c $(L)/merge.c $(L)/poly.c $(L)/poly2.c $(L)/random.c $(L)/rboxlib.c \ $(L)/qset.c $(L)/stat.c $(L)/user.c $(L)/usermem.c $(L)/userprintf.c $(L)/userprintf_rbox.c \ src/qconvex/qconvex.c src/qdelaunay/qdelaun.c src/qhalf/qhalf.c src/qvoronoi/qvoronoi.c # CFILESR for reentrant Qhull, ordered alphabetically after libqhull.c CFILESR= src/qhull/unix_r.c $(LSR)/libqhull_r.c $(LSR)/geom_r.c $(LSR)/geom2_r.c $(LSR)/global_r.c $(LSR)/io_r.c \ $(LSR)/mem_r.c $(LSR)/merge_r.c $(LSR)/poly_r.c $(LSR)/poly2_r.c $(LSR)/random_r.c $(LSR)/rboxlib_r.c \ $(LSR)/qset_r.c $(LSR)/stat_r.c $(LSR)/user_r.c $(LSR)/usermem_r.c $(LSR)/userprintf_r.c $(LSR)/userprintf_rbox_r.c \ src/qconvex/qconvex_r.c src/qdelaunay/qdelaun_r.c src/qhalf/qhalf_r.c src/qvoronoi/qvoronoi_r.c # CXXFILES for C++ sources using libqhull_r (reentrant qhull), alphabetical CXXFILES= $(LCPP)/Coordinates.cpp $(LCPP)/PointCoordinates.cpp \ $(LCPP)/Qhull.cpp $(LCPP)/QhullFacet.cpp \ $(LCPP)/QhullFacetList.cpp $(LCPP)/QhullFacetSet.cpp \ $(LCPP)/QhullHyperplane.cpp $(LCPP)/QhullPoint.cpp \ $(LCPP)/QhullPoints.cpp $(LCPP)/QhullPointSet.cpp $(LCPP)/QhullQh.cpp \ $(LCPP)/QhullRidge.cpp $(LCPP)/QhullSet.cpp $(LCPP)/QhullStat.cpp $(LCPP)/QhullUser.cpp \ $(LCPP)/QhullVertex.cpp $(LCPP)/QhullVertexSet.cpp $(LCPP)/RboxPoints.cpp \ $(LCPP)/RoadError.cpp $(LCPP)/RoadLogEvent.cpp src/user_eg3/user_eg3_r.cpp # TESTFILES for Qt test of C++ sources using libqhull_r (reentrant qhull), alphabetical after qhulltest.cpp TESTFILES= $(TCPP)/qhulltest.cpp $(TCPP)/Coordinates_test.cpp $(TCPP)/PointCoordinates_test.cpp \ $(TCPP)/Qhull_test.cpp $(TCPP)/QhullFacet_test.cpp $(TCPP)/QhullFacetList_test.cpp \ $(TCPP)/QhullFacetSet_test.cpp $(TCPP)/QhullHyperplane_test.cpp $(TCPP)/QhullLinkedList_test.cpp \ $(TCPP)/QhullPoint_test.cpp $(TCPP)/QhullPoints_test.cpp \ $(TCPP)/QhullPointSet_test.cpp $(TCPP)/QhullRidge_test.cpp \ $(TCPP)/QhullSet_test.cpp $(TCPP)/QhullVertex_test.cpp $(TCPP)/QhullVertexSet_test.cpp \ $(TCPP)/RboxPoints_test.cpp TXTFILES= Announce.txt REGISTER.txt COPYING.txt README.txt src/Changes.txt DOCFILES= html/rbox.txt html/qhull.txt FILES= Makefile src/rbox/rbox.c src/user_eg/user_eg.c src/user_eg2/user_eg2.c \ src/testqset/testqset.c eg/q_test eg/q_egtest eg/q_eg MANFILES= html/qhull.man html/rbox.man # Source code is documented by src/libqhull/*.htm HTMFILES= html/index.htm html/qh-quick.htm html/qh-impre.htm html/qh-eg.htm \ html/qh-optc.htm html/qh-opto.htm html/qh-optf.htm html/qh-optp.htm html/qh-optq.htm \ html/qh-c.htm html/qh-faq.htm html/qhull.htm html/qconvex.htm html/qdelaun.htm \ html/qh-geom.htm html/qh-globa.htm html/qh-io.htm html/qh-mem.htm html/qh-merge.htm \ html/qh-poly.htm html/qh-qhull.htm html/qh-set.htm html/qh-stat.htm html/qh-user.htm \ html/qconvex.htm html/qdelau_f.htm html/qdelaun.htm html/qhalf.htm html/qvoronoi.htm \ html/qvoron_f.htm html/rbox.htm qhull/unix.o: $(L)/libqhull.h $(L)/user.h $(L)/mem.h qconvex/qconvex.o: $(L)/libqhull.h $(L)/user.h $(L)/mem.h qdelanay/qdelaun.o: $(L)/libqhull.h $(L)/user.h $(L)/mem.h qhalf/qhalf.o: $(L)/libqhull.h $(L)/user.h $(L)/mem.h qvoronoi/qvoronoi.o: $(L)/libqhull.h $(L)/user.h $(L)/mem.h qhull/unix_r.o: $(LR)/libqhull_r.h $(LR)/user_r.h $(LR)/mem_r.h qconvex/qconvex_r.o: $(LR)/libqhull_r.h $(LR)/user_r.h $(LR)/mem_r.h qdelanay/qdelaun_r.o: $(LR)/libqhull_r.h $(LR)/user_r.h $(LR)/mem_r.h qhalf/qhalf_r.o: $(LR)/libqhull_r.h $(LR)/user_r.h $(LR)/mem_r.h qvoronoi/qvoronoi_r.o: $(LR)/libqhull_r.h $(LR)/user_r.h $(LR)/mem_r.h $(LS)/libqhull.o: $(LIBQHULL_HDRS) $(LS)/geom.o: $(LIBQHULL_HDRS) $(LS)/geom2.o: $(LIBQHULL_HDRS) $(LS)/global.o: $(LIBQHULL_HDRS) $(LS)/io.o: $(LIBQHULL_HDRS) $(LS)/mem.o: $(L)/mem.h $(LS)/merge.o: $(LIBQHULL_HDRS) $(LS)/poly.o: $(LIBQHULL_HDRS) $(LS)/poly2.o: $(LIBQHULL_HDRS) $(LS)/random.o: $(L)/libqhull.h $(L)/random.h $(L)/user.h $(LS)/rboxlib.o: $(L)/libqhull.h $(L)/random.h $(L)/user.h $(LS)/qset.o: $(L)/qset.h $(L)/mem.h $(LS)/stat.o: $(LIBQHULL_HDRS) $(LS)/user.o: $(LIBQHULL_HDRS) $(LSR)/libqhull_r.o: $(LIBQHULLR_HDRS) $(LSR)/geom_r.o: $(LIBQHULLR_HDRS) $(LSR)/geom2_r.o: $(LIBQHULLR_HDRS) $(LSR)/global_r.o: $(LIBQHULLR_HDRS) $(LSR)/io_r.o: $(LIBQHULLR_HDRS) $(LSR)/mem_r.o: $(LR)/mem_r.h $(LSR)/merge_r.o: $(LIBQHULLR_HDRS) $(LSR)/poly_r.o: $(LIBQHULLR_HDRS) $(LSR)/poly2_r.o: $(LIBQHULLR_HDRS) $(LSR)/random_r.o: $(LR)/libqhull_r.h $(LR)/random_r.h $(LR)/user_r.h $(LR)/mem_r.h $(LSR)/rboxlib_r.o: $(LR)/libqhull_r.h $(LR)/random_r.h $(LR)/user_r.h $(LR)/mem_r.h $(LSR)/qset_r.o: $(LR)/qset_r.h $(LR)/mem_r.h $(LSR)/stat_r.o: $(LIBQHULLR_HDRS) $(LSR)/user_r.o: $(LIBQHULLR_HDRS) $(LCPP)/RoadError.o: $(LCPP)/RoadError.h $(LCPP)/RoadLogEvent.h $(LCPP)/RoadLogEvent.o: $(LCPP)/RoadError.h $(LCPP)/Coordinates.o: $(LIBQHULLCPP_HDRS) $(LIBQHULLR_HDRS) $(LCPP)/PointCoordinates.o: $(LIBQHULLCPP_HDRS) $(LIBQHULLR_HDRS) $(LCPP)/Qhull.o: $(LIBQHULLCPP_HDRS) $(LIBQHULLR_HDRS) $(LCPP)/QhullFacet.o: $(LIBQHULLCPP_HDRS) $(LIBQHULLR_HDRS) $(LCPP)/QhullFacetList.o: $(LIBQHULLCPP_HDRS) $(LIBQHULLR_HDRS) $(LCPP)/QhullFacetSet.o: $(LIBQHULLCPP_HDRS) $(LIBQHULLR_HDRS) $(LCPP)/QhullHyperplane.o: $(LIBQHULLCPP_HDRS) $(LIBQHULLR_HDRS) $(LCPP)/QhullPoint.o: $(LIBQHULLCPP_HDRS) $(LIBQHULLR_HDRS) $(LCPP)/QhullPoints.o: $(LIBQHULLCPP_HDRS) $(LIBQHULLR_HDRS) $(LCPP)/QhullPointSet.o: $(LIBQHULLCPP_HDRS) $(LIBQHULLR_HDRS) $(LCPP)/QhullQh.o: $(LIBQHULLR_HDRS) $(LCPP)/QhullRidge.o: $(LIBQHULLCPP_HDRS) $(LIBQHULLR_HDRS) $(LCPP)/QhullSet.o: $(LIBQHULLCPP_HDRS) $(LIBQHULLR_HDRS) $(LCPP)/QhullStat.o: $(LIBQHULLCPP_HDRS) $(LIBQHULLR_HDRS) $(LCPP)/QhullVertex.o: $(LIBQHULLCPP_HDRS) $(LIBQHULLR_HDRS) $(LCPP)/QhullVertexSet.o: $(LIBQHULLCPP_HDRS) $(LIBQHULLR_HDRS) $(LCPP)/QhullUser.o: $(LIBQHULLCPP_HDRS) $(LIBQHULLR_HDRS) $(LCPP)/RboxPoints.o: $(LIBQHULLCPP_HDRS) $(LIBQHULLR_HDRS) .c.o: $(CC) -c $(CC_OPTS1) -o $@ $< .cpp.o: $(CXX) -c $(CXX_OPTS1) -o $@ $< # qhullx -- Compile qhull without using a qhull library. Must be after LIBQHULLS_RBOX_OBJS # For qconvex, rbox, and other programs, qhullx produces the same results as libqhull/Makefile # For qhull, 'make qhullx' produces the same results as libqhull_r/Makefile qhullx: src/qconvex/qconvex.o src/qdelaunay/qdelaun.o src/qhalf/qhalf.o src/qvoronoi/qvoronoi.o\ src/qhull/unix_r.o src/rbox/rbox.o src/testqset/testqset.o src/testqset_r/testqset_r.o\ $(LIBQHULLS_RBOX_OBJS) $(LIBQHULLSR_USER_OBJS) $(LS)/mem.o $(LS)/qset.o $(LS)/usermem.o mkdir -p bin/ $(CC) -o bin/qconvex $(CC_OPTS2) -lm $(LIBQHULLS_USER_OBJS) src/qconvex/qconvex.o $(CC) -o bin/qdelaunay $(CC_OPTS2) -lm $(LIBQHULLS_USER_OBJS) src/qdelaunay/qdelaun.o $(CC) -o bin/qhalf $(CC_OPTS2) -lm $(LIBQHULLS_USER_OBJS) src/qhalf/qhalf.o $(CC) -o bin/qvoronoi $(CC_OPTS2) -lm $(LIBQHULLS_USER_OBJS) src/qvoronoi/qvoronoi.o $(CC) -o bin/qhull $(CC_OPTS2) -lm $(LIBQHULLSR_USER_OBJS) src/qhull/unix_r.o $(CC) -o bin/rbox $(CC_OPTS2) -lm $(LIBQHULLS_RBOX_OBJS) src/rbox/rbox.o $(CC) -o bin/testqset $(CC_OPTS2) -lm $(LS)/mem.o $(LS)/qset.o $(LS)/usermem.o src/testqset/testqset.o $(CC) -o bin/testqset_r $(CC_OPTS2) -lm $(LSR)/mem_r.o $(LSR)/qset_r.o $(LSR)/usermem_r.o src/testqset_r/testqset_r.o -bin/testqset 10000 -bin/testqset_r 10000 -bin/rbox D4 | bin/qhull # The static library, libqhullstatic, contains non-reentrant code for Qhull. It is somewhat faster than reentrant libqhullstatic_r $(LS)/libqhull.o: $(L)/libqhull.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LS)/geom.o: $(L)/geom.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LS)/geom2.o: $(L)/geom2.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LS)/global.o: $(L)/global.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LS)/io.o: $(L)/io.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LS)/mem.o: $(L)/mem.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LS)/merge.o: $(L)/merge.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LS)/poly.o: $(L)/poly.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LS)/poly2.o: $(L)/poly2.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LS)/random.o: $(L)/random.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LS)/rboxlib.o: $(L)/rboxlib.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LS)/qset.o: $(L)/qset.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LS)/stat.o: $(L)/stat.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LS)/user.o: $(L)/user.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LS)/usermem.o: $(L)/usermem.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LS)/userprintf.o: $(L)/userprintf.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LS)/userprintf_rbox.o: $(L)/userprintf_rbox.c $(CC) -c $(CC_OPTS1) -o $@ $< # The static library, libqhullstatic_r, contains reentrant code with the same behavior as libqhullstatic $(LSR)/libqhull_r.o: $(LR)/libqhull_r.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LSR)/geom_r.o: $(LR)/geom_r.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LSR)/geom2_r.o: $(LR)/geom2_r.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LSR)/global_r.o: $(LR)/global_r.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LSR)/io_r.o: $(LR)/io_r.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LSR)/mem_r.o: $(LR)/mem_r.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LSR)/merge_r.o: $(LR)/merge_r.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LSR)/poly_r.o: $(LR)/poly_r.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LSR)/poly2_r.o: $(LR)/poly2_r.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LSR)/random_r.o: $(LR)/random_r.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LSR)/rboxlib_r.o: $(LR)/rboxlib_r.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LSR)/qset_r.o: $(LR)/qset_r.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LSR)/stat_r.o: $(LR)/stat_r.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LSR)/user_r.o: $(LR)/user_r.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LSR)/usermem_r.o: $(LR)/usermem_r.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LSR)/userprintf_r.o: $(LR)/userprintf_r.c $(CC) -c $(CC_OPTS1) -o $@ $< $(LSR)/userprintf_rbox_r.o: $(LR)/userprintf_rbox_r.c $(CC) -c $(CC_OPTS1) -o $@ $< lib/libqhullstatic.a: $(LIBQHULLS_RBOX_OBJS) @echo ========================================== @echo ==== If 'ar' fails, try 'make qhullx' ==== @echo ========================================== ar -rs $@ $^ #If 'ar -rs' fails, try using 'ar -s' with 'ranlib' #ranlib $@ lib/libqhullstatic_r.a: $(LIBQHULLSR_RBOX_OBJS) ar -rs $@ $^ #ranlib $@ # Do not create libqhullcpp as a shared library. Qhull C++ classes may change layout and size. lib/libqhullcpp.a: $(LIBQHULLCPP_OBJS) ar -rs $@ $^ #ranlib $@ lib/libqhull_r.$(SO): $(LIBQHULLSR_RBOX_OBJS) $(CC) -shared -o $@ $(CC_OPTS3) $^ # the following line fails under MSYS, not needed for SO=dll -(cd lib/ && ln -f -s libqhull_r.$(SO) libqhull_r.so) -(cd lib/ && ln -f -s libqhull_r.$(SO) libqhull_r.$(SONAME_EXT)) # don't use ../qconvex. Does not work on Red Hat Linux bin/qconvex: src/qconvex/qconvex.o lib/libqhullstatic.a $(CC) -o $@ $< $(CC_OPTS2) -Llib -lqhullstatic -lm bin/qdelaunay: src/qdelaunay/qdelaun.o lib/libqhullstatic.a $(CC) -o $@ $< $(CC_OPTS2) -Llib -lqhullstatic -lm bin/qhalf: src/qhalf/qhalf.o lib/libqhullstatic.a $(CC) -o $@ $< $(CC_OPTS2) -Llib -lqhullstatic -lm bin/qvoronoi: src/qvoronoi/qvoronoi.o lib/libqhullstatic.a $(CC) -o $@ $< $(CC_OPTS2) -Llib -lqhullstatic -lm bin/qhull: src/qhull/unix_r.o lib/libqhullstatic_r.a $(CC) -o $@ $< $(CC_OPTS2) -Llib -lqhullstatic_r -lm -chmod +x eg/q_test eg/q_eg eg/q_egtest bin/rbox: src/rbox/rbox.o lib/libqhullstatic.a $(CC) -o $@ $< $(CC_OPTS2) -Llib -lqhullstatic -lm bin/testqset: src/testqset/testqset.o src/libqhull/qset.o src/libqhull/mem.o src/libqhull/usermem.o $(CC) -o $@ $^ $(CC_OPTS2) -lm bin/testqset_r: src/testqset_r/testqset_r.o src/libqhull_r/qset_r.o src/libqhull_r/mem_r.o src/libqhull_r/usermem_r.o $(CC) -o $@ $^ $(CC_OPTS2) -lm # You may use -lqhullstatic_r instead of -lqhull_r bin/user_eg: src/user_eg/user_eg_r.o lib/libqhull_r.$(SO) @echo -e '\n\n===================================================' @echo -e '== If user_eg fails to link on a Windows host, use' @echo -e '== "make SO=dll" and copy lib/libqhull_r.dll to bin/' @echo -e '== Otherwise if user_eg fails to link, switch to -lqhullstatic_r' @echo -e '===================================================\n' $(CC) -o $@ $< $(CC_OPTS1) $(CC_OPTS3) -Llib -lqhull_r -lm bin/user_eg2: src/user_eg2/user_eg2_r.o lib/libqhullstatic_r.a @echo -e '\n\n===================================================' @echo -e '== user_eg2 links to qhullstatic_r. It may use libqhull_r instead.' @echo -e '===================================================\n' $(CC) -o $@ $< $(CC_OPTS2) -Llib -lqhullstatic_r -lm bin/user_eg3: src/user_eg3/user_eg3_r.o lib/libqhullstatic_r.a lib/libqhullcpp.a $(CXX) -o $@ $< $(CXX_OPTS2) -Llib -lqhullcpp -lqhullstatic_r -lm # end of Makefile qhull-2020.2/qhull-2020-src-8.0.2-tgz.md5sum0000644060175106010010000004376113724321437016103 0ustar bbarber65d09ceb4e9b64e6e6ec7a482f2303ec *Announce.txt 0720361ecd968b0dd4d89cf6e8ca2785 *CMakeLists.txt 484ee0cacf0472e8b40225b116f6296c *COPYING.txt f60ca60ab1172bba8ca679e64f1d3b96 *File_id.diz c6392cb46274b9145679419d9666ff84 *Makefile dd1051d9a32f67f84b14d8e841c98532 *QHULL-GO.lnk 54014768f765d484db59ae4f8d8db443 *README.txt dfc60c06612b894244510f7efa338c08 *REGISTER.txt 3df5c1d94c5b624903c46b16a03cc858 *build/CMakeModules/CheckLFS.cmake 87837a71483543335ee384d5f82046ad *build/config.cmake.in 4674d016bfa37816ad225bcf6d9ae2d6 *build/libqhull-32.vcxproj 2586adcb1f68104c6b442a80364060fa *build/libqhull-64.vcxproj 8f844acd13bdea1d0433330b0bb431ca *build/libqhull.vcproj 13cdf2a8dd294cc769921f70b81c9a24 *build/qconvex-32.vcxproj c24abdbe2b3e6a6b33a02f76386cfa8d *build/qconvex-64.vcxproj 009d73f2de59864af22baa0144420263 *build/qconvex.vcproj 29f144075cffa904203d8cceeb1cb817 *build/qdelaunay-32.vcxproj 015a6aa1836f0695ed24643dcef10d3d *build/qdelaunay-64.vcxproj e0cfb73e02bd751ba6e03de423aec448 *build/qdelaunay.vcproj 669d3abe08f776f1fb88573888169261 *build/qhalf-32.vcxproj b7c2f622e0fdcae7568347599a752c13 *build/qhalf-64.vcxproj 62e41a8ab99cce1346d92d8aa25dfa3b *build/qhalf.vcproj 2c3d77ab761390157dd820d8b09acc6b *build/qhull-32.sln eb1c989130db051048e27c9217b86e74 *build/qhull-32.vcxproj 239249d8729e802512203205e999ff5f *build/qhull-64.sln 67be08aa40c8073b7f4bff8d3952845c *build/qhull-64.vcxproj 96e3fc9be110b51d4cf67f8d4c39a7c7 *build/qhull.pc.in 9e4bd2b7739e4416e2e29e974e8705ba *build/qhull.sln 9cb65d19846cbc2055d977e52f9b3f9f *build/qhull.vcproj a255f3a11c112414e6e8558a770ee2d7 *build/qhull_p-32.vcxproj 6dfb8e9e6dd7c20655b6aeec4723aa73 *build/qhull_p-64.vcxproj 4c235c02ab61de1cb42f883996ba47f2 *build/qhull_p.vcproj 7e23bce282e1de9f518f0e3dcfb5e7bb *build/qhull_r-32.vcxproj af6429f2c7b475496234e63ec30280a3 *build/qhull_r-64.vcxproj acaf4abe23157c4c1159fa31d5412a32 *build/qhull_r.vcproj 87da5646b5150757b6a7bd14bef285f0 *build/qhullcpp-32.vcxproj 9c88330b04a21958fb4e864155523012 *build/qhullcpp-64.vcxproj 0a6605fa121cc63a9dab9c6b7e023ff2 *build/qhullcpp.vcproj 6277fea4325996336f0a81fa492a8528 *build/qhullstatic-32.vcxproj 8ae5f938a03f4edb28e0b21c96651436 *build/qhullstatic-64.vcxproj 63014725677aaf48bd9c39537480c4c2 *build/qhullstatic.vcproj 2f65933fc8ab244e7e8128111fe26c21 *build/qhullstatic_r-32.vcxproj 921fa3a27d5d4bdcac5ddd433f312f09 *build/qhullstatic_r-64.vcxproj 0fc1b5f0000da84f94d98c0834fd3d74 *build/qhullstatic_r.vcproj b50d39ba520c29b4244a886f93755129 *build/qvoronoi-32.vcxproj d875bde97f78d26f51d06800d60f4920 *build/qvoronoi-64.vcxproj 1ec841a1f6b2ce527aa921881ee7bd5e *build/qvoronoi.vcproj 3df85e67e03b6055c1f87dbece9f1f49 *build/rbox-32.vcxproj 0ce917ab6d57ba7f45af1291eabe8a67 *build/rbox-64.vcxproj 29f806fb2500e21d167b3519e31f3cb8 *build/rbox.vcproj e4d6dd9fdf1d4beb8a4de7846357a043 *build/testqset-32.vcxproj 9f610bb6508af3569e40227ae8c6134f *build/testqset-64.vcxproj 180df169e114aa5681a3b74cde5d9723 *build/testqset.vcproj 7c3d6eac7ea0ce73f13ae30a7724158a *build/testqset_r-32.vcxproj e7c8117ce1911f111f8c7af65ce2e38f *build/testqset_r-64.vcxproj abeb1b1c369c8befdfc15c30fbb0fd68 *build/testqset_r.vcproj 5fcff78b8a26f2cea4874325b1e68514 *build/user_eg-32.vcxproj a670399d6dd14a23e5d7c76e5268cda2 *build/user_eg-64.vcxproj e9b976dc3b2805a36b2006f93e5a257e *build/user_eg.vcproj 10dc74407641cc1f68999ae5f697a65d *build/user_eg2-32.vcxproj 473f1a98f684e1911d1e193fe8b44ca5 *build/user_eg2-64.vcxproj 1f8b42dabb6de8fbfd8956a07e646031 *build/user_eg2.vcproj 8b087c9c5a24c948100057ea490fdb6f *build/user_eg3-32.vcxproj 0158d73fe951d890949ca40a5da88c5a *build/user_eg3-64.vcxproj c8dc2e931a45dfe3aebeca085652e2f5 *build/user_eg3.vcproj a7c173113017aeac4a2f15cb0c391ad8 *eg/Qhull-go.bat e7b1c17bc19c003c26de72467a258605 *eg/make-qhull_qh.sh 89a30e16de271af01489ee6797576af7 *eg/make-vcproj.sh 5d92b824631d802afa304e93db37f186 *eg/q_benchmark 4f8c270a19a4654a411ee30c2de3b3ef *eg/q_benchmark-ok.txt ed8a87186ca51f3aef86c7098d53ea51 *eg/q_eg e8240a2c4c33aab2e6b1cf1681991664 *eg/q_egtest b29fe52be86de37cfd8bf6991d9098d2 *eg/q_test f0f27d75bbd37c2e618bca2f103dba43 *eg/q_test-ok.txt 29f540676a6eaafbc380eebf60aeb2d2 *eg/q_test.bat 03757af90de48525c4e2016820d33eae *eg/qhull-zip.sh c09360b40198e3bc8757fba186b85f4a *eg/qhulltest-ok.txt 5aee776ff7b0656ebef048346794fbef *eg/qtest.sh f4297aeec0354656c3efc99ea4cda387 *html/index.htm 59e9b69f186c9e715192df9e146ebd21 *html/normal_voronoi_knauss_oesterle.jpg 1cdddaa03a2575e7ff07638959fb9fe0 *html/qconvex.htm f167803bdc16a07fa23b2a31924abbdb *html/qdelau_f.htm a1a1518d37463a204c580d417550b408 *html/qdelaun.htm bb51e7810cc49e5aff1b910bc3126713 *html/qh--4d.gif 687f459f95e958da6c3ff0c83cafcf46 *html/qh--cone.gif dc51084bc7ba1f235c71d40c771ce9c8 *html/qh--dt.gif 829df3fbc9a3f36dbdb6389f768b5570 *html/qh--geom.gif 0587393a4591c5fbcd040af9a4f510c7 *html/qh--half.gif 0515fcc283b7dfeeaa7169218722880e *html/qh--rand.gif a63772a7b7c405bc97b37e8ee2f001dd *html/qh-code.htm e69cab72cd604f1e9aafce840e6306bf *html/qh-eg.htm 974ed918de1aa1105188dd4dc4a497bd *html/qh-faq.htm 0cea0d5a050266c7abe886d2cfa3b75e *html/qh-get.htm b59cd55b5b6f16737dc6075e647330c2 *html/qh-impre.htm 4383c32994b7330c7de53661dd0c51ec *html/qh-optc.htm 268899c7634da8acf9e31cd977481b93 *html/qh-optf.htm d06e302804f8b290266fc17e87332265 *html/qh-optg.htm 3471d4c6f65572ee0bf78dfccd99487e *html/qh-opto.htm da400a2bb032dda9888aea225ebb0db8 *html/qh-optp.htm f1916f39734895c9289aec380695e407 *html/qh-optq.htm ec16627e14caf0d8f79f8cc651fc9b26 *html/qh-optt.htm 5367b3e99373755d5744a34ac1d22d6c *html/qh-quick.htm 6112b359d174db3a32c575236b65fb90 *html/qh_findbestfacet-drielsma.pdf a183d4bf20cff3db7013dd5ccc475f05 *html/qhalf.htm da2fe3fd695ceae9437aca693e1fe76b *html/qhull-cpp.xml 9f48e440a7f28da3eef2fe9d0758961a *html/qhull.htm 5afb7d83533ac6d38303103c9936e8a3 *html/qhull.man ae0e659a7472f6387fddd46d5379ee84 *html/qhull.txt 031fe69b5db5e87cac77db517e9de804 *html/qvoron_f.htm f6f23918c9f7eb29e5fce2f26d12425e *html/qvoronoi.htm 30c848ff6f5cd7f4218e4270f0459e3b *html/rbox.htm 4cbad586d2136f611dbaf7f47128cc86 *html/rbox.man 61cd54c422366e1ef1db2babdb3daff9 *html/rbox.txt 8116baf92dcda379767f7a23a6549cf5 *index.htm e9215a2ce69ac30bfd31b51d1d0dc5f3 *src/Changes.txt 7611837185670c6d7f8768c29d239339 *src/libqhull/DEPRECATED.txt 17a6ffbaabc242df0e5ffebf655d2084 *src/libqhull/Makefile e76b4786a5fa7197784c0dcf98e3949f *src/libqhull/Mborland 29be4610c7fd8a1052ed3e41e384bfac *src/libqhull/geom.c 3a98ef14c7671e39a17266276c8c9794 *src/libqhull/geom.h d27392944e8b4895fc3aff6db97c3f50 *src/libqhull/geom2.c d9597f7a4eb8d39a16651fde58c863a0 *src/libqhull/global.c 39dd11d4ba1c16a11778577cc95a502d *src/libqhull/index.htm 518dbab7e087dd40c5c427e31dc57e13 *src/libqhull/io.c bc74bab30ca533ba3c85adb2c2708345 *src/libqhull/io.h 24346b91ddf45b75beedc254127df09b *src/libqhull/libqhull.c 97eeb276efecf399603313581ffeeabf *src/libqhull/libqhull.h 6b4f63226f2b9e7a4e92ed662dfbfc96 *src/libqhull/libqhull.pro 2dbf0bb26d822d217bc07ba7a114a370 *src/libqhull/mem.c 9574f63f06d0eb11317e498dbdf7eabe *src/libqhull/mem.h 0bfd96e51cf797d2545eb3724ae1add7 *src/libqhull/merge.c ffba845661c716508d5e4d6bf35db574 *src/libqhull/merge.h efbfd8c26ac93227e765f83f1ac0da22 *src/libqhull/poly.c 6f92baf68e56456a1b5a69e4ac527cf9 *src/libqhull/poly.h 91110c28f82bb4f21f8d1d118a64e365 *src/libqhull/poly2.c 6bb99f305df73fe577fd7042c6e4bd86 *src/libqhull/qh-geom.htm c577ca0f1516d07b435dfe08fec26364 *src/libqhull/qh-globa.htm 58fc73009db00fef28bf9990e73bee36 *src/libqhull/qh-io.htm 892166aee9a777e395b5e86bbdc78267 *src/libqhull/qh-mem.htm e944d190b08235150b92895074f18ede *src/libqhull/qh-merge.htm e8c9a7a70a66b5c7255ca8744fee5607 *src/libqhull/qh-poly.htm 4b493275f0a5bb23c25b09ae2f73921c *src/libqhull/qh-qhull.htm dc6914bc6c0c78ea99509e8685e49002 *src/libqhull/qh-set.htm 93266af6121082853a4f25557c00689e *src/libqhull/qh-stat.htm 02733f3342523af8b902e3d86a4fa794 *src/libqhull/qh-user.htm 987aa6e3464982b90af168173103625a *src/libqhull/qhull-exports.def fcd57bbb666943b18f3a2ee7a9a937d7 *src/libqhull/qhull-nomerge-exports.def d365ec42ee899a7914ff573ce114c5d1 *src/libqhull/qhull_a.h 83eba4edf07391024705d5bcc98b602d *src/libqhull/qhull_p-exports.def 1af9f55067eb6c50dc542f4f865ccaae *src/libqhull/qhull_p-nomerge-exports.def c031da674e4a4af9288e1235043e81a2 *src/libqhull/qset.c 700c0c8549947cecc0267bea3bb1b2c9 *src/libqhull/qset.h 249358a8f4227fcfd476a086f30d8aee *src/libqhull/random.c 4cf4514863c130058efc8f0733bb71b1 *src/libqhull/random.h c40e01c0f66cf2d10f2c486af831bdfa *src/libqhull/rboxlib.c c5f9cda941242f1dbd5b023ef9169df7 *src/libqhull/stat.c fcc7ee0199c523179d5bb760da31390d *src/libqhull/stat.h 5bb1d2cca19dc70182c9682981e3b937 *src/libqhull/user.c 35079e6ef420737d76d74db09d262b01 *src/libqhull/user.h bea66689b7321f3beb49ff3339175c75 *src/libqhull/usermem.c 73eed50a9986c51816fefcf38b12fa2c *src/libqhull/userprintf.c 64f1f7ed6c6016632bf29b9feef0d599 *src/libqhull/userprintf_rbox.c ed08b3fa49e20cc05d9f71b643799dc5 *src/libqhull_r/Makefile 876c09adad390e33d27f72fbb6dc520d *src/libqhull_r/geom2_r.c b5bfc1b056f16945579951686dc2c428 *src/libqhull_r/geom_r.c cfde24c128897c30273de690cfb8ad20 *src/libqhull_r/geom_r.h 7f6bb4819c9a4abbf9ad638892fa27cb *src/libqhull_r/global_r.c 7289aa97c84335378ac7bc84c84cac04 *src/libqhull_r/index.htm 580b19ed605ab74265254d47d020e14e *src/libqhull_r/io_r.c ebd7597c25e31f815e819da068e9914f *src/libqhull_r/io_r.h b6910ea39f0797da7489f4421c9b88ea *src/libqhull_r/libqhull_r.c c159399ed03809f06c240d31f274de7f *src/libqhull_r/libqhull_r.h f4bf5aab9cfdfd35e00dc8330fb60e61 *src/libqhull_r/libqhull_r.pro 8275d12edcabef504d1a39db3680bd09 *src/libqhull_r/mem_r.c e7a552cf8e5b47a75b6b9fd0eaf0b4cf *src/libqhull_r/mem_r.h 746094f172d5e194a3b6c857a554e397 *src/libqhull_r/merge_r.c 905850f71545d3b4d2d3d0811035eb3d *src/libqhull_r/merge_r.h 3e5c51d6c3a002eb661060b51be47fef *src/libqhull_r/poly2_r.c f28a42b955f615484659d25f4d40bc72 *src/libqhull_r/poly_r.c 73b0c0b388910469d2faae58a39ebca6 *src/libqhull_r/poly_r.h 484078e99a3fde0bd0daa99f4a1fd56b *src/libqhull_r/qh-geom_r.htm d7851a9939651e33ec7489c0e5085339 *src/libqhull_r/qh-globa_r.htm 7f7aa31b68cc8791ee8d210080404289 *src/libqhull_r/qh-io_r.htm 35606a644f52da36dd52bb72393383e9 *src/libqhull_r/qh-mem_r.htm 5735de0188677d8cc69d4e54372327da *src/libqhull_r/qh-merge_r.htm c71f6df7047165a05b427f1103b40664 *src/libqhull_r/qh-poly_r.htm b9c36e566998129216c3de8e14917c6c *src/libqhull_r/qh-qhull_r.htm 7ad1ad9102c469a634f776a8776f731f *src/libqhull_r/qh-set_r.htm a6ea3edf6fe83fcc4144189ffad0e551 *src/libqhull_r/qh-stat_r.htm 7ac470e4d33d52f6b25b368de3c95b92 *src/libqhull_r/qh-user_r.htm 2e497193088e1b6ae5381657cc343dd9 *src/libqhull_r/qhull_r-exports.def cb49262f5a240674ab152fd95f4bb945 *src/libqhull_r/qhull_r-nomerge-exports.def 52fcd7e36336fd312c022fce2c45edf5 *src/libqhull_r/qhull_ra.h 5442309186618a5774230daaba3c74ab *src/libqhull_r/qset_r.c 47f8171b0fbe74280bb1299fd8a6ef8d *src/libqhull_r/qset_r.h f498e0602fba35e60a1080f3918b99c4 *src/libqhull_r/random_r.c a1fe43bed99882c8c850ea6f0ae15ecd *src/libqhull_r/random_r.h 9d1c472d83fb77b0c0b1499b851432dd *src/libqhull_r/rboxlib_r.c 278521cfead70046b36b59b17bbaeb15 *src/libqhull_r/stat_r.c ee0baf81125db01bf0bc29f4c2a3c33f *src/libqhull_r/stat_r.h 27987c9ca25ddb728b7de06abeffd039 *src/libqhull_r/user_r.c 560946c6d1a20ac71211e1d76f3b5f78 *src/libqhull_r/user_r.h a6c60a2391b6beda18f4261707cb8090 *src/libqhull_r/usermem_r.c 61cd83f3c0639f8e6933f5a15b6c229c *src/libqhull_r/userprintf_r.c cc32478b6848d9938c0c5c2832e4869b *src/libqhull_r/userprintf_rbox_r.c f5cbe73af7fc4edac17f6d62924e02d0 *src/libqhullcpp/Coordinates.cpp 661eca245e61cced9e373aa6871148e2 *src/libqhullcpp/Coordinates.h 34a2dd1f51d4ecbf2fe3e9f6f0039f9b *src/libqhullcpp/PointCoordinates.cpp 1b63708c316032fe0a9e42cc254fb6c6 *src/libqhullcpp/PointCoordinates.h be371d83a58bd9f6811c122223b31936 *src/libqhullcpp/Qhull.cpp 471ff2463d651b96ff7294145ef8434c *src/libqhullcpp/Qhull.h 0c2543742f613ed0e75b14af5b8a1f07 *src/libqhullcpp/QhullError.h a4a2f2cc79ee68ad1a89cc0674d3d6c6 *src/libqhullcpp/QhullFacet.cpp 4445abbcb8d44364a7e99ccdc459bf8e *src/libqhullcpp/QhullFacet.h 20d2c8ddff36ef52bf09905dd45f7506 *src/libqhullcpp/QhullFacetList.cpp ea55403677477a66a944356ea41c5005 *src/libqhullcpp/QhullFacetList.h c1a4cf0f760882fb975250dba78c6732 *src/libqhullcpp/QhullFacetSet.cpp 2d8373e1574a89585526d75371f7f261 *src/libqhullcpp/QhullFacetSet.h 894c0cb4aab042c1a39c09ea621c46b5 *src/libqhullcpp/QhullHyperplane.cpp 8d88d655dca7732cef5591c8b68f1ad0 *src/libqhullcpp/QhullHyperplane.h 5778fcfe6e9993c684d48f467dd9e589 *src/libqhullcpp/QhullIterator.h a65b84f48f62431879a5b94b5e77238e *src/libqhullcpp/QhullLinkedList.h f1f4c76f261dad68d68c10ec7934ac34 *src/libqhullcpp/QhullPoint.cpp 0fd012acd20be74c0ce15f49a7d8d466 *src/libqhullcpp/QhullPoint.h 60238b90770fbeb302d1c1821b211cfe *src/libqhullcpp/QhullPointSet.cpp c8359ae483b46ca4cdf46df5e54c97ca *src/libqhullcpp/QhullPointSet.h 0b553aa2f07b93037d8cb4498db7b30a *src/libqhullcpp/QhullPoints.cpp 4c2b9b4ae4a24cdf7509c68d6f70e02d *src/libqhullcpp/QhullPoints.h 9f4621c4383ee7649a8654ed397729fc *src/libqhullcpp/QhullQh.cpp 18a16fc501e731277d56f052d694f28a *src/libqhullcpp/QhullQh.h 7adf5a94b243eefea6848ab59e234dac *src/libqhullcpp/QhullRidge.cpp 344512c37d10a06ac1b764f5affc0b46 *src/libqhullcpp/QhullRidge.h d7d9c4db6a94c808a1b90ec889b3562a *src/libqhullcpp/QhullSet.cpp 507cf1e784f462356901e180698514e9 *src/libqhullcpp/QhullSet.h 2f946b07ef3d44c65df9aa7cfcf710a8 *src/libqhullcpp/QhullSets.h 9358bbb3f43b27be0df52e781b048d73 *src/libqhullcpp/QhullStat.cpp f58ec9baf5fb04134b120c9ea66caeac *src/libqhullcpp/QhullStat.h 3605fa52376508c46b898f674fd5d8e2 *src/libqhullcpp/QhullUser.cpp 51d2f3ec5e46d07c888a228a9020bb25 *src/libqhullcpp/QhullUser.h 9c990237932a4df67c70634bef628e94 *src/libqhullcpp/QhullVertex.cpp 0c0f98b2de607a6469ac729cc75f6ffe *src/libqhullcpp/QhullVertex.h 17cab27891d47a7fdaeddb22b9cfae22 *src/libqhullcpp/QhullVertexSet.cpp 406c264a9732864b996b29ff8ae30864 *src/libqhullcpp/QhullVertexSet.h a27237c31d6b33a2db440fbfc8a17d9f *src/libqhullcpp/RboxPoints.cpp 639bef41ece0d409b3e9307d0829b0fd *src/libqhullcpp/RboxPoints.h de273e0fca7f3b2e6151e21cc0f317b9 *src/libqhullcpp/RoadError.cpp eb11e1a3de896aa19e96ce009c80db70 *src/libqhullcpp/RoadError.h a1f89e5ee8a5330485dcdfc24c819cb3 *src/libqhullcpp/RoadLogEvent.cpp 1efd4679fb346c162a52a98038f0187c *src/libqhullcpp/RoadLogEvent.h 2e1c39222d819ae6752a44092fb9d2b8 *src/libqhullcpp/functionObjects.h 88ac335866b28a3b8a3a2ac6aa8e35f0 *src/libqhullcpp/libqhullcpp.pro 10a6c51f22c670291f5c954c55fa1dd3 *src/libqhullcpp/qt-qhull.cpp f4dd3fa77a518897eb438efb78504499 *src/libqhullcpp/usermem_r-cpp.cpp b4752f1c7e6e6bdf90f2fafafabe324b *src/libqhullstatic/libqhullstatic.pro b22e10e89694ba6ce3c6a285b47e2f86 *src/libqhullstatic_r/libqhullstatic_r.pro 7e262184ff18ff86eac57c804833066b *src/qconvex/qconvex.c 4ea25c0ef260f5d1c1f59326f1439997 *src/qconvex/qconvex.pro ced1f28f5bd14198924cc163e87fe42a *src/qconvex/qconvex_r.c 205ef0e37e997a72920092543640dc82 *src/qdelaunay/qdelaun.c c829859a93554bbd2a0f9746ee92a968 *src/qdelaunay/qdelaun_r.c ae7da22e7e39cc39f54b5bc4f8f68b47 *src/qdelaunay/qdelaunay.pro 8374447cb68fe7ac8e7285c7b6b1dd58 *src/qhalf/qhalf.c eea5fc6e1ff79d68e05a525a7d2f5d82 *src/qhalf/qhalf.pro 977f29fdd977858d66e6882eb1ec66f0 *src/qhalf/qhalf_r.c ad3a57f1dbc582419fc5dae51d0fe852 *src/qhull-all.pro 0d3de78f61956b9b68741ba5b80bf801 *src/qhull-app-c.pri b91314146b69e2a45d791ce5e9410548 *src/qhull-app-c_r.pri 11aa141df627d7ec2da4e468c3dc4fdc *src/qhull-app-cpp.pri b6eda0a529088b9cc4b9b84afc2a47c6 *src/qhull-app-shared.pri ea2dba27c9f027aa6ed059337ea833f9 *src/qhull-app-shared_r.pri 6c2b47785a0fa76099cc6470b99e5046 *src/qhull-libqhull-src.pri 2d671d08665952d503d45a8470fc74c0 *src/qhull-libqhull-src_r.pri c96cb18ac8bf7b518bfb83bde5b4ddf4 *src/qhull-warn.pri 094c90c389b9929d514f4c045cd3cee5 *src/qhull/qhull.pro bab640b4ea8a53d344c3de39870a821a *src/qhull/unix.c b34388a871e1eb7b98dd0802cae20dfd *src/qhull/unix_r.c ab9a7520696cbaf5c16df416795c3882 *src/qhulltest/Coordinates_test.cpp c43036f7ce1c46ba0d4865d23bcd5b16 *src/qhulltest/PointCoordinates_test.cpp a7b6c5b507c80f79d0d3bc1e193195dc *src/qhulltest/QhullFacetList_test.cpp 171133a2056271755595ba3610b3dfa4 *src/qhulltest/QhullFacetSet_test.cpp cd5915244c632c19572c450be8424f3f *src/qhulltest/QhullFacet_test.cpp 6d802824b6ff4a45b3480e4214051b97 *src/qhulltest/QhullHyperplane_test.cpp 38a7bf1e5d36bc6d41cb2c0820f16191 *src/qhulltest/QhullLinkedList_test.cpp 37339b5e045661851eb65905be468394 *src/qhulltest/QhullPointSet_test.cpp 8c85f653155f3249244085deab2708f2 *src/qhulltest/QhullPoint_test.cpp b4c1f5408312f23c6fcdd6c67c6a1b7b *src/qhulltest/QhullPoints_test.cpp c9d97adc646c547bdc575468192f5167 *src/qhulltest/QhullRidge_test.cpp 3ae11e276cf75a0137edefbca4309a6b *src/qhulltest/QhullSet_test.cpp bbc4cbc1ccfd59714b951068474ef85d *src/qhulltest/QhullVertexSet_test.cpp ed340cf36d74d377c061d596bc10222e *src/qhulltest/QhullVertex_test.cpp 23199a0ae3f2824cb88258f1918a6d98 *src/qhulltest/Qhull_test.cpp 827f34b2911fa14abec9143f78189866 *src/qhulltest/RboxPoints_test.cpp b3de8b9ba6a904c82fc7c78a1766c16b *src/qhulltest/RoadTest.cpp ca7c9840fbbeb6ebf1b56ea647a831b9 *src/qhulltest/RoadTest.h 7dbad30230b7b123e1172c1191ad8085 *src/qhulltest/qhulltest.cpp 00fe5c4317a03cb83009b7a622a20170 *src/qhulltest/qhulltest.pro ab8b936d7aed5b34965773d5e4840460 *src/qvoronoi/qvoronoi.c fbeca66e16029e38c1ecfef02294387d *src/qvoronoi/qvoronoi.pro 42c25a668e35cd7aa8c6cac0b1de241f *src/qvoronoi/qvoronoi_r.c 63854e191e68440b691df57c19d47e10 *src/rbox/rbox.c 8528e43a27c17806d447b2bb20842aa0 *src/rbox/rbox.pro a68b116647242e9111e8e7f19ff62d95 *src/rbox/rbox_r.c 7fc05de3e183a5de6712b391caaa79cf *src/testqset/testqset.c 8424a44ea97cc3f5bd1a04b74815bdb1 *src/testqset/testqset.pro d87fa8259226adb84bc80cd5cb31e6a7 *src/testqset_r/testqset_r.c b0953b95725a8782f192afea4fa469e7 *src/testqset_r/testqset_r.pro df1e678a01abd7d0328cc0b9e85374e5 *src/user_eg/user_eg.c a1c77e28793f660109ceb46c904e3e7d *src/user_eg/user_eg.pro 63fa2c535d8c152eb537f13337b7caa2 *src/user_eg/user_eg_r.c 49d35f12ff9400608884a6f115963a1a *src/user_eg2/user_eg2.c a0bbf00f860f4cbbccada014cfc995e1 *src/user_eg2/user_eg2.pro 6a2977b32d1dade9af65e267488c8b14 *src/user_eg2/user_eg2_r.c d7c41d0a8ffeae7a484cbab75d251b3a *src/user_eg3/user_eg3.pro 2a4a48ccfd29a8c3df92f8b2c64e373d *src/user_eg3/user_eg3_r.cpp qhull-2020.2/QHULL-GO.lnk0000755060175106010010000000266711663044625013111 0ustar bbarberLF G^i}nz'PO :i+00/C:\<1m?0WINDOWS&ル86Jw? WINDOWS@1w?0system32(ル86Jw? system32<28` cmd.exe&ル8w?cmd.exeL/KDOSC:\WINDOWS\system32\cmd.exe!..\..\..\WINDOWS\system32\cmd.exe/K eg\Qhull-go.bat!%SystemRoot%\system32\SHELL32.dll`Xispy~..~Kz.ἠ$)A~..~Kz.ἠ$)A%SystemRoot%\System32\cmd.exe%\System32\cmd.exe \K eg\Qhull-go.bat%SystemRoot%\System32\cmd.exex ]|:(:d\|a|:@d |:t0||:@x 9B~\&@``d``d}w}w<>w>w@x 01|1| lY/|a/|.| 0 <=\ؚ|h/|a/|i?w%qhull-2020.2/README.txt0000644060175106010010000006657113724311755012713 0ustar bbarberName qhull, rbox 2020.2 2020/08/31 (8.0.2) Convex hull, Delaunay triangulation, Voronoi diagrams, Halfspace intersection Documentation: html/index.htm Available from: (git@github.com:qhull/qhull.git) News and a paper: Version 1 (simplicial only): Purpose Qhull is a general dimension convex hull program that reads a set of points from stdin, and outputs the smallest convex set that contains the points to stdout. It also generates Delaunay triangulations, Voronoi diagrams, furthest-site Voronoi diagrams, and halfspace intersections about a point. Rbox is a useful tool in generating input for Qhull; it generates hypercubes, diamonds, cones, circles, simplices, spirals, lattices, and random points. Qhull produces graphical output for Geomview. This helps with understanding the output. Environment requirements Qhull and rbox should run on all 32-bit and 64-bit computers. Use an ANSI C or C++ compiler to compile the program. The software is self-contained. It comes with examples and test scripts. Qhull's C++ interface uses the STL. The C++ test program uses QTestLib from the Qt Framework. Qhull is copyrighted software. Please read COPYING.txt and REGISTER.txt before using or distributing Qhull. To cite Qhull, please use Barber, C.B., Dobkin, D.P., and Huhdanpaa, H.T., "The Quickhull algorithm for convex hulls," ACM Trans. on Mathematical Software, 22(4):469-483, Dec 1996, http://www.qhull.org. To modify Qhull, particularly the C++ interface Qhull is on GitHub (http://github.com/qhull/qhull/wiki, git@github.com:qhull/qhull.git) For internal documentation, see html/qh-code.htm To install Qhull Qhull is precompiled for Windows 32-bit, otherwise it needs compilation. Qhull includes Makefiles for gcc and other targets, CMakeLists.txt for CMake, .sln/.vcproj/.vcxproj files for Microsoft Visual Studio, and .pro files for Qt Creator. It compiles under Windows with mingw. () Install and build instructions follow. See the end of this document for a list of distributed files. ------------------ Index Installing Qhull on Windows 10, 8, 7 (32- or 64-bit), Windows XP, and Windows NT Installing Qhull on Unix with gcc Installing Qhull with CMake 2.6 or later Installing Qhull with Qt Working with Qhull's C++ interface Calling Qhull from C programs Compiling Qhull with Microsoft Visual C++ Compiling Qhull with Qt Creator Compiling Qhull with mingw/gcc on Windows Compiling Qhull with cygwin on Windows Compiling from Makfile without gcc Compiling on other machines and compilers Distributed files Authors ------------------ Installing Qhull on Windows 10, 8, 7 (32- or 64-bit), Windows XP, and Windows NT The zip file contains rbox.exe, qhull.exe, qconvex.exe, qdelaunay.exe, qhalf.exe, qvoronoi.exe, testqset.exe, user_eg*.exe, documentation files, and source files. Qhull.exe and user-eg3.exe are compiled with the reentrant library while the other executables use the non-reentrant library. To install Qhull: - Unzip the files into a directory (e.g., named 'qhull') - Click on QHULL-GO or open a command window into Qhull's bin directory. - Test with 'rbox D4 | qhull' To uninstall Qhull - Delete the qhull directory To learn about Qhull: - Execute 'qconvex' for a synopsis and examples. Or 'qconvex --help' or 'qconvex -?' - Execute 'rbox 10 | qconvex' to compute the convex hull of 10 random points. - Execute 'rbox 10 | qconvex i TO file' to write results to 'file'. - Browse the documentation: qhull\html\index.htm - If an error occurs, Windows sends the error to stdout instead of stderr. Use 'TO xxx' to send normal output to xxx To improve the command window - Double-click the window bar to increase the size of the window - Right-click the window bar - Select Properties - Check QuickEdit Mode Select text with right-click or Enter Paste text with right-click - Change Font to Lucinda Console - Change Layout to Screen Buffer Height 999, Window Size Height 55 - Change Colors to Screen Background White, Screen Text Black - Click OK - Select 'Modify shortcut that started this window', then OK If you regularly use qhull on a Windows host, install a bash shell such as https://gitforwindows.org/ # based on MSYS2 https://github.com/git-for-windows/git/wiki http://www.msys2.org/ https://github.com/msys2/msys2/wiki [mar'19] Git for Windows v2.21 requires 'qhull --help' Install in C:\Git\... # Not 'Program Files\...' otherwise './configure && make' fails www.cygwin.com www.mingw.org/wiki/msys # for Windows XP Road Bash (www.qhull.org/bash) # based on MSYS ------------------ Installing Qhull on Unix with gcc To build Qhull, static libraries, shared library, and C++ interface - Download and extract Qhull (either GitHub, .tgz file, or .zip file) - make - export LD_LIBRARY_PATH=$PWD/lib:$LD_LIBRARY_PATH - make test 'make install' installs Qhull at '/usr/local/'. It installs pkg-config files at '/usr/local/lib/pkgconfig'. Change the install directory with DESTDIR and PREFIX. To build 32-bit Qhull on a 64-bit host (uses 33% less memory in 4-d) - make new M32=-m32 To build 32-bit Qhull without -fpic (may be faster, but shared library may fail) - make new M32=-m32 FPIC= The Makefiles may be edited for other compilers. If 'testqset' exits with an error, qhull is broken A simple Makefile for Qhull is in src/libqhull and src/libqhull_r. To build the Qhull executables and libqhullstatic - Extract Qhull from qhull...tgz or qhull...zip - cd src/libqhull_r # cd src/libqhull - make ------------------ Installing Qhull with CMake 2.6 or later See CMakeLists.txt for examples and further build instructions To build Qhull, static libraries, shared library, and C++ interface - Download and extract Qhull (either GitHub, .tgz file, or .zip file) - cd build - cmake --help # List build generators - cmake -G "" .. # e.g., for MINGW-w64 -- cmake -G "MSYS Makefiles" .. - cmake .. - make - ctest - make install # If MSYS or UNIX, default CMAKE_INSTALL_PREFIX is '/usr/local' # otherwise if WINDOWS, installs to ../bin, ../include, and ../lib - make uninstall # Delete the files in install_manifest.txt The ".." is important. It refers to the parent directory (i.e., qhull/) CMake installs lib/pkgconfig/qhull*.pc for use with pkg-config If CMAKE_INSTALL_PREFIX is C:/Program Files/qhull, you may need to give 'Users' "full control" to qhull's sub-directories: bin, doc, include, lib, and man (folder > Properties > Security > Edit > Users). On Windows, CMake's 64-bit generators have a "Win64" tag. Qhull's data structures are substantial larger as 64-bit code than as 32-bit code. This may slow down Qhull. If cmake fails with "No CMAKE_C_COMPILER could be found" - cmake was not able to find the build environment specified by -G "..." If cmake's gcc smoketest fails after a Windows update - Reinstall MINGW-w64 and delete CMakeCache.txt. A Windows update can break gcc process creation for cc1. ------------------ Installing Qhull with Qt To build Qhull, including its C++ test program (qhulltest) - Download and extract Qhull (either GitHub, .tgz file, or .zip file) - Load src/qhull-all.pro into QtCreator - Configure the project to use a Shadow build at the same level as 'src', 'bin', and 'lib' If, instead, the shadow build is a subdirectory of 'build', Qt Creator will install Qhull in 'build/bin' and 'build/lib' - Build - Build qhulltest with a C++11 or later compiler - qhulltest depends on shared libraries QtCore.a and QtTest.a. They may need to be copied into the bin directory. On Windows, copy Qt5Core.dll and Qt5Test.dll, e.g., /qt/5.11.2/msvc2017_64/bin - If qhulltest fails with exit status 127 and no error message, check for missing Q5Core.dll and Qt5Test.dll ------------------ Working with Qhull's C++ interface See html/qh-code.htm#cpp for calling Qhull from C++ programs Class and method documentation is limited See html/qh-code.htm#reentrant for converting from Qhull-2012 Examples of using the C++ interface user_eg3_r.cpp qhulltest/*_test.cpp Qhull's C++ interface is likely to change. Stay current with GitHub. To clone Qhull's next branch from http://github.com/qhull/qhull/wiki git init git clone git@github.com:qhull/qhull.git cd qhull git checkout next ... git pull origin next Compile qhullcpp and libqhullstatic_r with the same compiler. Both libraries use the C routines setjmp() and longjmp() for error handling. They must be compiled with the same compiler. Qhull provides pkg-config support with build/qhull.pc.in and lib/pkgconfig/qhull*.pc With back-ticks, you can compile your C++ program with the Qhull libraries: g++ `pkg-config --cflags --libs qhullcpp qhullstatic_r` -o my_app my_app.cpp or g++ `pkg-config --cflags --libs qhullcpp qhull_r` -o my_app my_app.cpp qhullcpp must be linked before qhull_r, otherwise the linker reports an error -- "QhullUser ... multiple definition of `qh_fprintf'" ------------------ Calling Qhull from C programs See html/qh-code.htm#library for calling Qhull from C programs Qhull provides pkg-config support with build/qhull.pc.in and lib/pkgconfig/qhull*.pc With back-ticks, you can compile your C program with the Qhull library gcc `pkg-config --cflags --libs qhull_r` -o my_app my_app.c See html/qh-code.htm#reentrant for converting from Qhull-2012 Warning: You will need to understand Qhull's data structures and read the code. Most users will find it easier to call Qhull as an external command. The reentrant 'C' code (src/libqhull_r), passes a pointer to qhT to most Qhull routines. This allows multiple instances of Qhull to run at the same time. It simplifies the C++ interface. The non-reentrant 'C' code (src/libqhull) looks unusual. It refers to Qhull's global data structure, qhT, through a 'qh' macro (e.g., 'qh ferr'). This allows the same code to use static memory or heap memory. If qh_QHpointer is defined, qh_qh is a pointer to an allocated qhT; otherwise qh_qh is a global static data structure of type qhT. ------------------ Compiling Qhull with Microsoft Visual C++ To compile 32-bit Qhull with Microsoft Visual C++ 2010 and later - Download and extract Qhull (either GitHub, .tgz file, or .zip file) - Load solution build/qhull-32.sln - Right-click 'Retarget solution' from toolset v110 to your Platform Toolset File > Save All - Build target 'Win32' - Project qhulltest requires Qt for DevStudio (http://www.qt.io) Set the QTDIR environment variable to your Qt directory (e.g., c:/qt/5.2.0/5.2.0/msvc2012) If QTDIR is incorrect, precompile will fail with 'Can not locate the file specified' - Copy Qt shared libraries, QtCore.dll and QtTest.dll, into the bin directory To compile 64-bit Qhull with Microsoft Visual C++ 2010 and later - 64-bit Qhull has larger data structures due to 64-bit pointers. This may slow down Qhull. - Download and extract Qhull (either GitHub, .tgz file, or .zip file) - Load solution build/qhull-64.sln - Right-click 'Retarget solution' from toolset v110 to your Platform Toolset File > Save All - Build target 'x64' - If build as 32-bit fails, use solution build/qhull-32.sln - Project qhulltest requires Qt for DevStudio (http://www.qt.io) Set the QTDIR environment variable to your Qt directory (e.g., c:/qt/5.2.0/5.2.0/msvc2012_64) If QTDIR is incorrect, precompile will fail with 'Can not locate the file specified' If error -- MSB8020: The build tools for Visual Studio 2012 (Platform Toolset = 'v110') cannot be found. - 'Project > Retarget solution' for both qhull-32.sln and qhull-64.sln - 'File > Open' your preferred solution (qhull-32.sln or qhull-64.sln) - 'Save All' both projects - DevStudio may need a restart To compile Qhull with Microsoft Visual C++ 2005 (vcproj files) - Download and extract Qhull (either GitHub, .tgz file, or .zip file) - Load solution build/qhull.sln - Build target 'win32' (not 'x64') - Project qhulltest requires Qt for DevStudio (http://www.qt.io) Set the QTDIR environment variable to your Qt directory (e.g., c:/qt/4.7.4) If QTDIR is incorrect, precompile will fail with 'Can not locate the file specified' ------------------ Compiling Qhull with Qt Creator Qt (http://www.qt.io) is a C++ framework for Windows, Linux, and Macintosh Qhull uses QTestLib to test qhull's C++ interface (see src/qhulltest/) To compile Qhull with Qt Creator - Download and extract Qhull (either GitHub, .tgz file, or .zip file) - Download the Qt SDK - Start Qt Creator - Load src/qhull-all.pro - Configure the project to use a Shadow build at the same level as 'src', 'bin', and 'lib' If, instead, the shadow build is a subdirectory of 'build', Qt Creator will install Qhull in 'build/bin' and 'build/lib' - Build - Build qhulltest with a C++11 or later compiler - qhulltest depends on shared libraries QtCore.a and QtTest.a. They may need to be copied into the bin directory. On Windows, copy Qt5Core.dll and Qt5Test.dll, e.g., /qt/5.11.2/msvc2017_64/bin - If qhulltest fails with exit status 127 and no error message, check for missing Q5Core.dll and Qt5Test.dll ------------------ Compiling Qhull with mingw/gcc on Windows To compile Qhull with MINGW - Download and extract Qhull (either GitHub, .tgz file, or .zip file) - Install GitForWindows (https://gitforwindows.org/) or MSYS2 (http://www.msys2.org/) Install in C:\Git\... # Not 'Program Files\...' otherwise './configure && make' will not work - Install MINGW-w64 with gcc (https://mingw-w64.org/) 1) Goto sourceforge -- https://sourceforge.net/projects/mingw-w64/files/ 2) in folder -- mingw-w64 3) download installer -- MinGW-W64-install.exe Run the installer 1) Select i686/posix/dwarf 2) Install in 'C:\mingw-w64' # Not 'Program Files\...' Rename /c/mingw-w64/mingw32/bin/mingw32-make.exe to make.exe Add the 'C:\mingw-w64\mingw32\bin' directory to your $PATH environment variable Execute 'which make' to check that 'make' is mingw-w64's make - Compile Qhull from the home directory make help make Notes - Mingw is included with Qt SDK in qt/Tools/mingw53_32 - If you use Windows XP Install Road Bash (http://www.qhull.org/bash) or MSYS (http://www.mingw.org/wiki/msys) Install MINGW (http://mingw.org/) ------------------ Compiling Qhull with cygwin on Windows To compile Qhull with cygwin - Download and extract Qhull (either GitHub, .tgz file, or .zip file) - Install cygwin (http://www.cygwin.com) - Include packages for gcc, make, ar, and ln - make ------------------ Compiling from Makfile without gcc The file, qhull-src.tgz, contains documentation and source files for qhull and rbox. To unpack the tgz file - tar zxf qhull-src.tgz - cd qhull - Use qhull/Makefile Simpler Makefiles are qhull/src/libqhull/Makefile and qhull/src/libqhull_r/Makefile Compiling qhull and rbox with Makefile - in Makefile, check the CC, CCOPTS1, PRINTMAN, and PRINTC defines - the defaults are gcc and enscript - CCOPTS1 should include the ANSI flag. It defines __STDC__ - in user.h, check the definitions of qh_SECticks and qh_CPUclock. - use '#define qh_CLOCKtype 2' for timing runs longer than 1 hour - type: make - this builds: qhull qconvex qdelaunay qhalf qvoronoi rbox libqhull.a libqhull_r.a - type: make doc - this prints the man page - See also qhull/html/index.htm - if your compiler reports many errors, it is probably not a ANSI C compiler - you will need to set the -ansi switch or find another compiler - if your compiler warns about missing prototypes for fprintf() etc. - this is ok, your compiler should have these in stdio.h - if your compiler warns about missing prototypes for memset() etc. - include memory.h in qhull_a.h - if your compiler reports "global.c: storage size of 'qh_qh' isn't known" - delete the initializer "={0}" in global.c, stat.c and mem.c - if your compiler warns about "stat.c: improper initializer" - this is ok, the initializer is not used - if you have trouble building libqhull.a with 'ar' - try 'make -f Makefile.txt qhullx' - if the code compiles, the qhull test case will automatically execute - if an error occurs, there's an incompatibility between machines - If you can, try a different compiler - You can turn off the Qhull memory manager with qh_NOmem in mem.h - You can turn off compiler optimization (-O2 in Makefile) - If you find the source of the problem, please let us know - to install the programs and their man pages: - define MANDIR and BINDIR - type 'make install' - if you have Geomview (www.geomview.org) - try 'rbox 100 | qconvex G >a' and load 'a' into Geomview - run 'q_eg' for Geomview examples of Qhull output (see qh-eg.htm) ------------------ Compiling on other machines and compilers Qhull may compile with Borland C++ 5.0 bcc32. A Makefile is included. Execute 'cd src/libqhull; make -f Mborland'. If you use the Borland IDE, set the ANSI option in Options:Project:Compiler:Source:Language-compliance. Qhull may compile with Borland C++ 4.02 for Win32 and DOS Power Pack. Use 'cd src/libqhull; 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] If you have troubles with the memory manager, you can turn it off by defining qh_NOmem in mem.h. ------------------ Distributed files README.txt // Instructions for installing Qhull REGISTER.txt // Qhull registration COPYING.txt // Copyright notice QHULL-GO.lnk // Windows icon for eg/qhull-go.bat Announce.txt // Announcement CMakeLists.txt // CMake build file (2.6 or later) File_id.diz // Package descriptor index.htm // Home page Makefile // Makefile for gcc and other compilers qhull*.md5sum // md5sum for all files bin/* // Qhull executables and dll (.zip only) build/CMakeModules/CheckLFS.cmake // enables Large File Support in CMake build/config.cmake.in // extract target variables build/qhull.pc.in // pkg-config template for creating lib/pkgconfig/qhull*.pc build/qhull-32.sln // 32-bit DevStudio solution and project files (2010 and later) build/*-32.vcxproj build/qhull-64.sln // 64-bit DevStudio solution and project files (2010 and later) build/*-64.vcxproj build/qhull.sln // DevStudio solution and project files (2005 and 2009) build/*.vcproj build/qhulltest/ // DevStudio project files for qhulltest (C++ and Qt) build/README-build.txt // Contents of build/ eg/* // Test scripts and geomview files from q_eg html/index.htm // Manual html/qh-faq.htm // Frequently asked questions html/qh-get.htm // Download page html/qhull-cpp.xml // C++ style notes as a Road FAQ (www.qhull.org/road) src/Changes.txt // Change history for Qhull and rbox src/qhull-all.pro // Qt project eg/ q_benchmark // shell script for precision and performance benchmark q_benchmark-ok.txt // reviewed output from q_benchmark q_eg // shell script for Geomview examples (eg.01.cube) q_egtest // shell script for Geomview test examples q_test // shell script to test qhull q_test.bat // Windows batch test for QHULL-GO.bat // cd bin; ..\eg\q_test.bat >q_test.x 2>&1 q_test-ok.txt // reviewed output from q_test qhulltest-ok.txt // reviewed output from qhulltest (Qt only) make-qhull_qh.sh // shell script to create non-reentrant qhull_qh from reentrant Qhull make-vcproj.sh // shell script to create vcproj and vcxprog files qhull-zip.sh // shell script to create distribution files qtest.sh // shell script for testing and logging qhull rbox consists of (bin, html): rbox.exe // Win32 executable (.zip only) rbox.htm // html manual rbox.man // Unix man page rbox.txt qhull consists of (bin, html): qconvex.exe // Win32 executables and dlls (.zip download only) qhull.exe // Built with the reentrant library (about 2% slower) qdelaunay.exe qhalf.exe qvoronoi.exe qhull_r.dll qhull-go.bat // command window qconvex.htm // html manual qdelaun.htm qdelau_f.htm qhalf.htm qvoronoi.htm qvoron_f.htm qh-eg.htm qh-code.htm qh-impre.htm index.htm qh-opt*.htm qh-quick.htm qh--*.gif // images for manual normal_voronoi_knauss_oesterle.jpg qh_findbestfacet-drielsma.pdf qhull.man // Unix man page qhull.txt bin/ msvcr80.dll // Visual C++ redistributable file (.zip download only) src/ qhull/unix.c // Qhull and rbox applications using non-reentrant libqhullstatic.a rbox/rbox.c qconvex/qconvex.c qhalf/qhalf.c qdelaunay/qdelaunay.c qvoronoi/qvoronoi.c qhull/unix_r.c // Qhull and rbox applications using reentrant libqhullstatic_r.a rbox/rbox_r.c qconvex/qconvex_r.c // Qhull applications built with reentrant libqhull_r/Makefile qhalf/qhalf_r.c qdelaunay/qdelaun_r.c qvoronoi/qvoronoi_r.c user_eg/user_eg_r.c // example of using qhull_r.dll from a user program user_eg2/user_eg2_r.c // example of using libqhullstatic_r.a from a user program user_eg3/user_eg3_r.cpp // example of Qhull's C++ interface libqhullcpp with libqhullstatic_r.a qhulltest/qhulltest.cpp // Test of Qhull's C++ interface using Qt's QTestLib qhull-*.pri // Include files for Qt projects testqset_r/testqset_r.c // Test of reentrant qset_r.c and mem_r.c testqset/testqset.c // Test of non-rentrant qset.c and mem.c src/libqhull libqhull.pro // Qt project for non-rentrant, shared library (qhull.dll) index.htm // design documentation for libqhull qh-*.htm qhull-exports.def // Export Definition files for Visual C++ qhull-nomerge-exports.def qhull_p-exports.def qhull_p-nomerge-exports.def Makefile // Simple gcc Makefile for qhull and libqhullstatic.a Mborland // Makefile for Borland C++ 5.0 libqhull.h // header file for qhull user.h // header file of user definable constants libqhull.c // Quickhull algorithm with partitioning user.c // user re-definable functions usermem.c userprintf.c userprintf_rbox.c qhull_a.h // include files for libqhull/*.c geom.c // geometric routines geom2.c geom.h global.c // global variables io.c // input-output routines io.h mem.c // memory routines, this is stand-alone code mem.h merge.c // merging of non-convex facets merge.h poly.c // polyhedron routines poly2.c poly.h qset.c // set routines, this only depends on mem.c qset.h random.c // utilities w/ Park & Miller's random number generator random.h rboxlib.c // point set generator for rbox stat.c // statistics stat.h src/libqhull_r libqhull_r.pro // Qt project for rentrant, shared library (qhull_r.dll) index.htm // design documentation for libqhull_r qh-*_r.htm qhull_r-exports.def // Export Definition files for Visual C++ qhull_r-nomerge-exports.def Makefile // Simple gcc Makefile for qhull and libqhullstatic.a libqhull_r.h // header file for qhull user_r.h // header file of user definable constants libqhull_r.c // Quickhull algorithm wi_r.hpartitioning user_r.c // user re-definable functions usermem.c userprintf.c userprintf_rbox.c qhull_ra.h // include files for libqhull/*_r.c geom_r.c // geometric routines geom2.c geom_r.h global_r.c // global variables io_r.c // input-output routines io_r.h mem_r.c // memory routines, this is stand-alone code mem.h merge_r.c // merging of non-convex facets merge.h poly_r.c // polyhedron routines poly2.c poly_r.h qset_r.c // set routines, this only depends on mem_r.c qset.h random_r.c // utilities w/ Park & Miller's random number generator random.h rboxlib_r.c // point set generator for rbox stat_r.c // statistics stat.h src/libqhullcpp/ libqhullcpp.pro // Qt project for renentrant, static C++ library Qhull.cpp // Calls libqhull_r.c from C++ Qhull.h qt-qhull.cpp // Supporting methods for Qt Coordinates.cpp // input classes Coordinates.h PointCoordinates.cpp PointCoordinates.h RboxPoints.cpp // call rboxlib.c from C++ RboxPoints.h QhullFacet.cpp // data structure classes QhullFacet.h QhullHyperplane.cpp QhullHyperplane.h QhullPoint.cpp QhullPoint.h QhullQh.cpp QhullRidge.cpp QhullRidge.h QhullVertex.cpp QhullVertex.h QhullFacetList.cpp // collection classes QhullFacetList.h QhullFacetSet.cpp QhullFacetSet.h QhullIterator.h QhullLinkedList.h QhullPoints.cpp QhullPoints.h QhullPointSet.cpp QhullPointSet.h QhullSet.cpp QhullSet.h QhullSets.h QhullVertexSet.cpp QhullVertexSet.h functionObjects.h // supporting classes QhullError.cpp QhullError.h QhullQh.cpp QhullQh.h QhullStat.cpp QhullStat.h QhullUser.cpp QhullUser.h RoadError.cpp // Supporting base classes RoadError.h RoadLogEvent.cpp RoadLogEvent.h usermem_r-cpp.cpp // Optional override for qh_exit() to throw an error src/libqhullstatic/ libqhullstatic.pro // Qt project for non-reentrant, static library src/libqhullstatic_r/ libqhullstatic_r.pro // Qt project for reentrant, static library src/qhulltest/ qhulltest.pro // Qt project for test of C++ interface Coordinates_test.cpp // Test of each class PointCoordinates_test.cpp Qhull_test.cpp QhullFacet_test.cpp QhullFacetList_test.cpp QhullFacetSet_test.cpp QhullHyperplane_test.cpp QhullLinkedList_test.cpp QhullPoint_test.cpp QhullPoints_test.cpp QhullPointSet_test.cpp QhullRidge_test.cpp QhullSet_test.cpp QhullVertex_test.cpp QhullVertexSet_test.cpp RboxPoints_test.cpp RoadTest.cpp // Run multiple test files with QTestLib RoadTest.h ------------------ Authors C. Bradford Barber Hannu Huhdanpaa (Version 1.0) bradb@shore.net hannu@qhull.org Qhull 1.0 and 2.0 were developed under NSF grants NSF/DMS-8920161 and NSF-CCR-91-15793 750-7504 at the Geometry Center and Harvard University. If you find Qhull useful, please let us know. qhull-2020.2/REGISTER.txt0000644060175106010010000000167611320141665013164 0ustar bbarberDear Qhull User We would like to find out how you are using our software. Think of Qhull 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 Qhull, 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) How Qhull has helped you, for example, by increasing your productivity or allowing you to do things you could not do before. If Qhull had a direct bearing on your work, please tell us about this. We encourage you to cite Qhull in your publications. To cite Qhull, please use Barber, C.B., Dobkin, D.P., and Huhdanpaa, H.T., "The Quickhull algorithm for convex hulls," ACM Trans. on Mathematical Software, 22(4):469-483, Dec 1996, http://www.qhull.org. Please send e-mail to bradb@shore.net Thank you! qhull-2020.2/src/0000755060175106010010000000000013724321425011760 5ustar bbarberqhull-2020.2/src/Changes.txt0000644060175106010010000051465713724320535014114 0ustar bbarber$Id: //main/2019/qhull/src/Changes.txt#77 $$Date: 2020/09/03 $ .............This file lists all changes to qhull and rbox..................... ==== == Contents ==== To do Qhull 2018-2020 Qhull 2015 Qhull 2012.1 Qhull 2011.1 Qhull 2010.1 and 2009.1 Qhull 2003.1 Qhull 2002.1 Qhull 3.1 (2001) Qhull 2.6 (1999) Qhull 2.5 (1998) Qhull 2.4 (1997) Qhull 2.3 (1996) Qhull 2.2 (1995-1996) Qhull 2.1 (1995) Qhull 2.0 (1994-1995) ==== == To do ==== - For a list of enhancement requests, see http://www.qhull.org/html/qh-code.htm#enhance - The C++ interface needs documentation. Give C++ a try and make it better. http://github.com/qhull/qhull/wiki - Expand the C++ interface for Voronoi diagrams Design for arbitrary dimension with non-simplicial facets Start with 'user_eg3 eg-voronoi eg-fifo' Compute the convex hull of each Voronoi region Compare its facet hyperplanes with eg-fifo Create a data structure for the Voronoi diagram Compare your result to CGAL's 2-d Voronoi diagram Two CGAL halfedges is equivalent to a Qhull ridge https://doc.cgal.org/4.7/Voronoi_diagram_2/group__PkgVoronoiDiagramAdaptor2.html ================== == Qhull 2018-2020 ================== ------------ Qhull 2020.2 2020/08/31 (8.0.2) CMake builds - CMakeLists.txt: Fixed /usr/local/lib/pkgconfig for debug builds - CMakeLists.txt: Remove qhull_SHARED and qhull_SHAREDP from 'make all' Remove qhull_SHARED and qhull_SHAREDP from qhull_TARGETS_SHARED Use reentrant Qhull (libqhull_r) for user code - CMakeLists.txt: If "MSYS Makefiles", change the default CMAKE_INSTALL_PREFIX to "/usr/local" Remove WIN32 conditionals from MAN_INSTALL_DIR and DOC_INSTALL_DIR - CMakeLists.txt: Add 'uninstall' to delete the files listed in install_manifest.txt - CMakeLists.txt: If LINK_APPS_SHARED, link qhull applications to libqhull_r.so [S. Bruens #69] If BUILD_STATIC_LIBS=OFF or BUILD_SHARED_LIBS=OFF, exclude those libraries [S. Bruens #69] libqhullcpp and user_eg3 are built only if BUILD_STATIC_LIBS is true - CMakeModules/CheckLFS.cmake: Moved CMakeModules to the build/ directory - CMakeLists.txt: Replace rbox_SOURCES(etc.) with a source file, either reentrant or non-reentrant - CMakeLists.txt: Add deprecated libqhull and qhull_p to "# Additional build targets" If not MSVC, add qh_QHpointer to user_egp_DEFINES and qhullp_DEFINES (otherwise qh_lib_check fails) Other builds - build/README-build.txt: Add description of build/ directory - build/qhull*.sln: Remove qhull_p and qhull_p.dll, retain the corresponding DevStudio project files Remove libqhull and qhull.dll, retain the corresponding DevStudio project files - Makefile: Add libqhull_r/libqhullstatic_r.a to 'cleanall' - Makefile: Add note about installing debug libraries (e.g., libqhull_rd) - Makefile,libqhull*/Makefile: Copy README.txt,...,Changes.txt and html/* to ABS_DOCDIR - Makefile,libqhull*/Makefile: Add target 'uninstall' to delete installed Qhull files - libqhull/qhull-exports.def,qhull-nomerge-exports.def: Add qh_nextfacet2d Documentation - html/qh-code.htm: Add request for Doxygen documentation of the C++ interface - html/index.htm,etc: "Contents" instead of "Table of Contents" Testing - eg/make-qhull_qh.sh: Redo help prompt - eg/make-qhull_qh.sh: Create src/qhull_qh/_QH_CONVERTED_FILES as a safety check - eg/make-qhull_qh.sh: Require destination directory and _QH_CONVERTED_FILES for 'sed-only' ------------ Qhull Github C++ interface - libqhullcpp/qt-qhull.cpp: In toQList(), use count() to avoid a type error - libqhullcpp/qt-qhull.cpp: In toQList(), use nullptr instead of NULL - libqhullcpp/QhullSet.h: Declare 'QList toQList() const' to avoid a prototype error Builds - Qhull build systems: Add wiki page on build systems to GitHub - CMakeLists.txt: Use same target name for Debug and non-Debug builds [Spacelm #76] - CMakeLists.txt: Remove functional documentation from /usr/local/include/libqhull* Most of the links are broken. - CMakeLists.txt: Move Qhull html documentation to /usr/local/share/doc/qhull/html/ Otherwise index.htm is overwritten and README links are broken - CMakeLists.txt: Add /usr/local/share/doc/qhull/src/Changes.txt - Makefile, make install: Remove functional documentation from /usr/local/include/libqhull and /usr/local/include/libqhullinclude/libqhull_r. Most of the links are broken. - Makefile, src/libqhull/Makefile: Add DEPRECATED.txt to /usr/local/include/libqhull - Makefile, src/libqhull*/Makefile: Add 'make install' to the welcome prompt Documentation - index.htm: Balance the top-page 'URL:' and 'To:' links - index.htm: Send the top-page 'Functions' link to www.qhull.org (better 'src' links) - index.htm: Make the bottom-page 'URL:' and 'To:' links the same as the top-page links - index.htm: "please use rentrant Qhull (libqhull_r or libqhullstatic_r)" - html/index.htm: Add rbox.txt to Contents and rename "Table of Contents" - html/index.htm,qh-code.htm,qh-eg.htm,qh-impre.htm: Remove 'please wait while loading' - README.txt/Installing Qhull with Qt: The shadow build directory should be at the same level as 'src' - README.txt/Compiling Qhull with Qt Creator: Copy steps from 'Installing Qhull with Qt' ------------ Qhull 8.0.1 (2020.2 2020/07/24) C++ interface - Removed Java-style iterators for Coordinates and PointCoordinates. std::vector has an expensive copy constructor and copy assignment, and a pointer to std::vector is vulnerable to mysterious overwrites (e.g., deleting a returned value and reusing its memory). Qt's 'foreach' should not be used for Coordinates and PointCoordinates. It copies std::vector - QHULL_DECLARE_SEQUENTIAL_ITERATOR: allow temporary results The Jave-style iterator copies the container. Same as Qt's Q_DECLARE_SEQUENTIAL_ITERATOR - QhullHyperplaneIterator,QhullPointIterator,QhullPointsIterator: allow temporary results These Java-style iterators copy the container instead of pointing to the container - QhullLinkedListIterator,QhullFacetListIterator,QhullVertexListIterator: allow temporary results These Java-style iterators copy the container instead of pointing to the container - QhullSetIterator,QhullFacetSetIterator,QhullPointSetIterator,QhullVertexSetIterator: add documentation about temporary results These Java-style iterators have always copied the container - QhullUser.h, user_eg3_r.cpp: Removed C++11 dependencies [G. Romualdi, S. Grein #65, #66,#67] QhullUser.cpp: Use intptr_t to avoid C++11 dependencies [S. Grein, Spacelm #68] - QhullVertex.cpp: moved the copy constructor to the code file. It was inline. Testing and example programs - user_eg3_r.cpp: Renamed 'inputSites' to 'voronoiRegions' in qvoronoi_o/qvoronoi_pfn [M. Konecny #72] - user_eg3_r.cpp: Replaced C++11's range-based for loops with Qhull's Java-style iterators - qh-code.html: Updated qhullcpp code example [M. Konecny #71] - QhullFacet_test.cpp: fixed hyperplane epsilon test in t_getSet. The epsilon due to rotation is unknown. - Qhull*List_test.cpp,Qhull*Set_test.cpp,QhullRidge_test,QhullVertex_test: test Qt's 'foreach' in t_foreach - Qhull*List_test.cpp,Qhull*Set_test.cpp,QhullRidge_test,QhullVertex_test: test C++11 range for in t_foreach - Qhull*List_test.cpp,Qhull*Set_test.cpp: test Java-style iterator in t_java_iterator - Coordinates_test.cpp,PointCoordinates_test.cpp,QhullHyperplane_test.cpp,QhullPoint_test.cpp,QhullPoints_test.cpp,RboxPoints_test.cpp test C++11 range for, Qt's 'foreach', and Java-style iterators (if available) Builds - README.txt: Fixed "cmake -G" for "Installing Qhull with CMake" - README.txt: Added a note on 'make install' to "Installing Qhull on Unix" - README.txt: Added 'make test' to "Installing Qhull on Unix" - README.txt: Added 'ctest' to "Installing Qhull with CMake" - README.txt: Added pkg-config notes to "Installing Qhull with CMake" - README.txt: Added usage notes for Windows to "Installing Qhull with CMake" - README.txt: Added instructions for downloading MinGW-W64-install.exe - build/qhull_p.pc.in,qhull_r.pc.in: Delete obsolete files [T. Roehling #63] - build/qhull.pc.in: move qhull.pc.in into the build/ directory [T. Roehling #63] Documentation - qh-code.htm, qhull-news.html: Add Toronto and McCarthy, "Practically accurate floating-point math". ------------ Qhull 2020.1 2020/05/29 (8.0.0) Bugs fixed - QhullLinkedList::const_iterator: Fixed operator->() for T*. It returned &i [J. Mirabel 5/1/2020 #61] API changes - RoadError.cpp: stringGlobalLog returns std::string instead of const char* [M. Gehre #46] - io_r.c/qh_order_vertexneighbors: order facet neighbors of a vertex by 2-d (orientation), 3-d (adjacency), n-d (f.visitid,id) [I. Gardner] - poly2_r.c/qh_nextfacet2d: Return next facet and vertex in qh_ORIENTclock order [N. Katzakis #54] C++ interface - Qhull.cpp: Add isDelaunay(). True if computing Delaunay or Voronoi regions Add prepareVoronoi() for Voronoi output. See user_eg3_r.cpp for examples ~Qhull: Change 'Qhull output at end' to 'Qhull messages at ~Qhull()' - QhullFacet.cpp: Add visitId() for f.visitid. Needed for Voronoi output Add nextFacet2d(): Iterate 2-d facets and vertices in counter-clockwise order [N. Katzakis #54] Add setFacetT() - QhullRidge.cpp: Add setRidgeT() and qh() - QhullUser.cpp: Add a user-modifiable interface to Qhull using a custom qh_fprintf Enhanced qh_fprintf with qhull-2019.1 updates to userprintf_r Option 'Ta' prefixes output with message code, [QHnnnn] Option 'Tf' flushes the output after each message, for tracing segfaults Errors and high-level trace messages prefixed with QHnnnn Debugging traps for qh.tracefacet, qh.traceridge, qh.tracevertex - QhullVertex.cpp: Add setVertexT() - QhullQh.cpp: moved qh_fprintf to QhullUser - RoadLogEvent::toString: do not prepend QHnnnn if format_string starts with QHn or [QHn - RboxPoints::appendPoints: use current dimension instead of throwing an error - user_eg3 rbox: set dimension for multiple options (e.g., user_eg3 rbox D4 5 qhull) - user_eg3 eg-convex: a 3-d convex hull using the C++ interface to Qhull [I. Voutchkov] - user_eg3 eg-delaunay: a 2-d Delaunay triangulation using the C++ interface to Qhull - user_eg3 eg-voronoi: a 2-d Voronoi diagram using the C++ interface to Qhull - user_eg3 eg-fifo: hyperplanes separating Voronoi regions via QhullUser and qh_fprintf Documentation - index.htm: Add Teillaud's http://www.computational-geometry.org/ - index.htm: Add When to use Qhull and Performance of Qhull to the Qhull Manual - html/qconvex.htm: Add orientation for options 'i', 'Fx', and 'o' qconvex .: keep the option prompt to five columns - html/qdelaun.htm: qh_findbestfacet may return an adjacent facet for a point - html/qhalf.htm,qh-optf.htm,qh-opto.htm: Added notes for options to halfspaces, e.g., 'Fp' and -10.101 [E. Huang #53] - html/qhalf.htm,qhalf.c,qhalf_r.c,qh-optf.htm: Fix documentation for 'qhalf FN'. The output includes all halfspaces. - html/qvoronoi.htm,qvoron_f.htm: Fix link for control option, 'TI file' - html/qvoronoi.htm,qvoron_f.htm, qh-optf: the hyperplanes for 'Fi' and 'Fo' include the first vertex Option 'Fo' uses the midpoint in place of the vertex at infinity. - html/qh-optf.htm: Voronoi options 'Fi' and 'Fo' orient the hyperplane so that the site is below the hyperplane - html/qh-optf.htm,qh-optt.htm: Voronoi option 'Fo' does not check the hyperplane with 'Tv' The hyperplane check for 'Fi Tv' uses the midpoint, which 'Fo' already used in place of infinity - README.txt/Windows install: install Git for Windows in C:\Git\ instead of Program Files README.txt/Unix install: add options for 32-bit builds w/o -fpic README.txt,Makefile: link libqhullcpp before libqhull_r - COPYING.txt: Add a note to COPYING.txt about C.B. Barber [M. Pryczek] - libqhull/DEPRECATED.txt: Add link to qh-code.htm#convert - Qhull::vertexList: ordered by qh.vertex_list, not by adjacency [N. Katzakis #54] - QhullPoints.cpp/extraCoordinatesCount: must be less than point_dimension (-Wconversion) - QhullPoints.cpp/indexOf: extra must be less than point_dimension (-Wconversion) - io_r.c/qh_detvnorm: add note that qh_sethyperplane_gauss returns nearzero for axis-parallel hyperplanes - user_r.h/qh_CPUclock: may be converted to approximate double (-Wconversion) - Update copyright to 2020 Build - Increase SOVERSION to 8.0 due to ABI breakage in 2019.1 [T. Roehling #58] Change SOVERSION to major.minor due to Qhull's global data structure qhT [T. Roehling #58] Add symbolic link from SONAME_EXT to libqhull_r [T. Roehling #58] Add SO and SONAME_EXT to 'make help' - qhull.pc.in: Added for pkg-config support [T. Roehling #60] - CMakeLists.txt: Add pkg-config support and change *_INSTALL_DIR to relative paths [T. Roehling #60] Change CMAKE_SOURCE_DIR to CMAKE_CURRENT_SOURCE_DIR to allow qhull as a subdirectory [Morwenn #53, A. De #59, A. Maloney, futex] - Makefile: Add pkg-support [T. Roehling #63] Renamed $DESTDIR as $PREFIX to conform with GNU Makefile standards [T. Roehling #63] $DESTDIR is for staged installs as defined by GNU Makefile standards [T. Roehling #63] Commented out M32=-m32 despite memory savings. It caused build failures, e.g., Mac [J. Hollowed] '-fpic' is required for linking to shared libraries [T. Roehling #63] Replaced -fpic with FPIC=-fpic for gcc builds Added FPIC to CXX_OPTS1 (same as CMakeLists.txt for libqhullcpp) Use 'FPIC=' to disable -fpic (may be faster for 32-bit builds on 64-bit hosts) Extract qhull_VERSION and qhull_SOVERSION from CMakeLists.txt [T. Roehling #63] Move the -lm linker flag to the end of the linker command [T. Roehling #63] Add QhullVertexSet.h to LIBQHULLCPP_HDRS Invoke q_test via bash to avoid "eg not a valid command" - Add build/*vcxproj to Unix distribution Testing and other changes - q_test: Add list of executables via 'which' Add tests of user_eg3 with each option and use case Add "Testing done" notification Add "set +v" for echoes - qhull-zip.sh: Add early check for 32-bit release build and modified files Add link checks for options Add findf for identifying files for link checks Add prompts for web.archive and md5sum in qh-get.htm ------------ Qhull 2019.1 github 2019/10/24 Documentation - Review and fix Qhull html and option links - README.txt/mingw: Install GitForWindows in C:\Git\ - libqhull_r/index.htm: Fixed Firefox web access to '.c' and '.h' files (http://qhull.org/src/libqhull_r/) Bugs fixed - merge_r.c/qh_appendmergeset,qh_appendvertexmerge,qh_mergefacet,qh_tracemerge: fix error check of index for mergetypes Build - CMakeLists.txt: Rename Qhull to QhullExport for QhullConfig. On MacOS, "Qhull" conflicts with "qhull" [tamasmeszaros #48, C. Xu, tschoonj] - CMakeLists.txt: Add POSITION_INDEPENDENT_CODE "TRUE" to set_target_properties for libqhullcpp [J Anderson 11/20/2019 #47] ------------ Qhull 2019.1 2019/06/21 (7.3.2) bugs fixed - Fixed broken HTML links identified by Firefox Link Analyzer. Replace old links with web.archive.org (archive.is) - Moved live code out of qh_NOtrace regions - qh-faq.htm#learn: fixed the Delaunay examples (rbox generates a square, but does not generate two squares) - geom2_r.c/qh_maxmin: qh_scalelast for 'd Qbb' to qh.MAXabs_coord instead of qh.MAXwidth [J.R. Roussel, D. Sterratt] - geom2_r.c/qh_maxsimplex: estimate targetdet as prevdet*qh.MAXwidth, set mindet to 10*qh_RATIOmaxsimplex [J.R. Roussel, D. Sterratt] - global_r.c/qh_freebuild: in high-D, simplicial facets may use long memory - global_r.c/qh_initqhull_globals: set qh.DOcheckmax and qh.KEEPnearinside if qh.APPROXhull ('Wn', rbox 100 D3 W1e-1 | qhull QJ W1e-1 Tv) - libqhull_r.c/qh_addpoint: add qh.lastmerges to qh_addpoint trace - libqhull_r.c/qh_buildcone_mergepinched: called qh_partitioncoplanar with uninitialized 'dist' - libqhull_r.c/qh_build_withrestart: if qh_joggle_restart, set v.partitioned for qh.del_vertices. Avoid error in qh_delvertex from qh_freebuild - libqhull_r.c/qh_partitionall: if qh.KEEPnearinside, qh_partitionpoint for non-outside pointset - libqhull_r.c/qh_partitioncoplanar: define qh.coplanar_apex to prevent infinite loop of repartition point - merge_r.c/qh_checkzero: check opposite vertex against -2*qh.DISTround to account for qh_distround and 'Rn' - merge_r.c/qh_comparevisit: fix compare of 'unsigned int' - poly2_r.c/qh_findbestfacet: for Delaunay triangulations, may be an adjacent triangle [F. Drielsma] Updated discussion at qh-code.htm/findfacet and examples at user_eg_r.c and user_eg2_r.c - poly2_r.c/qh_findfacet_all: do not search visible facets, and if qh_NOupper, f.upperdelaunay facets [P. Virtanen, S. Dominguez, J.Arkin] - poly2_r.c/qh_initialhull: reverse orientation if clearly flipped. qh_ERRsingular if maybe flipped [S. Caron, P. Virtanen, D. Sterratt, others] - poly2_r.c/qh_initialhull: test for coplanar qh.interior_point with 'allerror' (dist >= -qh.DISTround) [S. Caron, P. Virtanen, D. Sterratt, others] - poly2_r.c/qh_initialhull: call qh_joggle_restart for qh.DELAUNAY if cospherical input sites [P. Celba] - poly2_r.c/qh_initbuild: qh_scalelast for 'd Qbb' to qh.MAXabs_coord instead of qh.MAXwidth [J.R. Roussel, D. Sterratt] - random_r.c/qh_argv_to_command_size: returned size may be < 1. If so, rbox.c/main reports an error - rboxlib_r.c/qh_rboxpoints: report error for coincident, regular points 'rbox r C1,1e-13' - stat_r.c/qh_initstatistics: missing call to qh_allstatistics for qh_newstats. qh_checkoutput ignored - userprintf.c/qh_fprintf: fixed 2019.0.1 bug if 'qh_qh' is NULL for qh_QHpointer - Qhull.cpp/outputQhull: fixed missed conditional if qh.GOODvertex == -qh.GOODpoint documentation and web site - Add notes that Qhull 64-bit code uses 50% more memory than 32-bit code. This slows down Qhull. A future version of Qhull will include memory and performance improvements for 64-bit code. - Add the Qhull identity pipeline to html/qhalf.htm - Enabled PDF download from portal.acm.org - Error exit from qhull,qconvex,etc. returns a 6xxx error code if available - Rename md5sum files back to *-tgz.md5sum and *-zip.md5sum Both Firefox and IE convert *.tgz.md5sum and *.zip.md5sum as .tgz/.zip files - html/qh-code.htm: add sections on debugging Qhull - html/qh-faq.html: reviewed startup questions for Qhull - html/qh-opto.htm: the centrum indices for option 'i' are one more than the centrum indices for option 'Ft' build and test - CMakeLists.txt: export QhullTargets for config.cmake.in and find_package [tamasmeszaros] - eg/q_benchmark: add 'uname -a' for host identification - eg/q_test.bat: update for changes to q_test removed redirects on every line (invoke with redirection) - eg/q_test: add some tests for option warnings and errors - Makefile: add dependencies for 'install', 'test', 'qtest', and 'qconvex-prompt' [V. Delecroix] - Makefile: set -m32 as default for gcc builds. Uses less memory on 64-bit hosts. disable with 'make M32=' - Remove 'unused parameter' warnings if qh_NOmerge - Tested qh_QHpointer, qh_NOmem, qh_NOmerge, qh_NOtrace, qh_KEEPstatistics 0 - Tested qh_NOmerge with qh_NOtrace and qh_KEEPstatistics 0. Simpler code, fewer errors, 35% smaller - Tested random qh_distplane and qh_setplane qh_RANDOMdist 1e-5, qh_RANDOMdist 1e-13 - user_r.h: define qh_RANDOMdist to perturb all calls to qh_distplane, qh_newfacetplane by 'Rn' other changes - Replace 'unsigned' with 'unsigned int', for consistency - Replace warning 6263 with 7079 in qconvex_r.c, etc. - Resolved C warnings for -Wsign-conversion, mostly type casts Continue to use -Wno-sign-conversion for C++ due to countT, boolT, int vs. size_t mismatches - Reviewed gcc 8.1.0 warnings. See Makefile CC_WARNINGS and CXX_WARNINGS Type cast (int)sizeof(facetT),etc. as needed - Reviewed error and warning codes for multiple instances of the same code - Reviewed file references such as libqhull_r.c vs libqhull.c - Reviewed multi-line, error message width for 80 column output - global.c/qh_initflags: Add 'qh_QHpointer' to qh_option for option list - geom2_r.c/qh_joggleinput: report QH6010, current joggle is too large, as qh_ERRinput - geom2_r.c/qh_maxsimplex: report error if qh.MAXwidth not defined, for estimating the determinates - geom2_r.c/qh_minmax: if tracing, log min and max coordinates [J.R. Roussel, D. Sterratt] - io_r.c/qh_printbegin: rewrote warning QH7053, use 'p' or 'o' for Voronoi centers - io_r.c/qh_produce_output2: fflush to maintain execution order of output - libqhull_r.c/qh_buildtracing: change qh.lastfacets, qh.lastplanes, qh.lastdist to 'int' - libqhull_r.c/qh_build_withrestart: change error QH6229, 101 attempts to joggle input, to qh_ERRinput and 51 attempts - merge_r.c/qh_renameridgevertex: report error if old vertex not found - poly_r.c/qh_update_vertexneighbors: use qh_setappend instead of qh_setunique for newly created facets (restores 2015.2 code) - poly2_r.c/qh_check_point: limit 'Tv' errors to qh_MAXcheckpoint per facet - poly2_r.c/qh_initialhull: rewrite QH6329 for cospherical input sites and add qh_printvertexlist [P. Celba] - qset_r.c/qh_setlarger_quick: optimize qh_setlarger for quick memory - rboxlib_r.c/qh_rboxpoints2: fix strncat to resolve -Wstringop-truncation warning [D. Sterratt] increased command[] to 250 and decreased seedbuf[] to 50 - user_r.h/qh_JOGGLEmaxretry: reduced from 100 iterations to 50 iterations - user_r.c/qh_new_qhull: allow "qhull" for the qhull_cmd parameter - user_eg_r.c/findDelaunay: qh_findbestfacet returns the closest Delaunay triangle or an adjacent triangle - user_eg2_r.c/findDelaunay: qh_findbestfacet returns the closest Delaunay triangle or an adjacent triangle - userprintf_r.c/qh_fprintf: set qh.last_errcode for MSG_ERROR (6000) codes - RboxPoints::qh_fprintf_rbox: print error message to stderr if cpp_object undefined ------------ Qhull 2019.0.1 2019/05/24 (7.3.1) Qhull options - Disallow unknown options and other option errors, allow option warnings with 'Qw' - New option 'Qallow-short': allow input with fewer or more points than coordinates - New option 'Qwarn-allow': allow option warnings - New option 'TAn': stop after adding n vertices - New option 'Tf': flush after qh_fprintf for debugging segfaults - New experimental option 'Q14-merge-pinched-vertices': merge pinched vertices due to dupridge Excessive merging leads to additional topological and wide facet errors - New experimental option 'Q15-check-duplicates': check for duplicate ridges with the same vertices - Option 'Q1' merges by mergetype/angle instead of mergetype/distance, coplanar merges first In 2015.2 by default, Qhull merged by mergetype/angle with lower angles first - Option 'TP-1' turns on tracing after qh_buildhull and qh_postmerge It traces qh_check_maxout, qh_prepare_output, qh_triangulate, qh_voronoi_center - Options '--help', '-?', and '--' display a short help message Qhull does not support '--' options. Git for Windows v2.21.0 does not support isatty ('winpty qhull' is OK) - Allow Qhull extra options Q12 and Q14 for qconvex/qdelaunay/qhalf/qvoronoi - Allow option 'QRn' (random rotate) for qdelaunay/qhalf/qvoronoi - Alphabetize short prompts (qhull .) - Alphabetize long prompts w/ normal options first (qhull -) - Alphabetize option help by option code - Add 'Number of merged pinched vertices' to summary ('s') - Add 'TI file' to help message for qconvex/qdelaunay/qhalf/qvoronoi - Dropped experimental option 'Q16-simplex-merge'. Centrums are required for convexity - Error if 'd', 'v', or 'Hn,n,n' are used together - Ignore missing space after 'TI' or 'TO'. Allow 'TIinputfile' and 'TOoutputfile' - Prefix option errors and warnings with 'qhull option error:' or 'qhull option warning:' - Remove hidden option 'normals' from help prompts for qdelaunay, qhalf, qvoronoi - Reword short prompts to 'Pdrop-d0:0D0', 'QbBound-0:0.5', and 'off_format' - Updated qh-quick.htm, 'qhull -', and 'qhull .' for 'T...' and 'Q...' options. Separate help prompts for 'T options' and 'Trace options' - Use '-' instead of '_' for word delimiter in option names Qhull builds, scripts, and debugging - Add qh.traceridge, qh.traceridge_id, and qh_delridge for debugging by ridge in qh_fprintf - Check for qhull with 'which qhull' instead of 'qhull', avoids hangs in git bash - Makefile/CC_WARNINGS: Add instructions for collecting and testing gcc warnings - Makefile/benchmark: Add q_benchmark, 10 runs of each - Makefile/clean: Delete linked files from src/libqhull and src/libqhull_r, as in their Makefiles - Makefile/help: Add 'make all' to 'make help' prompts - Makefile/qhullx: Add test of testqset and testqset_r - Makefile/qhullx: Create bin/ directory if missing - Makefile/test: Add user_eg3 help prompt - Makefile/testall: Add q_benchmark, 1 run of each - eg/make-vcproj.sh/qhullx: Build bin/qhullx from src/qhullx/ for comparison - eg/q_benchmark: new script for measuring Qhull precision and performance with qtest.sh - eg/q_test: update error messages for missing bin/ and bin/libqhull_r.dll - eg/q_test: tests of Tf and TAn - eg/qhull-zip.sh: add note that it requires road-script.sh from http://www.qhull.org/road/ - eg/qhull-zip.sh: check source depencencies for prompts - eg/qtest.sh: new script for testing Qhull and summarizing its trace files - libqhull_r/Makefile: install target creates $INCDIR/libqhull_r and $LIBDIR - libqhull_r.h/qh_ERRdebug: define error status for debugging exits Qhull fixed bugs - html/qh-optp.htm: options 'PDk' and 'Pdk' require option 'Pg' to return the closest facet - Makefile/qhullx: fixed qhullx compile of testqset and testqset_r - PointCoordinates.cpp/appendPoints: read 'in >> p' instead of 'in >> p >> ws' otherwise istream fails if file does not end with whitespace - geom_r.c/qh_findbesthorizon: fix test for Zfindjump (bestdist jumps by searchdist) - geom_r.c/qh_findbesthorizon: increased minsearch of coplanar facets if ischeckmax and more than 100 neighbors - geom_r.c/qh_sethyperplane_det: dropped precision statistic Znearlysingular (it's Zminnorm) - geom2_r.c/qh_detjoggle: use 'En' (roundoff) if specified by options - geom2_r.c/qh_distround: move adjustment for 'Rn' into qh_distround. 'QJn' did not account for 'Rn' - global_r.c/qh_checkflags: handle two-digit Q options in hiddenflags - global_r.c/qh_freebuild: do not delete unattached ridges, otherwise a double delete. Should not occur - global_r.c/qh_option: fix potential overflow of qh.qhull_options - global_r.c/qh_initflags: fixed incorrect indentation for option 'TO file' - global_r.c/qh_initqhull_start2: set qh.NOerrexit True - io_r.c/qh_eachvoronoi: allow fp==NULL for QhullQh::qh_fprintf to appendQhullMessage - io_r.c/qh_readpoints: error if 'd' or 'v' with 'H', otherwise memory corruption - libqhull_r.h/qh.MERGEvertices: fixed comment, 'Q3' disables this feature - libqhull_r.c/qh_buildcone_onlygood: cannot qh_delfacet inside FORALLnew_facets - libqhull_r.c/qh_partitionpoint: if qh.NARROWhull and bestdist>qh.MINoutside and isnewoutside, may need to move facet to qh.newfacet_list for qh.next_facet - libqhull_r.c/qh_printsummary: Zdistconvex is for checking convexity instead of testing convexity - libqhull_r.c/qh_findhorizon: coplanar horizon if apex >= -qh.MAXcoplanar, instead of > -qh.MAXcoplanar - mem_r.c/qh_memcheck: define null qh_memcheck if qh_NOmem - merge_r.c/qh_mergecycle_all: turn on tracing, 'TMn', for coplanar horizon merge of one facet - merge_r.c/qh_mergefacet2d: do not create ridges for neighborB. The opposite neighbor may be tested - merge_r.c/qh_test_centrum_merge: coplanar if centrum >= -qh.centrum_radius, instead of > -qh.centrum_radius - merge_r.c/qh_test_nonsimplicial_merge: coplanar if centrum >= -qh.centrum_radius, instead of > -qh.centrum_radius - merge_r.c/qh_tracemerging: fixed "qhull has merged" prompt - merge_r.c/qh_willdelete: empty f.neighbors and f.ridges, references are no longer valid, will be deleted - poly_r.c/qh_checkflipped: flipped if qh.interior_point >= -qh.DISTround, instead of > -qh.DISTround - poly2_r.c/qh_addfacetvertex: initialize vertex_i in case f.vertices is empty - poly2_r.c/qh_check_maxout: need to include qh.DISTround when checking f.maxoutside with qh.maxoutside - poly2_r.c/qh_checkconvex: fix documentation for qh_DATAfault. It is restricted to qh_initialhull with qh.ZEROcentrum - poly2_r.c/qh_checkconvex: coplanar if >= -qh.DISTround, instead of > -qh.DISTround - poly2_r.c/qh_checkconvex: check simplicial ridges if !qh.MERGING && qh.ZEROcentrum (unlikely or not-possible) - poly2_r.c/qh_findgood: restrict qh.GOODvertex ('QVn') to good facets - poly2_r.c/qh_findgood_all: unless 'Pg', ignore qh.GOODclosest for nearest facet to thresholds. 'PdD' reports 0 good facets - poly2_r.c/qh_replacefacetvertex: initialize vertex_n in case f.vertices is empty - qconvex.c,qdelaunay.c,etc.: remove automatic 'Qx' for 5-d and higher. Set by default in qh_initqhull_globals - qvoronoi_r.c/qh_prompt: remove disabled option 'TRn' from help prompt - random_r.c/qh_argv_to_command: fixed missing braces, same behavior as before - rbox_r.c: return 0 exit status on prompt - rboxlib.c/qh_rboxpoints: use qh_fprintf_stderr instead of qh_fprintf_rbox. Avoid qh_errexit_rbox - rboxlib.c/qh_rboxpoints2: clear rbox_inuse on exit, as in error exit - rboxlib_r.c/qh_rboxpoints2: incorrect string arg to 'rbox error: unknown flag' - rboxlib_r.c/qh_rboxpoints2: remove superfluous qh_free(*simplex) - stat_r.c/qh_initstatistics: due to NOerrors cannot use qh_fprintf, use qh_fprintf_stderr instead - stat_r.c/qh_stddev: return sqrt of absolute value - testqset_r.c: if qh_NOmem, do not call qh_memfreeshort - user_eg_r.c,user_eg2_r.c: if qh_NOmem, call qh_freeqhull(qh, qh_ALL) instead of qh_memfreeshort - user_eg3_r.cpp: return 0 exit status on prompt Qhull fixed bugs introduced by 2018.0 - libqhull_r.c/qh_addpoint: clear qh.retry_addpoint on success - libqhull_r.c/qh_buildcone_mergepinched: cannot qh_delfacet inside FORALLnew_facets - libqhull_r.c/qh_partitioncoplanar: clear qh.repart_id on exit for infinite recursion detect - geom2_4.c/qh_detmaxoutside: move qh_option call to qh_errexit - merge_r.c/mergetypes[]: fixed order by mergeT - merge_r.c/qh_all_vertexmerges: fix retryfacet for repeated calls - merge_r.c/qh_forcedmerge: f.dupridge retained after MRGdupridge hides MRGdegenerate in qh_test_degen_neighbors and qh_test_redundant_neighbors - merge_r.c/qh_postmerge: call qh_freemergesets - merge_r.c/qh_test_nonsimplicial_merge: clear iscoplanar if isconcave and any vertex is not coplanar - poly2_r.c/qh_triangulate: move reset of f.degenerate into delete facet loop Qhull C++ - QhullFacet.cpp: add hasNext() and hasPrevious() - QhullVertex.cpp: add hasNext() and hasPrevious() - qhulltest-64/QhullFacet_test.cpp,QhullVertex_test.cpp: test hasNext, hasPrevious, and hasPrevious iterator - user_eg3.cpp: use 'qhull-cout' for option 'Tz' (trace to cout) Qhull errors, warnings, and tracing - Error messages rewritten and error codes changed (see qh_fprintf) Renumbered Qhull warnings as 'QH7xxx' if needed (e.g., QH9375) Reused unused error and message codes ("def counters" in user_r.h/msgcode) Please check your code if it depends on error and message codes - Initialize variables to avoid potential uninitialized warnings - Use qh_ERRqhull for Qhull internal errors, "qhull internal error (qh_...): ..." - Use 'defined()' for qh_QHpointer_dllimport and qh_dllimport (-Wundef) - Use 'defined()' for __cplusplus, _MSC_VER, __MWERKS__, and __POWERPC__ (-Wundef) - Use 'Early exit' instead of 'At a premature exit' - libqhull_r.h/qh_ERRother: define error status for non-internal errors - libqhull_r.h/qh_ERRtopology: define error status for qhull topology errors - libqhull_r.h/qh_ERRwide: define error status for wide facets due to qhull precision error - geom_r.c/qh_setfacetplane: add qh_printfacet if qh.tracefacet for qh.tracefacet_id - global_r.c/qh_freebuild: record previousfacet/ridge/vertex in case a memory fault occurs - global_r.c/qh_init_flags: improved error message for 'cannot open file' for 'TO f' - global_r.c/qh_init_flags: improved warning message for 'unknown option' - global_r.c/qh_initbuild: add trace options to "Trace level ..." - global_r.c/qh_initqhull_globals: error if qh.VORONOI without qh.DELAUNAY - global_r.c/qh_initqhull_globals: error if numpoints is <1 or >qh_POINTSmax (INT_MAX-16) - global_r.c/qh_lib_check: use C-style comment for _CrtSetBreakAlloc - io_r.c/qh_printfacetheader: add "max" if f.merges==qh_MAXnummerge (511) - io_r.c/qh_readpoints: error if numinput is <1 or >qh_POINTSmax (INT_MAX-16) - io_r.c/qh_readpoints: moved up 'chop' of qh.rbox_command to report short input errors - io_r.c/qh_readpoints: replace warning QH7073 with error message. Override with Qallow-short - libqhull_r.c/qh_addpoint: if 'T4', check qh.visible_list before qh_partitionvisible - libqhull_r.c/qh_buildtracing: add delta cpu/facets/hyperplanes to QH1049 'qh_addpoint: add p%d...' - merge_r.c/qh_findbest_pinchedvertex: replaced assert with a 'qhull internal error' - merge_r.c/qh_check_dupridge: drop advice about reporting wide merges for error QH6271 - merge_r.c/qh_mark_dupridges: topological error if multiple dupridges for one facet, not handled - merge_r.c/qh_test_nonsimplicial_merge: if Qx and many merges, replace centrum_radius with maxoutside - poly_r.c/qh_matchneighbor: drop extra warnings for duplicate facet (QH7084) - poly_r.c/qh_matchnewfacets: check for simplicial facets on qh.newfacet_list, otherwise memory overwrite by qh_matchneighbor - poly2_r.c/qh_checkconvex: identify simplicial checking of vertices (qh.ZEROcentrum, default) - poly2_r.c/qh_checkconvex: distinguish above from coplanar for non-convex initial simplex - poly2_r.c/qh_checkconvex: "non-convex initial simplex" for qh_joggle_restart - poly2_r.c/qh_checkfacet: check f.id and f.vertex_visit - poly2_r.c/qh_checklists: check and repair facet and vertex lists for infinite loops or overwritten facets/vertices - poly2_r.c/qh_checkpolygon: if qh.NEWfacets, check visible facets for empty f.neighbors and f.ridges - poly2_r.c/qh_checkpolygon: add qh_checkvertex - poly2_r.c/qh_checkpolygon: check f.previous and v.previous links (for C++) - poly2_r.c/qh_checkvertex: add parameters for allchecks and waserror (like qh_checkfacet) - poly2_r.c/qh_checkvertex: check v.id and v.vertex_visit - qvoronoi.c/hidden_options: hide option 'FM'. Maple output is not available - rboxlib_r.c/qh_rboxpoints: use QH6... for error codes instead of warnings - stat_r.c/qh_stddev: check for division by 0 - testqset_r.c: send all messages, except 'OK' to stderr - testqset_r.c: reassign unique QH8nnn codes, 8001/etc in use by libqhull_r - user_r.c/qh_printhelp_internal: add descriptive message for a Qhull internal error - user_r.c/qh_printhelp_narrowhull: add option 'Qs' (search all points) - user_r.c/qh_printhelp_topology: add descriptive message for a Qhull topology error - user_r.c/qh_printhelp_wide: add descriptive message for a wide merge error - user_eg_r.c: add fflush and '=======' markers to interleave stdout with stderr (MSYS2) - user_eg2_r.c: add fflush and '=======' markers to interleave stdout with stderr (MSYS2) - user_eg2_r.c: add warning about calling qh_addpoint after qh_qhull with 'QJ' (joggle) Qhull documentation and statistics - Add Index to README.txt - Add links to Wiki, http://github.com/qhull/qhull/wiki - Add links to local home page (index.htm) - Add GitHub, Scholar, and Code to navigation bar on home page - Change numbered fixups to 'QH110nn FIX:' and renamed as MSG_FIX - Chrome and Internet Explorer load '.c' and '.h' files as text/html from the Web These browsers along with Firefox do not read disk files as text/html Changed 'Functions' link from a local link to "http://www.qhull.org/src/libqhull_r/index.htm" - Document implicit parameters at end of parameter list with '/* qh. ... */' - Limit maximum length of literals to 1800 characters - Move 'called by' comments to start of 'notes:' - Option 'QRn' appends the actual QRn to the summary line ('s') - Remove references to 'Qx' in 5-d and higher. It is automatically set by default. - Replace references to 'src/libqhull/*.htm' with reentrant 'src/libqhull_r/*_r.htm' - Retitle 'Qhull internals' as 'Qhull code' - Use 'nearly adjacent vertices' instead of 'nearly coincident points' - Use 'dupridge' instead of 'duplicate ridge' for ridges with more than two neighbors. Reserve 'duplicate ridge' for two ridges with the same vertices. - Various edits to documentation (*.htm) - Update copyright to 2019 - eg/q_test: Add examples to q_test "front ends" - html/index.htm: Add 'Limitations of merged facets' to the Qhull manual - html/index.htm: Add links to qdelaun_f.htm and qvoroin_f.htm (furthest-site) - html/qconvex.htm,etc: update synopsis and options - html/qh-code.htm: Add 'qh_addpoint' trace to 'Performance of Qhull' - html/qh-code.htm: Add a section on 'Debugging Qhull' with subsections for error codes, infinite loops, trace options, core dumps, segfaults, qtest.sh, and memory errors. - html/qh-impre.htm: Add 'Topological error' to 'Precision problems' - html/qh-impre.htm: Add 'Topological errors' to 'Limitations of merged facets' - html/qh-impre.htm: Add "narrow range of values" to 'Uneven dimensions' - html/qh-optq.htm: Add note to 'QJ' (joggle) about calls to qh_addpoint - html/qh-optt.htm#'Tc': 'T4' makes additional checks beyond check-frequently - html/qhalf.htm: Split the first example to clarify the "feasible point" for qhalf - html/qhalf.htm: Use 'feasible point' instead of 'interior point' for halfspace intersection Same as Qhull::feasiblePoint and distinguished from qh.interior_point - html/qhull.man,qhull.txt: updated man page - libqhull_r.h: update documentation for PRINTgood, GOODpoint, GOODvertex - qhull_ra.h: include ''. Used for INT_MAX,etc. - stat.h: add zretryadd stats for qh_merge_pinchedvertices - stat.h: add zvertextests for distance tests of vertices for merging - libqhull_r/*: document global variables as 'qh.' - libqhull_r/*: fix libqhull/... links - libqhull_r.c/qh_partitioncoplanar: reword Zpartflip as Zpartcorner with updated messages - merge_r.c/qh_merge_degenredundant: rename statistic Zneighbor to Zredundant - stat_r.c: new or reworded statistics for Zpartcorner, Zparthidden, Zparttwisted, Zpinchduplicate, Zpinchedvertex - stat_r.c: rename 'renamed vertex statistics' to 'statistics for vertex merges' - stat_r.c: add merge statistics for MRGconcavecoplanar - stat_r.c/qh_allstat: add ' ' before parens in statistics - user_eg_r.c,user_eg2_r.c: rewrote prompt Qhull changes - For simple initializers, remove spaces (e.g., 'for (i=0; ...') - Normalize spacing for libqhull - Normalize spacing as 'for (i=0; ...' for simple initializers - Review use of '>' for comparison to negative quantities. Usually should be '>=', e.g., for coplanar tests - Reassigned 8xxx and 9xxx codes as trace codes if traced at T3 or lower - Remove unused variables - Test floating point values with 0.0 instead of 0 (qh.premerge_centrum,lower_bound,upper_bound) - Use SETsecondt_() and SETelemt_() instead of SETelem_() when assigning to a specific type - Use '(type *)' for pointer casts. It makes the cast more visible. - Use void for empty parameter lists - geom_r.c/qh_findbesthorizon: mark startfacet visited, avoids unnecessary visit - geom2_r.c/qh_detmaxoutside: determine precision target qh.MAXoutside (option _maxoutside at error exit) replaces 'maxoutside' computation - geom2_r.c/qh_maxsimplex: add ratio test for false narrow hull with search for prevdet [J. Romain] - global_r.c/qh_freebuild: free global sets first instead of last, otherwise dangling references - io_r.c/qh_compare_nummerge: renamed qh_compare_facetmerge due to conflict with merge_r.h - io_r.c/qh_compare_vertexpoint: remove this routine. Not usable in libqhull_r due to 'qh' - io_r.c/qh_printfacetridges: do not print ridge if already printed (e.g., duplicate neighbors for merge of simplicial facets) - io_r.c/qh_produce_output2: fflush of qh.fout to show statistics and verification after output (MSYS2) - libqhull_r.h/qh.ALLOWwide: rename qh.NOwide to qh.ALLOWwide for 'Q12-allow-wide' - libqhull_r.h/qh.IGNOREpinched: replaced qh.MERGEpinched with reversed meaning - libqhull_r.c/qh_addpoint: 'TVn' stops after qh_all_vertexmerges, not before qh_resetlists. Matches documentation - merge_r.h/MRGdupridge: renamed MRGridge - merge_r.h/qh_ANGLEconcave,etc.: replace mergetype indicators with qh_ANGLEnone and m.mergetype - merge_r.c/qh_all_vertexmerges: replace qh_getmergeset_initial with qh_getmergeset. No facets created - merge_r.c/qh_all_vertexmerges: move while loop into qh_all_vertexmerges - merge_r.c/qh_append_mergeset: ignore merges into a MRGdegen facet (f.degenerate) - merge_r.c/qh_buildcone_mergepinched: clean up code and design documentation - merge_r.c/qh_compare_anglemerge: renamed qh_compareangle and sort by mergetype as well as angle - merge_r.c/qh_compare_facetmerge: merge MRGcoplanar before MRGconcave, opposite order from 2015.2 sort MRGanglecoplanar by angle - merge_r.c/qh_degen_redundant_facet,qh_test_degen_neighbors: moved into qh_mergefacet due to qh_willdelete - merge_r.c/qh_getmergeset,qh_getmergeset_initial: set f.tested after testing ridges, not before - merge_r.c/qh_next_facetmerge: split out next merge from qh_all_merges and replace qsort - merge_r.c/qh_findbest_pinchedvertex,qh_findbest_ridgevertex: dropped selecting merge direction via qh_vertex_isbelow. Expensive and evidence mixed - merge_r.c/qh_freemergesets,qh_initmergesets: pair qh_initmergesets with qh_freemergesets - merge_r.c/qh_freemergesets,qh_initmergesets: drop the 'all' parameter - merge_r.c/qh_mergecycle_all: move qh_merge_degenredundant, etc. to end from qh_premerge - merge_r.c/qh_mergesimplex: delete facet1 from facet2.neighbors at end, not at ridge - merge_r.c/qh_post_merges,qh_all_merges: remove setting of v.delridge on all vertices, not needed - merge_r.c/qh_premerge: replace parameter 'apex' with 'apexpointid'. Only used for logging - merge_r.c/qh_premerge: add qh.newfacet_list as an implicit parameter - merge_r.c/qh_test_degen_neighbors: split from qh_degen_redundant_neighbors and qh_mergefacet - merge_r.c/qh_test_redundant_neighbors: split from qh_degen_redundant_neighbors and qh_mergefacet - poly_r.c/qh_attachnewfacets: clear f.neighbors and f.ridges for visible facets, will be deleted - poly_r.c/qh_matchnewfacets: remove call to qh_checkflipped_all for qh.FORCEoutput, checked by qh_setfacetplane - poly_r.c/qh_update_vertexneighbors: renamed qh_updatevertices. A future version will optimize qh_update_vertexneighbors_cone: optimization for cone of new facets - poly2_r.c/qh_checkconvex: immediate skip of f.tricoplanar facets. Tricoplanar facets not tested. Called before qh_triangulate - poly2_r.c/qh_initbuild: move 'create sentinels' before qh_createsimplex so that qh.vertex_tail is v0 like f0 - poly2_r.c/qh_initialvertices: cleaned up code for qh_INITIALmax (8-d) - poly2_r.c/qh_makenewfacets: clear f.neighbors and f.ridges for visible facets, will be deleted - poly2_r.c/qh_matchdupridge: optimize dupridge for flipped->!flipped, good merge, not !flipped->flipped - poly2_r.c/qh_matchdupridge_coplanarhorizon: dropped routine. Results same or slightly worse. Complex addition, rarely used - poly2_r.c/qh_triangulate: rename facet and vertex lists as triangulated_facet_list,etc. qh_triangulate does not maintain qh.newfacet_list or qh.visible_list - poly2_r.c/qh_triangulate: ignore qh.NEWfacets. qh_checkpolygon is not valid inside qh_triangulate - rboxlib_r.c/qh_rboxpoints2: split function from qh_rboxpoints to avoid -Wclobbered - stat_r.c/qh_printstatlevel: remove unused NULLfield Qhull C++ changes - Use NULL instead of 0 for pointers - Remove old style casts such as '(size_t)...' - Define initializers for default constructors even if explicitly assigned - Update static initializer list for s_empty_facet, s_empty_ridge, s_empty_vertex - Coordinates.h: default constructor clears coordinate_array - Coordinates.h: default iterator constructor clears i - RboxPoints.cpp/qh_fprintf_rbox: add empty default to switch statement ------------ Qhull 2018.0.1 2018/12/28 (7.3.0) Qhull options - If unknown option, report error QH6035 instead of warning QH7035. Override with Qw - Add option 'Tf' to flush each qh_fprintf for debugging segfaults - Add Q14-ignore-pinched-vertices: ignore pinched vertices due to dupridge Default if post-merge only ('Cn'), 'Qgood-only', or 2-d convex hulls - Expand Q12-allow-wide to include wide facet errors reported by qh_check_maxout and qh_merge_facet - Add Q16-simplex-merge: test opposite vertex instead of centrum for merges - option 'f' (print facets): updated flags for facets 'seen' and 'seen2' flags not listed (listed if tracing) Renamed 'new' to 'newfacet' 'isarea' if area is listed for the facet 'cycledone' if qh_mergefacet completed Renamed 'MERGE' to 'MERGEridge' in the facet neighors (for merging) Renamed 'DUP' to 'DUPLICATEridge' in the facet neighors (for merging) Comment '- horizon ridge to visible facet' added for tentative new facets - option 'f' (print facets): updated flags for ridges 'mergevertex' and 'mergevertex2' if a ridge vertex will be merged 'simplicialtop' and 'simplicialbot' if the top/bottom facet is simplicial - option 'f' (print facets): updated flags for vertices Renamed 'ridgedeleted' to 'delridge' 'newfacet' if the vertex belongs to a new facet on qh.newfacet_list 'seen' and 'seen2' listed if tracing - Option 'T3' prepend message number for trace levels 0-3 e.g., "[QH1040]qh_findhorizon: find horizon..." - Option 'TCone_stop' stops before vertex merge due to duplicate ridges (unlikely) - Option 'Ts' (qh_initbuild): print command prompt at start of run for segfaults - Rename option 'U-coplanar-distance' to 'U-max-coplanar' (qh.MAXcoplanar) Qhull documentation - Explanation of clobbered warning for Qhull::runQhull and qh_new_qhull - html/index.htm: Add "Nearly coincident points" to "When to use Qhull" - html/index.htm: Add Tomilov's qhullhull.hpp for general position input. - html/qh-eg.htm: Add 'Q0' link to eg.14.sphere.corner - html/qh-faq.htm,qh-code.htm: merge slivers in a Delaunay triangulation [M. Treacy] - html/qh-optq.htm: Update documentation for 'Qx' and its default behavior - html/qh-impre.htm: Rewrote notes on 'Nearly coincident points within 1e-13' - geom_r.c/qh_distplane: nearly coplanar points may return the same distance for different points Qhull builds - Move 'extern "C" {}' logic from C++ to C headers [C. Atkins, nine7nine, W. Scullin, M. Culpo] - build/*-64.vcxproj Updated for tool set 8.1 - CMakeLists.txt: Add note for "dynamic linking" of qhull executables [M. Atzeri] - CMakeLists.txt: Revert accidental commit cea6d22 [pchilds, QuLogic, fabiencastan, daniel-packard] Bugs fixed - html/*.htm: fix trailing
after 'Comments to:' - libqulll_r.c/qh_findbest: search from newfacet_list instead of f.next if !bestfacet - merge_r.c/qh_find_newvertex: use v.seen to avoid maxvisit > qh.vertex_visit - merge_r.c/qh_merge_simplex: repeat with next ridge after qh_delridge_merge - merge_r.c/qh_vertexridges: 'qh.visit_id += 2' to avoid visit_id collision - poly_r.c/qh_appendfacet: update qh.visible_list if qh.newfacet_list/visible_list are empty - poly2_r.c/qh_check_maxout: check qh.min_vertex if qh.VERIFYoutput/CHECKfrequently - poly2_r.c/qh_checkpolygon: do not report qh.visible_list error if visible_list and newfacet_list are defined but empty - Qhull.cpp/outputQhull: do not call qh_check_points if qh.FORCEoutput - stat_r.c/qh_printallstatistics,qh_printstatistics: 'const char *string' instead of 'char *string' for !qh_KEEPstatistics - user_r.c/qh_new_qhull: do not call qh_check_points if qh.FORCEoutput - user_eg2.c: do not call qh_check_points if qh.FORCEoutput Qhull error reporting - io_r.c/qh_readpoints: improved formating of error "QH6410 ... instead of n points" - libqulll_r.c/qh_findhorizon: error if no neighbors for a visible facet - libqulll_r.c/qh_findbestnew: error if facet sentinel (!facet->next) - libqhull_r.c/qh_nextfurthest: error if infinite loop - libqhull_r.c/qh_partitioncoplanar: error if partition into a visible facet - libqhull_r.c/qh_partitionpoint: error if partition into a visible facet - libqhull_r.c/qh_partitionvisible: error if deleted vertex with an empty qh.newfacet_list - libqulll_r.c/qh_printsummary: if qh.ERREXITcalled and qh.DELAUNAY, update f.good and qh.num_good (qh_findgood_all) - merge_r.c/qh_checkdelfacet: check that mergeset does not reference facet - merge_r.c/qh_checkdelridge: check that qh_delridge_merge is not needed for deleted ridges Call from qh_mergecycle, qh_makenewfacets, qh_attachnewfacets - merge_r.c/qh_maydropneighbor: error if simplicial facet or neighbor - merge_r.c/qh_merge_facet: error if wide merge (allow with 'Q12') - merge_r.c/qh_merge_nonconvex: error if unexected mergetype - poly_r.c/qh_matchneighbor: convert error QH6106 (two facets with same vertices) to a warning (QH7084) and automatic fix - poly2_r.c/qh_check_maxout: error if wide qh.max_outside/min_vertex (allow with 'Q12') - poly2_r.c/qh_check_maxout: warn if wide maxout for vertices (for diagnosing errors) - poly2_r.c/qh_check_maxout: warn if point is outside f.outside (for diagnosing errors) - poly2_r.c/qh_check_maxout: warn if 'f.maxoutside > qh.max_outside' - poly2_r.c/qh_check_maxout: changed comparison from 'dist==maxoutside' to 'dist >= maxoutside' (allow multiple warnings) - poly2_r.c/qh_checkfacet: error if 'redundant' or 'degenerate', but neither 'visible' nor qh.degen_mergeset - poly2_r.c/qh_checkfacet: error if 'dupridge' or 'newmerge', but not 'newfacet' - poly2_r.c/qh_checkfacet: error if neighbor of facet is 'visible' (i.e., deleted) - poly2_r.c/qh_checkfacet: report 'Repaired by qh_remove_extravertices' as trace4 (QH4025) instead of error QH6134 - poly2_r.c/qh_checkpolygon: error if qh.visible_list is after qh.newfacet_list - poly2_r.c/qh_checkpolygon: error if f.newfacet before qh.visible_list or qh.newfacet_list - poly2_r.c/qh_checkpolygon: error if qh.newfacet_list without f.newfacet - poly2_r.c/qh_checkpolygon: error if f.visible not on qh.visible_list - poly2_r.c/qh_checkpolygon: error if qh.visible_list without f.visible - poly2_r.c/qh_checkpolygon: error if qh.newfacet_list is not on qh.facet_list - poly2_r.c/qh_checkpolygon: error if v.newfacet not on qh.newvertex_list - poly2_r.c/qh_checkpolygon: error if qh.newvertex_list is not on qh.vertex_list - poly2_r.c/qh_checkpolygon: error if a facet occurs twice in v.neighbors - poly2_r.c/qh_checkpolygon: error if vertex not in f.vertices for facets in v.neighbors - poly2_r.c/qh_checkpolygon: error if facet not in v.neighbors for vertices in f.vertices - poly2_r.c/qh_delvertex: error if vertex previously deleted but not partitioned as a coplanar point - user_r.c/qh_errexit: clear printed flags on statistics (qh_allstatistics) - user_r.c/qh_errprint: print vertex and ridge before facets - user_r.c/qh_printfacetlist: add 'qh_printfacetlist:' for rapid navigation Source code additions - mergeT: expanded for vertices and ridges - mergeType: add MRGconcavecoplanar, MRGtwisted, MRGsubridge, MRGvertices, and MRGcoplanarhorizon - qtT.FLUSHprint: true if 'Tf', flush output on qh_fprintf - qtT.MERGEpinched: false if 'Q14', merge pinched vertex due to duplicate ridge - qtT.SIMPLEXmerge: true if 'Q16', test_appendmerge tests opposite vertex instead of centrum - qtT.first_newfacet: id of first new facet in qh_buildcone, other new facets were merged - qtT.isRenameVertex: true during qh_merge_pinchedvertices - qtT.NEWtentative: true while new facets are tentative due to qh.MERGEpinched or ONLYgood - qtT.repart_facetid: previous facetid to prevent recursive qh_partitioncoplanar - qtT.retry_addpoint: number of retries of qh_addpoint due to qh.MERGEpinched - qtT.vertex_mergeset: set of vertex merges for qh_next_vertexmerge - ridgeT.mergevertex and mergevertex2 if a ridge vertex will be merged - ridgeT.simplicialtop and simplicialbot if the top/bottom facet is simplicial - vertexT.partitioned: true if deleted vertex partitioned by qh_partitionvisible - geom2_r.c/qh_furthestnewvertex: return furthest unvisited, new vertex to a facet - geom2_r.c/qh_furthestvertex: return furthest unvisited vertex to a facet - geom2_r.c/qh_vertex_bestdist: return nearest distance between vertices - geom2_r.c/qh_vertex_bestdist2: return nearest vertex pair between vertices - geom2_r.c/qh_vertex_isbelow: test vertexA distance to vertexB's simplicial facets and vice versa - libqhull_r.c/qh_buildcone: split out qh_makenewfacets,etc. from qh_addpoint - merge_r.c/qh_all_vertexmerges: perform vertex merges in qh.vertex_mergeset - merge_r.c/qh_appendvertexmerge: append vertex merge to qh.vertex_mergeset - merge_r.c/qh_delridge_merge: split out ridge maintenance from qh_renameridgevertex and qh_merge_simplex - merge_r.c/qh_hasmerge: True if mergeset has mergetype for facetA and facetB - merge_r.c/qh_initmergesets,qh_freemergesets: init/free of qh.*_mergeset with error reporting - merge_r.c/qh_maybe_duplicateridge: add MRGvertices if neighboring facet has another ridge with the same vertices - merge_r.c/qh_maybe_duplicateridges: add MRGvertices if ridges with the same vertices - merge_r.c/qh_merge_dupridges: split out conversion of dupridges to MRGridge merges from qh_makeridges - merge_r.c/qh_merge_pinchedvertices- merge pinched vertices in qh.vertex_mergeset to avoid qh_forcedmerges of duplicated ridges - merge_r.c/qh_merge_twisted: merge twisted facets that are above and below their neighbors (4D+ and non-simplicial) - merge_r.c/qh_neighbor_vertices,qh_neighbor_vertices_facet: return neighboring vertices for a vertex (not in subridge) - merge_r.c/qh_next_vertexmerge: select next vertex merge by distance, allow one MRGsubridge merge - merge_r.c/qh_opposite_horizonfacet: return horizon facet for a merge facet and its opposite vertex - merge_r.c/qh_reducevertices: qh_merge_degenredundant if qh_remove_extravertices or qh_rename_sharedvertex - merge_r.c/qh_remove_mergetype: remove mergetype merges from mergeset - merge_r.c/qh_rename_adjacentvertex: rename oldvertex as newvertex, must be adjacent (i.e., in the same subridge) - merge_r.c/qh_test_cemtrum_merge: split out test centrum convexity from qh_test_appendmerge - merge_r.c/qh_test_nonsimplicial_merge: test nonsimplicial convexity and append non-convex facets to qh.facet_mergeset - merge_r.h/FOREACHmergeA_,FOREACHmerge_i_: add macros for mergeset iteration - poly_r.c/qh_getreplacement: split out new facet for visible facet from qh_partitionvisible and qh_merge_degenredunant - poly2_r.c/qh_addfacetvertex: split out add newvertex to f.vertices if not already there from qh_merge_simplex - poly2_r.c/qh_matchdupridge_coplanarhorizon: match duplicate ridges with the same coplanar horizon, instead of qh_matchdupridge - poly2_r.c/qh_opposite_vertex: return the opposite vertex in facetA to neighbor - poly2_r.c/qh_replacefacetvertex: replace oldvertex with newvertex in f.vertices - user_r.h/qh_RATIOconcavehorizon: ratio of horizon vertex distance to qh.max_outside for concave, twisted new facets in qh_test_nonsimplicial_merge - user_r.h/qh_RATIOconvexmerge: ratio of vertex distance to qh.min_vertex for clearly convex new facets in qh_test_nonsimplicial_merge - user_r.h/qh_RATIOcoplanarapex: ratio of best distance for coplanar apex vs. vertex merge in qh_getpinchedmerges - user_r.h/qh_RATIOcoplanaroutside: ratio to repartition a coplanar point as an outside point in qh_partitioncoplanar and qh_check_maxout - user_r.h/qh_RATIOpinchedsubridge: ratio to qh.ONEmerge to accept vertices in qh_findbest_pinchedvertex - user_r.h/qh_RATIOtrypinched: ratio to qh.ONEmerge to merge twisted facets in qh_merge_twisted - user_r.h/qh_RATIOtwisted: maximum ratio to qh.ONEmerge to merge twisted facets in qh_merge_twisted - user_r.h/qh_WIDEmaxoutside: precision ratio for maximum increase for qh.max_outside in qh_check_maxout - user_r.h/qh_WIDEmaxoutside2: precision ratio for maximum qh.max_outside in qh_check_maxout - user_r.h/qh_WIDEpinched: merge ratio for distance between pinched vertices compared to current facet width for qh_getpinchedmerges and qh_next_vertexmerge Source code changes - Change " = " to "= " (avoid confusion with "==") - Improved tracing and code comments throughout - Moved qh_check_dupridge from poly2_r.c to merge_r.c. It is used for merging - Removed qh_compareangle and qh_comparemerge. Replaced by qh_next_facetmerge - Renamed 'qh_precision' to 'qh_joggle_restart'. It restarts qhull to avoid a precision error. - Renamed 'Qhull internal error' to 'qhull internal error' for consistency - Renamed mergeT.type to mergetype. Same as parameters and local variables - Renamed vertexT.newlist to newfacet. True if on a new facet - Renamed qh_matchduplicates to qh_matchdupridge (poly2_r.c). A 'duplicates' is ridges with duplicate vertices - Use coordT for distances instead of realT. Needs further review. - qh_NOmerge: include comments in #ifndef - global_r.c/qh_freebuffers: use the same order as qh_initbuffers - global_r.c/qh_freebuild: free the global sets, qh.degen_mergeset,etc. - io_r.c/qh_printfacetheader: print 'MERGEridge' instead of 'MERGE' to match name of flag - io_r.c/qh_printfacetheader: print 'DUPLICATEridge' instead of 'DUP' to match name of flag - libqhull_r.c/qh_partitioncoplanar: change qh.findbestnew to a parameter (search all new facets) - libqhull_r.c/qh_partitioncoplanar: repartition a coplanar point if far outside typically due to a twisted facet in D4+ with almost coincident vertices - libqhull_r.c/qh_partitionpoint: if outside set is empty, set f.newfacet and adjust qh.facet_next - libqhull_r.c/qh_partitionvisible: prevent duplicate partitions of deleted vertices - libqhull_r.c/qh_partitionvisible: test against !f.next instead of qh.facet_tail. Both indicate sentinel - mrege_r.h/mergeType: reordered mergetypes is preference order - merge_r.c: identify MRGconcavecoplanar facets that are above and coplanar with their neighbors - merge_r.c/mergetypes: string names for mergeType - merge_r.c/qh_all_merges: clear wasmerge and othermerge on qh_reducevertices. Avoids extra calls - merge_r.c/qh_appendmergeset: add parameters for m.dist and m.angle - merge_r.c/qh_appendmergeset: initialize all fields of mergeT - merge_r.c/qh_copynonconvex: clear old r.nonconvex for consistency. Ridge will be deleted soon - merge_r.c/qh_degen_redundant_neighbors: check neighbors of delfacet instead of facet. Faster and it matches definition - merge_r.c/qh_mark_dupridges: add 'allmerges' parameter for dupridges vs. pinched vertices - merge_r.c/qh_mark_dupridges: test for duplicate vertices to avoid duplicate MRGridge - merge_r.c/qh_merge_cycle_all: test for duplicate ridges at end of merge_cycle_all (qh_maybe_duplicateridges) - merge_r.c/qh_merge_dupridges: clear mergeridge/mergeridge2 flags (not needed on first call) - merge_r.c/qh_merge_facet: test for qh_degen_redundant_facet and qh_maybe_duplicateridges - merge_r.c/qh_merge_facet: add mergeType parameter for logging - merge_r.c/qh_merge_facet: rename 'apex' to 'opposite' (not always apex) - merge_r.c/qh_merge_simplex: identify 'isnew' instead of 'issame' (more accurate) - merge_r.c/qh_remove_extravertices: skip for simplicial facets - merge_r.c/qh_renamevertex: test qh_maybe_duplicateridge if qh_renameridgevertex - merge_r.c/qh_renamevertex: test qh_degen_redundant_facet for oldvertex neighbors - merge_r.c/qh_renamevertex: test qh_degen_redundant_neighbors for oldvertex nonsimplicial neighbors - merge_r.c/qh_renamevertex: test qh_maybe_duplicateridge if qh_renameridgevertex - merge_r.c/qh_renamevertex: test qh_degen_redundant_facet oldfacet - merge_r.c/qh_tracemerge: add mergeType parameter for logging - merge_r.c/qh_test_appendmerge: calls qh_test_centrum_merge or qh_test_nonsimplicial_merge as needed - merge_r.c/qh_vertexridges: add 'allneighbors' parameter to test all neighbors of a vertex - merge_r.c/qh_vertexridges_facet: optimize qh_setin by common cases - poly_r.c/qh_checkflipped: move call from qh_matchnewfacets to qh_setfacetplane. Allow call of qh_setfacetplane from qh_initialhull to reverse orientation - poly_r.c/qh_matchneighbor: call qh_setfacetplane/qh_checkflipped on-demand to support qh.NEWtentative - poly_r.c/qh_matchnewfacets: returns maxdupdist for duplicate ridges - poly_r.c/qh_matchnewfacets: move qh_joggle_restart from qh_matchduplicates ("ridge with multiple neighbors") - poly_r.c/qh_matchnewfacets: try to match ridges with coplanar horizon (qh_matchdupridge_coplanarhorizon) - poly_r.c/qh_update_vertexneighbors: use qh_setunique to pdate vertex neighbors (due to pinched vertex merge) - poly2_r.c/qh_checkfacet: optimize qh_setequal of ridges with the same vertices - poly2_r.c/qh_checkpolygon: do not include visible facets in totvertices - poly2_r.c/qh_initialhull: use f.flipped instead of qh_distplane/qh_checkflipped (qh_checkflipped called from qh_setfacetplane) - poly2_r.c/qh_matchdupridge: was qh_matchduplicates in qhull 2015.2 - poly2_r.c/qh_matchdupridge: detect duplicate facets/ridges and force vertex merge - poly2_r.c/qh_matchdupridge: separate code for qh_DUPLICATEridge/f.tricoplanar for improved logging - poly2_r.c/qh_matchdupridge: if !makematch, collect best match via flipped and qh_getdistance between facets - poly2_r.c/qh_resetlists: clear f.dupridge - poly2_r.c/qh_triangulate: clear f.degenerate at end (degenerate tricoplanar facets) - poly2_r.c/qh_triangulate_link: skip duplicate MRGmirror merges - poly2_r.c/qh_triangulate_mirror: skip duplicate MRGmirror merges and previously deleted MRGmirror facets ------------ Qhull github 2018 - Fixed confusing indentation [A. Lee 2018/12/28] - Add labels for each release [A. Mailaga 2016/7/5] - Add 'typename qualifier to QhullSet [D. Gomes 2016/6/16] - Make C headers safe for C++ inclusion [C. Atkins 2016/01/20] - build/qhull*.pc.in: Removed templates for pkg-config (not updated for Qhull 2015) ============= == Qhull 2015 ============= ------------ Qhull 2015.2 2016/01/18 (7.2.0) - Fixed memory leak in ~QhullQh [M. Sandim] QhullQh.cpp: call checkAndFreeQhullMemory() in the destructor. Otherwise memT is not freed. Remove checkAndFreeQhullMemory() from Qhull.h. It is not needed. Remove calls to checkAndFreeQhullMemory in qhulltest. It is called by ~QhullQh() libqhull_r.h: Document qh_ASvornoi and facetT.center qh_freeqhull: if qh_NOmem, use qh_ALL qh_memalloc: short memory is freed by qh_memfreeshort unless qh_NOmem qh_memstatistics (mem.c): call qh_memcheck() as done in mem_r.c qh_new_qhull calls qh_memcheck qh_newvertex: free vertex on error qh_projectinput: Free memory allocations on error qh_rboxpoints: free simplex on error qh_sethalfspace_all: Fixed memory leak on error QH8032 feasible not inside halfspace qh_triangulate_facet: For TRInormals ('Q11') replace qh_copypoints with qh_memalloc qh_triangulate_facet: Document qh.TRInormals qh_voronoi_center: Free center on error qhulltest: Fixed memory leak of s_testcases by calling RoadTest::deleteTests() qhulltest: The 'add_*_test' functions append the test object to RoadTest::s_testcases ~RoadTest: declare virtual for Q_OBJECT, removeAll not needed user_eg2: Check memory at end of each run user_r.h: Add QHULL_CRTDBG for invoking Microsoft's memory leak detector use _MSC_VER instead of QHULL_OS_WIN for QHULL_CRTDBG Call qh_freeqhull with qh_ALL/!qh_ALL instead of 'True/False' Include user_r.h with RoadError,h for QHULL_CRTDBG Invoke _CrtSetDbgFlag... at beginning of program Moved user_r.h/libqhull_r.h/qhull_ra.h as first include (for QHULL_CRTDBG) Moved QHULL_OS_WIN from qhull_ra.h to user_r.h Removed __CYGWIN__ from QHULL_OS_WIN (same as Qt's qglobal.h) - check_dupridge: A bounding box is not sufficient to avoid dupridge errors - qh_findbestneighor: Error if qh.CENTERtype is qh_ASvoronoi (i.e., no merging now) - qh_printstatlevel: Remove unused parameter, 'start' - QhullLinkedList::last() and back(): Return T instead of T& (T is computed) - qh-code.htm: "How to convert code to reentrant Qhull" Update "Nearly coincident points on an edge" Add 2012 size of data structures to "Qhull on 64-bit computers" - html/index.htm: Add CGAL to "When to use" - qh-optq.htm: Add documentation for option 'Q12' - Move suggestions from Changes.txt to qh-code.htm#enhance - user_r.h: Fixed qh-us_r.html links - Fixed links in html pages - QhullIterator and QhullLinkedList: Include [B. Boeckel] - Moved include file for each C++ source file to the top of the includes - Prepend cpp includes with "libqhullcpp/" - RoadLogEvent includes RoadLogEvent.h - QhullIterator.h: Only QHULL_DECLARE_SEQUENTIAL_ITERATOR is used. - Compared src/libqhull/* to src/libqhull_r/* and resolved differences - qh_printpoint in io.c skips qh_IDnone like io_r.c - qhull_p-exports.def: Added three missing exports - set_r.h: Removed countT. Too many issues - libqhull_r/Makefile: Add help prompts to 'make qtest' - libqhull.pro: Add '../libqhull/' to sources and headers - libqhull/Makefile: Fixed -I,./,,/src - qhull-zip.sh: Add CMakeModules to tarball [C. Rosenvik] - CMakeLists.txt: Add targets qhullp and user_egp for qh_QHpointer and libqhull_p - Reorganized 'make help' - Makefile cleanall: Delete testqset and qhulltest from bin/ - Fix filetype of Unix-only files - Fix Unix line endings for Makefile and check in qhull-zip.sh - Fix Windows line-endings and check in qhull-zip.sh - qhull-zip.sh: Check for Unix text files ------------ Qhull 2015.1 2016/01/03 (7.1.0) - Add Rbox option 'Cn,r,m' to add nearly coincident points. Trigger for duplicate ridges - Add Qhull option 'Q12' to allow wide merge due to a dupridge - qh_findbestlower: Call qh_findfacet_all to fix rare "flipped or upper Delaunay" error QH6228 (now QH3025) QH6228 input provided by J. Metz. Reported (date order): L. Fiaschi, N. Bowler, A. Liebscher, V. Vieira, N. Rhinehart, N. Vance, P. Shafer - qh_check_dupridge: Check if wide merge due to duplicate ridge from nearly coincident points - qh_initialhull: Fix error messages for initial simplex is flat - qh_determinant: increased 2-d and 3-d nearzero by 10x due to a counter-example - rbox: Add qh_outcoord() to output coordinates w/ or w/o iscdd - qh_meminit (mem.c): Add call to qh_memcheck - Compare libqhull/... to libqhull_r/... and resolve differences - Update builds for DevStudio (qhull.sln for msdev 2005..2009, qhull-32.sln and qhull-64.sln for recent releases) - qh-impre.htm: Add a section about precision errors for 'Nearly coincident points on an edge' - html/index.htm#geomview: Document how to install, build, and use Geomview. - html/index.htm: Emphasize program links and move related urls to end - qhull/index.htm: Emphasize manual, geomview, and imprecision - Fix documentation links in libqhull_r/index.htm - Add 'Functions' link to documentation headers - Change '...' to '...' - libqhull_r/index.htm -- Add instructions for configuring web browsers for source links. - libqhull_r/ -- Fix source links for ..._r.htm files ------------ Qhull 2015.0.7 2015/11/09 (7.0.7) - Fix return type of operator-> in QhullLinkedList and other collection classes [F. Jares] - Fix return types for QhullLinkedList - Fix return types for QhullPoints - Simplify return type for Coordinates::operator[] (same as QList) - Add const to operators for QhullSet::iterator and add documentation - Coordinates.h: Fix return types for operations of iterator and const_iterator - Drop use of Perforce changelist number in qhull_VERSION of CMakeLists.txt - Rename the md5sum files as *.tgz.md5sum instead of *-tgz.md5sum - Fix build dependency for testqset_r [asekez] - rbox.c depends on Qhull due to qh_lib_check which uses qh_version2 for error messages - QhullFacet_test.cpp: Annotate Qhull invocations. Allows their repetition. - QhullFacet_test.cpp: Adjust epsilon on distance tests - Do not create libqhullcpp as a shared library. Qhull C++ classes may change layout and size. - qhull-cpp.xml: Make a relative path to road-faq.xsl ------------ Qhull 2015.0.6 2015/10/20 (7.0.6.2013) - In the libraries, exit() is only called from qh_exit(). qh_exit may be redefined. - Add qh_fprintf_stderr to usermem.c. May be overridden to avoid use of stderr [D. Sterratt] Add usermem to testqset builds Used by qh_fprintf_rbox - Remove most instances of stderr/stdout from libqhull, libqhull_r, and libqhullcpp [D. Sterratt] qh_fprintf_stderr may be redefined. qh_meminit and qh_new_qhull use stderr as the default ferr - qh_initflags: Use qh.fout instead of stdout for 'TO file'. A library caller may define a different qh.fout. - qh_settemppush: Call qh_fprintf() instead of fprintf() on error. - Rename qh_call_qhull as "Qhull-template" from user.c. Updated its references. - qh-code.htm: "How to avoid exit(), fprintf(), stderr, and stdout" - html/index.htm: Fix table of contents for qh-code - libqhull_r/index.htm: Rewrite introduction to Reentrant Qhull - qh-faq.htm: Rewrite "Can Qhull use coordinates without placing them in a data file?" - qh-get.html: Link to github - Remove qhull_interface.cpp from the documentation ------------ Qhull 2015.0.5 2015/10/12 (7.0.5.1995) - qh_new_qhull: default 'errfile' is 'stderr'. outfile and errfile are optional [B. Pearlmutter] - qh_new_qhull: returns qh_ERRinput instead of exit() if qhull_cmd is not "qhull ..." [B. Pearlmutter] - qhalf_r.c,etc: Add clear of qh.NOerrexit - global.c: gcc 4.4.0 mingw32 segfault cleared by adding comment - usermem_r-cpp.cpp: Optional file to redefine qh_exit() as throw "QH10003.." [B. Pearlmutter] qh_exit() is called by qhull_r when qh_errexit() is not available. - html/index.htm: Add bibliographic reference to Golub & van Loan and other references [R. Gaul] - qhalf.htm: A halfspace is the points on or below a hyperplane [D. Strawn] - qh-opto.htm#n: Defined inside, outside, on, above, and below a hyperplane [D. Strawn] - qhalf.htm#notes: Recast the linear program using negative halfspaces (as used by Qhull) [D. Strawn] - qhull_a.h: Fix comment '#include "libqhull/qhull_a.h" [fe rew] - build/qhull*.pc.in: Templates for pkg-config (derived from Fedorra) [P. McMunn] https://bitbucket.org/mgorny/pkg-config-spec/src/c1bf12afe0df6d95f2fe3f5e1ffb4c50f018825d/pkg-config-spec.txt?at=master&fileviewer=file-view-default - Makefile: Remove user_eg3.o from LIBQHULLCPP_OBJS - Makefile: Add .h dependencies for unix_r.o, etc. - libqhull/Makefile: Fix build of rbox - libqhull_r/Makefile: Fix build -I - qhull.sln/user_eg3: Add dependency on libcpp - Removed bin/libqhull_r.dll (should be qhull_r.dll) - Removed build/qhulltest.vcproj (see build/qhulltest/qhulltest.vcproj) ------------ Qhull 2015.0.4 2015/9/30 (7.0.4.1984) - qh-get.htm: Unix tarball includes version number (e.g., qhull-2015-src-7.1.0.1940.tgz) [Hauptman] - qglobal.c: Add qh_version2 with Unix version for "-V" option [Hauptman] - build/qhull-32.sln, *-32.vcxproj: Add Visual Studio 32-bit build for 2010+ - build/qhull-64.sln, *-64.vcxproj: Add Visual Studio 64-bit build for 2010+ [G. Lodron] - make-vcproj.sh: Restore to eg/... It is required for Visual Studio builds - README.txt: updated builds and reentrant Qhull - Add documentation for QHULL_LIB_CHECK - qh_lib_check: Check for unknown QHULL_LIB_TYPE - qh-code.htm: Add memory requirements for 32- and 64-bit ------------ Qhull 2015.0.3 2015/9/22 - qh_mem, qh_merge: Log before 'delete' instead of afterwards [Coverity, K. Schwehr] - qh_merge: Test for NULL horizon in qh_checkzero [Coverity, K. Schwehr] - qh_matchneighbor: Check for matchfacet not a neighbor of facet [Coverity, K. Schwehr] - qh_triangulate: Explicit check for visible==NULL [Coverity, K. Schwehr] - qh_findbestfacet (unused by qhull): Fix test of isoutside [Coverity, K. Schwehr] - qh_check_maxout: Check bestfacet!=0 for logging its id [Coverity, K. Schwehr] - qh_nearvertex: Check for bestvertex not found [Coverity, K. Schwehr] - qh_checkfacet: Check for missing neighbors of simplicial facets [Coverity, K. Schwehr] - qh_setdelnth: Check 'nth' before using it [Coverity, K. Schwehr] - Annotate code for Coverity warnings (most of these protected by qh_errexit) [K. Schwehr] - qh_printfacet3math: explicit format string (duplicates change to io.c) [B. Pearlmutter] - libqhull_r.h: fix spelling error (duplicates change to libqhull.h) [B. Pearlmutter] - unix_r.c: fix spelling error (duplicates change to unix.c) [B. Pearlmutter] - qhull_a.h: define qhullUnused() only if defined(__cplusplus) [R. Stogner] - qh_version: Use const char str[]= "string" instead of const char * str= "string" [U. Drepper, p. 27] - qh_newvertex: Use UINT_MAX instead of 0xFFFFFFFF - qh_newridge: Use UINT_MAX instead of 0xFFFFFFFF - Reviewed FIXUP notes - QhullRidge_test: t_foreach use 'foreach(const QhullVertex &v, vertices) - Made '#include "RoadTest.h" consistent across all C++ tests - qh-code.htm: May also use libqhull_r (e.g., FOREACHfacet_(...)) - qh-get.htm: Add list of download build repositories - Add CMakeModules/CheckLFS.cmake: Enables Large File Support [B. Pearlmutter] - Makefile: Use -fpic at all times instead of -fPIC, [U. Drepper p. 15] ------------ Qhull 2015.0.2 2015/9/1 - global_r.c: Fixed spelling of /* duplicated in...qh_clear_outputflags */ [K. Schwehr] - Replaced Gitorious with GitHub - Moved 'to do' comments into Changes.txt ------------ Qhull 2015.0.1 2015/8/31 Source code changes - Increased size of vertexT.id and ridgeT.id to 2^32 [H. Strandenes, C. Carson, K. Nguyen] Reworded the warning message for ridgeT.id overflow. It does not affect Qhull output - Add qh_lib_check to check for a compatible Qhull library. Programs should call QHULL_LIB_CHECK before calling Qhull. - Include headers prefixed with libqhull/, libqhull_r/, or libqhullcpp/ - Renamed debugging routines dfacet/dvertex to qh_dfacet/qh_dvertex - Rewrote user_eg, user_eg2, and user_eg3 as reentrant code - Renamed 'qh_rand_seed' to 'qh_last_random'. Declare it as DATA - qh_initqhull_start2 sets qh->NOerrexit on initialization User must clear NOerrexit after setjmp() Other source code changes - Define ptr_intT as 'long long' for __MINGW64__ [A. Voskov] - poly_r.c: initialize horizon_skip [K. Schwehr] - Removed vertexT.dim and MAX_vdim. It is not used by reentrant Qhull. - Removed qhull_inuse. Not used by C++ - Removed old __MWERKS__/__POWERPC__ code that speed up SIOUX I/O - Moved #include libqhull/... before system includes (e.g., - Comment-out _isatty declaration. Avoids "C4273 ... inconsistent dll linkage" - Add random.h/random_r.h as an include file to random.c/random_r.c - Rename rbox routines to qh_roundi/qh_out1/qh_out2n/qh_out3n - Rename dfacet and dvertex to qh_dfacet and qh_dvertex - Replace 'qhmem .zzz' with 'qhmem.zzz' - Removed spaces between function name and parentheses - Rename 'enum statistics' to 'enum qh_statistics' - Declare rbox as DATA in qhull-exports.def and qhull_p-exports.def - In comments, use 'qh.zzz' to reference qhT fields - In qh_fprintf, use qhmem.ferr to report errors - qh_fprintf may be called for errors in qh_initstatistics and qh_meminit - qh_pointid returns qh_IDnone, qh_IDinterior, qh_IDunknown in place of -3, -2, -1 resp. - getid_() returns qh_IDunknown in place of -1 - After qh_meminit, qhmem.ferr is non-zero (stderr is the default) - Update qh_MEMalign in testqset.c to user.h (with realT and void*) - Split rboxT into a header file - Add rboxlib.h to libqhull_a.h - Rename PI to qh_PI and extend to 30 digits - Rename MAXdim to qh_MAXdim - Change spacing for type annotations '*' and '&' in C++ header files - Test for !rbox_output/cpp_object in qh_fprintf_rbox - Remove 'inline' annotation from explicit inline declarations - Column 25 formatting for iterators, etc. - Use '#//!\name' for section headers - QhullFacet.cpp: zinc_(Zdistio); - Clear qhT.ALLOWrestart in qh_errexit - Replace longjmp with qh_errexit_rbox in qh_rboxpoints - Add jmpExtra after rbox_errexit to protect against compiler errors - Add qh.ISqhullQh to indicate initialization by QhullQh() - Add library warnings to 'rbox D4', user_eg, user_eg2, user_eg3 - Add headers to q_eg, q_egtest, and q_test - Check that qh.NOerrexit is cleared before call to qh_initflags Qhull documentation - README.txt: Added references to qh-code.htm - README.txt: Added section 'Calling Qhull from C programs' - qh-code.htm: Moved Performance after C++ and C interface - qh-code.htm: Moved Cpp Questions to end of the C++ section - qh-code.htm: Fixed documentation for 'include' path. It should be include/libqhull - qconvex.htm: Fixed documentation for 'i'. It triangulates in 4-d and higher [ref] - Clarified qhalf space documentation for the interior point [J. Santos] - rbox.c: Version is same date as qh_version in global.c - gobal_r.c: Version includes a '.r' suffix to indicate 'reentrant' Qhull builds - Development moved to http://github.com/qhull/qhull git clone git@github.com:qhull/qhull.git - Exchanged make targets for testing. 'make test' is a quick test of qhull programs. 'make testall' is a thorough test - Added 'make help' and 'make test' to libqhull and libqhull_r Makefiles - CMakeLists.txt: Remove libqhull, libqhull_r, and libqhullcpp from include_directories - CMakeLists.txt: Add qhull_SHAREDR for qhull_r - CMakeLists.txt: Retain qhull_SHARED and qhull_SHAREDP (qh_QHpointer) - CMakeLists.txt: Move qhull_SHARED and qhull_SHAREDP (qh_QHpointer) to qhull_TARGETS_OLD Drop qhull_STATICP (use qhull_SHAREDP or qhull_STATIC) Set SOVERSION and VERSION for shared libraries - Move qhull_p-exports.def back to libqhull - Switched to mingw-w64-install for gcc - Improved prompts for 'make' - qhull-all.pro: Remove user_eg3.cpp from OTHER_FILES - libqhull.pro: Ordered object files by frequency of execution, as done before - Add the folder name to C++ includes and remove libqhullcpp from INCLUDEPATH - Changed CONFIG+=qtestlib to QT+=testlib - Changed Makefile to gcc -O3 (was -O2) - Changed libqhull/libqhull_r Makefiles to both produce rbox, qhull, ..., user_eg, and user_eg2 - Removed Debian 'config/...'. It was needed for Qhull 2012. libqhull_r (reentrant Qhull) - Replaced qh_qh with a parameter to each procedure [P. Klosterman] No more globally defined data structures in Qhull Simplified multithreading and C++ user interface All functions are reentrant (Qt: "A reentrant function can ... be called simultaneously from multiple threads, but only if each invocation uses its own data.") No more qh_QHpointer. See user_eg3 and qhulltest New libraries libqhull_r -- Shared library with reentrant sources (e.g., poly_r.h and poly_r.c which replace libqhull's poly.h and poly.c) libqhullstatic_r -- Static library with the same sources as libqhull_r libqhullcpp -- The C++ interface using libqhullstatic_r (further notes below) New executables testqset_r -- Test qset_r.c (the reentrant version of qset.c Source code changes for libqhull_r - Add qh_zero() to initialize and zero memory for qh_new_qhull - Remove qh_save_qhull(), qh_restore_qhull(), and qh.old_qhstat from global_r.c - Remove qh_freeqhull2() (global_r.c) - Remove qh_freestatistics() (stat_r.c) - Remove qh_compare_vertexpoint (qhT is not available, unused code) - Remove conditional code for __POWERPC__ from unix_r.c and rbox_r.c - Move qh_last_random into qh->last_random (random_r.c) - Rename sources files with a '_r' suffix. qhull_a.h becomes qhull_ra.h - Replace 'qh' macro with 'qh->' - Replace global qhT with parameter-0 - Add qhmemT to beginning of qhT. It may not be used standalone. - Add qhstatT to end of qhT - Remove qhull_inuse - Change qhmem.zzz to qh->qhmem.zzz - Replace qh_qhstat with qh->qhstat - Remove qh_freestatistics - Replace qh_last_random with qh->last_random - Replace rboxT with qh->rbox_errexit, rbox_isinteger, rbox_out_offset - Replace rbox.ferr/fout with qh->ferr/fout - No qh for qh_exit, qh_free, qh_malloc, qh_strtod, qh_strtol, qh_stddev - New qmake include files qhull-app-c_r.pri, qhull-app-shared_r.pri, qhull-libqhull-src_r.pri - Replace 'int' with 'countT' and 'COUNTmax' for large counts and identifiers - qhset converted to countT - Removed vertexT.dim -- No longer needed by cpp Removed MAX_vdim - Guarantee that qh->run_id!=0. Old code assumed that qh_RANDOMint was 31 bits Changes to libqhullcpp - Added QhullVertexSet.h to libqhullcpp.pro and libqhullpcpp.pro - QhullVertexSet: error if qhsettemp_defined at copy constructor/assignment (otherwise double free) - Enable QhullSet.operator=. Copy constructor and assignment only copies pointers - Changed QhullPoint.operator==() to sqrt(distanceEpsilon) - Added assignment of base class QhullPoints to PointCoordinates.operator= - Enable QhullPoints.operator= - Rename PointCoordinates.point_comment to describe_points - Add 'typename T' to definition of QhullSet::value() C++ interface - Reimplemented C++ interface on reentrant libqhull_r instead of libqhull - Prepend include files with libqhullcpp/ - Replaced UsingLibQhull with QhullQh and macro QH_TRY Removed UsingLibQhull.currentAngleEpsilon and related routines Removed UsingLibQhull_test.cpp Replaced globalDistanceEpsilon with QhullQh.distanceEpsilon Replaced globalAngleEpsilon with QhullQh.angleEpsilon Moved UsingQhullLib.checkQhullMemoryEmpty to QhullQh.checkAndFreeQhullMemory Replaced FACTORepsilon=10 with QhullQh.factor_epsilon=1.0 - To avoid -Wshadow for QhullQh*, use 'qqh' for parameters and 'qh()' for methods - Moved messaging from Qhull to QhullQh - Add check of RboxPoints* in qh_fprintf_rbox - Renamed Qhull.initializeQhull to Qhull.allocateQhullQh Added qh_freeqhull(!qh_ALL) as done by unix.c and other programs - Moved QhullPoints.extraCoordinatesCount into QhullPoints.cpp - Replaced section tags with '#//!\name ...' - Removed qhRunId from print() to ostream. - Removed print() to ostream. Use '<< qhullPoint' or '<< qhullPoint.print("message")' C++ interface for most classes - Remove qhRunId - Add QhullQh *qh_qh to all types Pointer comparisons of facetT,etc. do not test corresponding qh_qh Added to end of type for debugging information, unless wasteful alignment - Add QhullQh * to all constructors - All constructors may use Qhull & instead of QhullQh * - For inherited QhullQh types, change to 'protected' - Renamed 'o' to 'other' except where used extensively in iterators - Except for conditional code, merged the Conversion section into GetSet - Removed empty(). Use isEmpty() instead - Add operator= instead of keeping it private - print_message=0 not allowed. Use "" instead. - Rename isDefined() to isValid() to match Qt conventions C++ interface by class - Coordinates Removed empty(). Use isEmpty() instead Added append(dim, coordT*) Reformated the iterators Convert to countT - PointCoordinates Added constructors for Qhull or QhullQh* (provides access to QhullPoint.operator==) Removed PointCoordinates(int pointDimension) since PointCoordinates should have a comment. Also, it is ambiguous with PointCoordinates(QhullQh*) Renamed point_comment to describe_points Convert to countT - Qhull Remove qhull_run_i Remove qh_active Replace property feasiblePoint with field feasible_point and methods setFeasiblePoint/feasiblePoint Returns qh.feasible_point if defined Moved useOutputStream to QhullQh use_output_stream Renamed useOutputStream() to hasOutputStream() Replaced qhull_dimension with qh->input_dim //! Dimension of result (qh.hull_dim or one less for Delaunay/Voronoi) Removed global s_qhull_output= 0; Move qhull_status, qhull_message, error_stream, output_stream to QhullQh Renamed qhullQh() to qh() Added check of base address to allocateQhullQh(), Was not needed for qhullpcpp - QhullFacet Constructor requires Qhull or QhullQh* pointer Convert to countT Dropped implicit conversion from facetT Dropped runId Add print("message") to replace print() - QhullFacetList Constructor requires Qhull or QhullQh* pointer Convert to countT Dropped runId - QhullFacetSet Removed empty(). Use isEmpty() instead Constructor requires Qhull or QhullQh* pointer Convert to countT Dropped runId Add operator= Implement print("message") - QhullHyperplane Add hyperplaneAngle() method Rewrite operator==to use hyperplaneAngle() Reorganize fields to keep pointers aligned Except for default constructor requires Qhull or QhullQh* pointer Enable copy assignment Reorganized header - QhullLinkedList Add operator= Removed empty(). Use isEmpty() instead Convert to countT iterator(T) made iterator(const T &) const_iterator(T) made const_iterator(const T &) const_iterator(iterator) made const_iterator(const iterator &) - QhullPoint Add constructors for Qhull or QhullQh* pointer (for id() and operator==) Add defineAs(coordT*) Add getBaseT() and base_type for QhullSet Added checks for point_coordinates==0 Removed static QhullPoint::id(), use QhullPoint.id() instead distance() throws an error if dimension doesn't agree or if a point is undefined Convert to countT If !qh_qh, operator==() requires equal coordinates Use cout<

[R. Richter, S. Pasko] - Remove deprecated libqhull/qhull.h Use libqhull/libqhull.h instead. Avoids confusion with libqhullcpp/Qhull.h - Makefile: Add LIBDIR, INCDIR, and DESTDIR to install [L.H. de Mello] Separate MAN install from DOC install Create install directories Installs headers to include/libqhull, include/libqhullcpp, include/road - CMakeLists.txt: Add MAN_INSTALL_DIR for qhull.1 and rbox.1 man pages Add RoadTest.h to include/road for Qt users (road_HEADERS) - Renamed md5sum files to avoid two extensions - qh-get.htm: Add Readme links and 2009.1 note. - qh-optf.htm: Fix link - index.htm: Updated Google Scholar link - qhull-zip.sh: Improved error message. ------------ Qhull 2011.1 2011/04/17 6.2.0.1373 Changes to deliverables - qvoronoi: Deprecated 'Qt' and 'QJn'. Removed from documentation and prompts. These options produced duplicate Voronoi vertices for cospherical data. - Removed doskey from Qhull-go.bat. It is incompatible with Windows 7 - Added 'facets' argument to user_eg3.cpp - user_eg links with shared library - qhulltest.cpp: Add closing prompt. Changes to build system - Reorganized source directories - Moved executables to bin directory - Add CMake build for all targets (CMakeFiles.txt) [M. Moll assisted] - Add gcc build for all targets (Makefile) - Fixed location of qhull.man and rbox.man [M. Moll] - Add DevStudio builds for all targets (build/*.vcproj) - Added shared library (lib/qhull6.dll) Added qh_QHpointer_dllimport to work around problems with MSVC - Added static libraries with and without qh_QHpointer (lib/qhullstatic.lib) - Added eg/make-vcproj.sh to create vcproj/sln files from cmake and qmake - Document location of qh_QHpointer - Use shadow build directory - Made -fno-strict-aliasing conditional on gcc version - Added src/qhull-app-cpp.pri, src/qhull-app-c.pri, etc. for common settings - Add .gitignore with ignored files and directories. - Use .git/info/exclude for locally excluded files. - Fixed MBorland for new directory structure - cleanall (Makefile): Delete 'linked' programs due to libqhull_r and libqhull/Makefile Changes to documentation - qvoronoi.htm: Remove quotes from qvoronoi example - qhull-cpp.xml: Add naming conventions - index.htm: Add Google Scholar references - qh-optf.htm: Add note about order of 'Fn' matching 'Fv' order [Q. Pan] - Add patch for old builds in qh-get.htm - Added C++ compiling instructions to README.txt - Add instructions for fixing the DOS window - Changed DOS window to command window - Fixed html links - qh-get.htm: Dropped the Spanish mirror site. It was disabled. Changes to C code - mem.h: Define ptr_intT as 'long long' for Microsoft Windows _win64 builds. On Linux and Mac, 'long' is 64-bits on a 64-bit host - Added qh_QHpointer_dllimport to work around MSVC problem - qconvex.c,etc.: Define prototype for _isatty - Define MSG_QHULL_ERROR in user.h - Move MSG_FIXUP to 11000 and updated FIXUP QH11... Changes to test code - Add note to q_test than R1e-3 may error (qh-code.htm, Enhancements) - Add test for executables to q_eg, etc. - Fixed Qhull-go.bat. QHULL-GO invokes it with command.com, Changes to C++ interface - QhullFacet: Added isSimplicial, isTopOrient, isTriCoplanar, isUpperDelaunay - Added Qhull::defineVertexFacetNeighbors() for facetNeighbors of vertices. Automatically called for facet merging and Voronoi diagrams Do not print QhullVertex::facetNeighbors is !facetNeighborsDefined() - Assigned FIXUP identifiers - QhullError: Add copy constructor, assignment operator, and destructor - Add throw() specifiers to RoadError and QhullError - Renamed RoadError::defined() to RoadError::isDefined() - Add #error to Qhull.h if qh_QHpointer is not defined Changes to C++ code - Fixed bug reported by renangms. Vertex output throws error QH10034 and defineVertexNeighbors() does not exist. - Define QHULL_USES_QT for qt-qhull.cpp [renangms] - Reviewed all copy constructors and copy assignments. Updated comments. Defined Qhull copy constructor and copy assignment [G. Rivet-Sabourin] Disabled UsingQhullLib default constructor, copy construct, and copy assign - Merged changes from J. Obermayr in gitorious/jobermayrs-qhull:next - Fix strncat limit in rboxlib.c and global.c - Changes to CMakeLists.txt for openSUSE - Fixed additional uses of strncat - Fixed QhullFacet::PrintRidges to check hasNextRidge3d() - Removed gcc warnings for shadowing from code (src/qhull-warn.pri) - Removed semicolon after extern "C" {...} - Removed experimental QhullEvent/QhullLog - Use fabs() instead of abs() to avoid accidental conversions to int - Fixed type of vertex->neighbors in qh_printvoronoi [no effect on results] - Removed unnecessary if statement in qh_printvoronoi ============= == Qhull 2010.1 and 2009.1 ============= ------------ qhull 2010.1 2010/01/14 - Fixed quote for #include in qhull.h [U.Hergenhahn, K.Roland] - Add qt-qhull.cpp with Qt conditional code - Add libqhullp.proj - Add libqhull5 to Readme, Announce, download - Reviewed #pragma - Reviewed FIXUP and assigned QH tags - All projects compile with warnings enabled - Replaced 'up' glyphs with » - Moved cpp questions to qh-code.htm#questions-cpp - Moved suggestions to qh-code.htm#enhance - Moved documentation requests to qh-code.htm#enhance - Add md5sum file to distributions - Switched to DevStudio builds to avoid dependent libraries, 10% slower Removed user_eg3.exe and qhullcpp.dll from Windows build Fix qhull.sln and project files for qh_QHpointer - Add eg/qhull-zip.sh to build qhull distribution files ------------ qhull 2010.1 2010/01/10 - Test for NULL fp in qh_eachvoronoi [D. Szczerba] qhull 2010.1 2010/01/09 Changes to build and distribution - Use qh_QHpointer=0 for libqhull.a, qhull, rbox, etc. Use -Dqh_QHpointer for libqhullp.a, qhullcpp.dll, etc. qh_QHpointer [2010, gcc] 4% time 4% space, [2003, msvc] 8% time 2% space - Add config/ and project/debian/ for Autoconf build [R. Laboissiere] from debian branch in git and http://savannah.nongnu.org/cvs/?group=qhull - Add CMakeLists.txt [kwilliams] - Fix tabs in Makefile.txt [mschamschula] - Add -fno-strict-aliasing to Makefile for gcc 4.1, 4.2, and 4.3 qset segfault - Remove user_eg.exe and user_eg2.exe from Windows distribution - Order object files by frequency of execution for better locality. Changes to source - Remove ptr_intT from qh_matchvertices. It was int since the beginning. - user.h requires for CLOCKS_PER_SEC - Move ostream<

  ---------------------------------

   geom.c
   geometric routines of qhull

   see qh-geom.htm and geom.h

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull/geom.c#4 $$Change: 2953 $
   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $

   infrequent code goes into geom2.c
*/

#include "qhull_a.h"

/*---------------------------------

  qh_distplane( point, facet, dist )
    return distance from point to facet

  returns:
    dist
    if qh.RANDOMdist, joggles result

  notes:
    dist > 0 if point is above facet (i.e., outside)
    does not error (for qh_sortfacets, qh_outerinner)
    for nearly coplanar points, the returned values may be duplicates
      for example pairs of nearly incident points, rbox 175 C1,2e-13 t1538759579 | qhull d T4
      622 qh_distplane: e-014  # count of two or more duplicate values for unique calls
      258 qh_distplane: e-015
      38 qh_distplane: e-016
      40 qh_distplane: e-017
      6 qh_distplane: e-018
      5 qh_distplane: -e-018
      33 qh_distplane: -e-017
         3153 qh_distplane: -2.775557561562891e-017  # duplicated value for 3153 unique calls
      42 qh_distplane: -e-016
      307 qh_distplane: -e-015
      1271 qh_distplane: -e-014
      13 qh_distplane: -e-013

  see:
    qh_distnorm in geom2.c
    qh_distplane [geom.c], QhullFacet::distance, and QhullHyperplane::distance are copies
*/
void qh_distplane(pointT *point, facetT *facet, realT *dist) {
  coordT *normal= facet->normal, *coordp, randr;
  int k;

  switch (qh hull_dim){
  case 2:
    *dist= facet->offset + point[0] * normal[0] + point[1] * normal[1];
    break;
  case 3:
    *dist= facet->offset + point[0] * normal[0] + point[1] * normal[1] + point[2] * normal[2];
    break;
  case 4:
    *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3];
    break;
  case 5:
    *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4];
    break;
  case 6:
    *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5];
    break;
  case 7:
    *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6];
    break;
  case 8:
    *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6]+point[7]*normal[7];
    break;
  default:
    *dist= facet->offset;
    coordp= point;
    for (k=qh hull_dim; k--; )
      *dist += *coordp++ * *normal++;
    break;
  }
  zzinc_(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;
  }
#ifndef qh_NOtrace
  if (qh IStracing >= 4) {
    qh_fprintf(qh ferr, 8001, "qh_distplane: ");
    qh_fprintf(qh ferr, 8002, qh_REAL_1, *dist);
    qh_fprintf(qh ferr, 8003, "from p%d to f%d\n", qh_pointid(point), facet->id);
  }
#endif
  return;
} /* distplane */


/*---------------------------------

  qh_findbest( point, startfacet, bestoutside, qh_ISnewfacets, qh_NOupper, dist, isoutside, numpart )
    find facet that is furthest below a point
    for upperDelaunay facets
      returns facet only if !qh_NOupper and clearly above

  input:
    starts search at 'startfacet' (can not be flipped)
    if !bestoutside(qh_ALL), stops at qh.MINoutside

  returns:
    best facet (reports error if NULL)
    early out if isoutside defined and bestdist > qh.MINoutside
    dist is distance to facet
    isoutside is true if point is outside of facet
    numpart counts the number of distance tests

  see also:
    qh_findbestnew()

  notes:
    If merging (testhorizon), searches horizon facets of coplanar best facets because
    after qh_distplane, this and qh_partitionpoint are the most expensive in 3-d
      avoid calls to distplane, function calls, and real number operations.
    caller traces result
    Optimized for outside points.   Tried recording a search set for qh_findhorizon.
    Made code more complicated.

  when called by qh_partitionvisible():
    indicated by qh_ISnewfacets
    qh.newfacet_list is list of simplicial, new facets
    qh_findbestnew set if qh_sharpnewfacets returns True (to use qh_findbestnew)
    qh.bestfacet_notsharp set if qh_sharpnewfacets returns False

  when called by qh_findfacet(), qh_partitionpoint(), qh_partitioncoplanar(),
                 qh_check_bestdist(), qh_addpoint()
    indicated by !qh_ISnewfacets
    returns best facet in neighborhood of given facet
      this is best facet overall if dist >= -qh.MAXcoplanar
        or hull has at least a "spherical" curvature

  design:
    initialize and test for early exit
    repeat while there are better facets
      for each neighbor of facet
        exit if outside facet found
        test for better facet
    if point is inside and partitioning
      test for new facets with a "sharp" intersection
      if so, future calls go to qh_findbestnew()
    test horizon facets
*/
facetT *qh_findbest(pointT *point, facetT *startfacet,
                     boolT bestoutside, boolT isnewfacets, boolT noupper,
                     realT *dist, boolT *isoutside, int *numpart) {
  realT bestdist= -REALmax/2 /* avoid underflow */;
  facetT *facet, *neighbor, **neighborp;
  facetT *bestfacet= NULL, *lastfacet= NULL;
  int oldtrace= qh IStracing;
  unsigned int visitid= ++qh visit_id;
  int numpartnew=0;
  boolT testhorizon= True; /* needed if precise, e.g., rbox c D6 | qhull Q0 Tv */

  zinc_(Zfindbest);
#ifndef qh_NOtrace
  if (qh IStracing >= 4 || (qh TRACElevel && qh TRACEpoint >= 0 && qh TRACEpoint == qh_pointid(point))) {
    if (qh TRACElevel > qh IStracing)
      qh IStracing= qh TRACElevel;
    qh_fprintf(qh ferr, 8004, "qh_findbest: point p%d starting at f%d isnewfacets? %d, unless %d exit if > %2.2g,",
             qh_pointid(point), startfacet->id, isnewfacets, bestoutside, qh MINoutside);
    qh_fprintf(qh ferr, 8005, " testhorizon? %d, noupper? %d,", testhorizon, noupper);
    qh_fprintf(qh ferr, 8006, " Last qh_addpoint p%d,", qh furthest_id);
    qh_fprintf(qh ferr, 8007, " Last merge #%d, max_outside %2.2g\n", zzval_(Ztotmerge), qh max_outside);
  }
#endif
  if (isoutside)
    *isoutside= True;
  if (!startfacet->flipped) {  /* test startfacet before testing its neighbors */
    *numpart= 1;
    qh_distplane(point, startfacet, dist);  /* this code is duplicated below */
    if (!bestoutside && *dist >= qh MINoutside
    && (!startfacet->upperdelaunay || !noupper)) {
      bestfacet= startfacet;
      goto LABELreturn_best;
    }
    bestdist= *dist;
    if (!startfacet->upperdelaunay) {
      bestfacet= startfacet;
    }
  }else
    *numpart= 0;
  startfacet->visitid= visitid;
  facet= startfacet;
  while (facet) {
    trace4((qh ferr, 4001, "qh_findbest: neighbors of f%d, bestdist %2.2g f%d\n",
                facet->id, bestdist, getid_(bestfacet)));
    lastfacet= facet;
    FOREACHneighbor_(facet) {
      if (!neighbor->newfacet && isnewfacets)
        continue;
      if (neighbor->visitid == visitid)
        continue;
      neighbor->visitid= visitid;
      if (!neighbor->flipped) {  /* code duplicated above */
        (*numpart)++;
        qh_distplane(point, neighbor, dist);
        if (*dist > bestdist) {
          if (!bestoutside && *dist >= qh MINoutside
          && (!neighbor->upperdelaunay || !noupper)) {
            bestfacet= neighbor;
            goto LABELreturn_best;
          }
          if (!neighbor->upperdelaunay) {
            bestfacet= neighbor;
            bestdist= *dist;
            break; /* switch to neighbor */
          }else if (!bestfacet) {
            bestdist= *dist;
            break; /* switch to neighbor */
          }
        } /* end of *dist>bestdist */
      } /* end of !flipped */
    } /* end of FOREACHneighbor */
    facet= neighbor;  /* non-NULL only if *dist>bestdist */
  } /* end of while facet (directed search) */
  if (isnewfacets) {
    if (!bestfacet) { /* startfacet is upperdelaunay (or flipped) w/o !flipped newfacet neighbors */
      bestdist= -REALmax/2;
      bestfacet= qh_findbestnew(point, qh newfacet_list, &bestdist, bestoutside, isoutside, &numpartnew);
      testhorizon= False; /* qh_findbestnew calls qh_findbesthorizon */
    }else if (!qh findbest_notsharp && bestdist < -qh DISTround) {
      if (qh_sharpnewfacets()) {
        /* seldom used, qh_findbestnew will retest all facets */
        zinc_(Zfindnewsharp);
        bestfacet= qh_findbestnew(point, bestfacet, &bestdist, bestoutside, isoutside, &numpartnew);
        testhorizon= False; /* qh_findbestnew calls qh_findbesthorizon */
        qh findbestnew= True;
      }else
        qh findbest_notsharp= True;
    }
  }
  if (!bestfacet)
    bestfacet= qh_findbestlower(lastfacet, point, &bestdist, numpart); /* lastfacet is non-NULL because startfacet is non-NULL */
  if (testhorizon) /* qh_findbestnew not called */
    bestfacet= qh_findbesthorizon(!qh_IScheckmax, point, bestfacet, noupper, &bestdist, &numpartnew);
  *dist= bestdist;
  if (isoutside && bestdist < qh MINoutside)
    *isoutside= False;
LABELreturn_best:
  zadd_(Zfindbesttot, *numpart);
  zmax_(Zfindbestmax, *numpart);
  (*numpart) += numpartnew;
  qh IStracing= oldtrace;
  return bestfacet;
}  /* findbest */


/*---------------------------------

  qh_findbesthorizon( qh_IScheckmax, point, startfacet, qh_NOupper, &bestdist, &numpart )
    search coplanar and better horizon facets from startfacet/bestdist
    ischeckmax turns off statistics and minsearch update
    all arguments must be initialized, including *bestdist and *numpart
    qh.coplanarfacetset used to maintain current search set, reset whenever best facet is substantially better
  returns(ischeckmax):
    best facet
    updates f.maxoutside for neighbors of searched facets (if qh_MAXoutside)
  returns(!ischeckmax):
    best facet that is not upperdelaunay or newfacet (qh.first_newfacet)
    allows upperdelaunay that is clearly outside
  returns:
    bestdist is distance to bestfacet
    numpart -- updates number of distance tests

  notes:
    called by qh_findbest if point is not outside a facet (directed search)
    called by qh_findbestnew if point is not outside a new facet
    called by qh_check_maxout for each point in hull
    called by qh_check_bestdist for each point in hull (rarely used)

    no early out -- use qh_findbest() or qh_findbestnew()
    Searches coplanar or better horizon facets

  when called by qh_check_maxout() (qh_IScheckmax)
    startfacet must be closest to the point
      Otherwise, if point is beyond and below startfacet, startfacet may be a local minimum
      even though other facets are below the point.
    updates facet->maxoutside for good, visited facets
    may return NULL

    searchdist is qh.max_outside + 2 * DISTround
      + max( MINvisible('Vn'), MAXcoplanar('Un'));
    This setting is a guess.  It must be at least max_outside + 2*DISTround
    because a facet may have a geometric neighbor across a vertex

  design:
    for each horizon facet of coplanar best facets
      continue if clearly inside
      unless upperdelaunay or clearly outside
         update best facet
*/
facetT *qh_findbesthorizon(boolT ischeckmax, pointT* point, facetT *startfacet, boolT noupper, realT *bestdist, int *numpart) {
  facetT *bestfacet= startfacet;
  realT dist;
  facetT *neighbor, **neighborp, *facet;
  facetT *nextfacet= NULL; /* optimize last facet of coplanarfacetset */
  int numpartinit= *numpart, coplanarfacetset_size, numcoplanar= 0, numfacet= 0;
  unsigned int visitid= ++qh visit_id;
  boolT newbest= False; /* for tracing */
  realT minsearch, searchdist;  /* skip facets that are too far from point */
  boolT is_5x_minsearch;

  if (!ischeckmax) {
    zinc_(Zfindhorizon);
  }else {
#if qh_MAXoutside
    if ((!qh ONLYgood || startfacet->good) && *bestdist > startfacet->maxoutside)
      startfacet->maxoutside= *bestdist;
#endif
  }
  searchdist= qh_SEARCHdist; /* an expression, a multiple of qh.max_outside and precision constants */
  minsearch= *bestdist - searchdist;
  if (ischeckmax) {
    /* Always check coplanar facets.  Needed for RBOX 1000 s Z1 G1e-13 t996564279 | QHULL Tv */
    minimize_(minsearch, -searchdist);
  }
  coplanarfacetset_size= 0;
  startfacet->visitid= visitid;
  facet= startfacet;
  while (True) {
    numfacet++;
    is_5x_minsearch= (ischeckmax && facet->nummerge > 10 && qh_setsize(facet->neighbors) > 100);  /* QH11033 FIX: qh_findbesthorizon: many tests for facets with many merges and neighbors.  Can hide coplanar facets, e.g., 'rbox 1000 s Z1 G1e-13' with 4400+ neighbors */
    trace4((qh ferr, 4002, "qh_findbesthorizon: test neighbors of f%d bestdist %2.2g f%d ischeckmax? %d noupper? %d minsearch %2.2g is_5x? %d searchdist %2.2g\n",
                facet->id, *bestdist, getid_(bestfacet), ischeckmax, noupper,
                minsearch, is_5x_minsearch, searchdist));
    FOREACHneighbor_(facet) {
      if (neighbor->visitid == visitid)
        continue;
      neighbor->visitid= visitid;
      if (!neighbor->flipped) {  /* neighbors of flipped facets always searched via nextfacet */
        qh_distplane(point, neighbor, &dist); /* duplicate qh_distpane for new facets, they may be coplanar */
        (*numpart)++;
        if (dist > *bestdist) {
          if (!neighbor->upperdelaunay || ischeckmax || (!noupper && dist >= qh MINoutside)) {
            if (!ischeckmax) {
              minsearch= dist - searchdist;
              if (dist > *bestdist + searchdist) {
                zinc_(Zfindjump);  /* everything in qh.coplanarfacetset at least searchdist below */
                coplanarfacetset_size= 0;
              }
            }
            bestfacet= neighbor;
            *bestdist= dist;
            newbest= True;
          }
        }else if (is_5x_minsearch) {
          if (dist < 5 * minsearch)
            continue; /* skip this neighbor, do not set nextfacet.  dist is negative */
        }else if (dist < minsearch)
          continue;  /* skip this neighbor, do not set nextfacet.  If ischeckmax, dist can't be positive */
#if qh_MAXoutside
        if (ischeckmax && dist > neighbor->maxoutside)
          neighbor->maxoutside= dist;
#endif
      } /* end of !flipped, need to search neighbor */
      if (nextfacet) {
        numcoplanar++;
        if (!coplanarfacetset_size++) {
          SETfirst_(qh coplanarfacetset)= nextfacet;
          SETtruncate_(qh coplanarfacetset, 1);
        }else
          qh_setappend(&qh coplanarfacetset, nextfacet); /* Was needed for RBOX 1000 s W1e-13 P0 t996547055 | QHULL d Qbb Qc Tv
                                                 and RBOX 1000 s Z1 G1e-13 t996564279 | qhull Tv  */
      }
      nextfacet= neighbor;
    } /* end of EACHneighbor */
    facet= nextfacet;
    if (facet)
      nextfacet= NULL;
    else if (!coplanarfacetset_size)
      break;
    else if (!--coplanarfacetset_size) {
      facet= SETfirstt_(qh coplanarfacetset, facetT);
      SETtruncate_(qh coplanarfacetset, 0);
    }else
      facet= (facetT *)qh_setdellast(qh coplanarfacetset);
  } /* while True, i.e., "for each facet in qh.coplanarfacetset" */
  if (!ischeckmax) {
    zadd_(Zfindhorizontot, *numpart - numpartinit);
    zmax_(Zfindhorizonmax, *numpart - numpartinit);
    if (newbest)
      zinc_(Znewbesthorizon);
  }
  trace4((qh ferr, 4003, "qh_findbesthorizon: p%d, newbest? %d, bestfacet f%d, bestdist %2.2g, numfacet %d, coplanarfacets %d, numdist %d\n",
    qh_pointid(point), newbest, getid_(bestfacet), *bestdist, numfacet, numcoplanar, *numpart - numpartinit));
  return bestfacet;
}  /* findbesthorizon */

/*---------------------------------

  qh_findbestnew( point, startfacet, dist, isoutside, numpart )
    find best newfacet for point
    searches all of qh.newfacet_list starting at startfacet
    searches horizon facets of coplanar best newfacets
    searches all facets if startfacet == qh.facet_list
  returns:
    best new or horizon facet that is not upperdelaunay
    early out if isoutside and not 'Qf'
    dist is distance to facet
    isoutside is true if point is outside of facet
    numpart is number of distance tests

  notes:
    Always used for merged new facets (see qh_USEfindbestnew)
    Avoids upperdelaunay facet unless (isoutside and outside)

    Uses qh.visit_id, qh.coplanarfacetset.
    If share visit_id with qh_findbest, coplanarfacetset is incorrect.

    If merging (testhorizon), searches horizon facets of coplanar best facets because
    a point maybe coplanar to the bestfacet, below its horizon facet,
    and above a horizon facet of a coplanar newfacet.  For example,
      rbox 1000 s Z1 G1e-13 | qhull
      rbox 1000 s W1e-13 P0 t992110337 | QHULL d Qbb Qc

    qh_findbestnew() used if
       qh_sharpnewfacets -- newfacets contains a sharp angle
       if many merges, qh_premerge found a merge, or 'Qf' (qh.findbestnew)

  see also:
    qh_partitionall() and qh_findbest()

  design:
    for each new facet starting from startfacet
      test distance from point to facet
      return facet if clearly outside
      unless upperdelaunay and a lowerdelaunay exists
         update best facet
    test horizon facets
*/
facetT *qh_findbestnew(pointT *point, facetT *startfacet,
           realT *dist, boolT bestoutside, boolT *isoutside, int *numpart) {
  realT bestdist= -REALmax/2;
  facetT *bestfacet= NULL, *facet;
  int oldtrace= qh IStracing, i;
  unsigned int visitid= ++qh visit_id;
  realT distoutside= 0.0;
  boolT isdistoutside; /* True if distoutside is defined */
  boolT testhorizon= True; /* needed if precise, e.g., rbox c D6 | qhull Q0 Tv */

  if (!startfacet || !startfacet->next) {
    if (qh MERGING) {
      qh_fprintf(qh ferr, 6001, "qhull topology error (qh_findbestnew): merging has formed and deleted a cone of new facets.  Can not continue.\n");
      qh_errexit(qh_ERRtopology, NULL, NULL);
    }else {
      qh_fprintf(qh ferr, 6002, "qhull internal error (qh_findbestnew): no new facets for point p%d\n",
              qh furthest_id);
      qh_errexit(qh_ERRqhull, NULL, NULL);
    }
  }
  zinc_(Zfindnew);
  if (qh BESToutside || bestoutside)
    isdistoutside= False;
  else {
    isdistoutside= True;
    distoutside= qh_DISToutside; /* multiple of qh.MINoutside & qh.max_outside, see user.h */
  }
  if (isoutside)
    *isoutside= True;
  *numpart= 0;
#ifndef qh_NOtrace
  if (qh IStracing >= 4 || (qh TRACElevel && qh TRACEpoint >= 0 && qh TRACEpoint == qh_pointid(point))) {
    if (qh TRACElevel > qh IStracing)
      qh IStracing= qh TRACElevel;
    qh_fprintf(qh ferr, 8008, "qh_findbestnew: point p%d facet f%d. Stop? %d if dist > %2.2g,",
             qh_pointid(point), startfacet->id, isdistoutside, distoutside);
    qh_fprintf(qh ferr, 8009, " Last qh_addpoint p%d, qh.visit_id %d, vertex_visit %d,",  qh furthest_id, visitid, qh vertex_visit);
    qh_fprintf(qh ferr, 8010, " Last merge #%d\n", zzval_(Ztotmerge));
  }
#endif
  /* 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) /* testhorizon is always True.  Keep the same code as qh_findbest */
    bestfacet= qh_findbesthorizon(!qh_IScheckmax, point, bestfacet ? bestfacet : startfacet,
                                        !qh_NOupper, &bestdist, numpart);
  *dist= bestdist;
  if (isoutside && *dist < qh MINoutside)
    *isoutside= False;
LABELreturn_bestnew:
  zadd_(Zfindnewtot, *numpart);
  zmax_(Zfindnewmax, *numpart);
  trace4((qh ferr, 4004, "qh_findbestnew: bestfacet f%d bestdist %2.2g for p%d f%d bestoutside? %d \n",
    getid_(bestfacet), *dist, qh_pointid(point), startfacet->id, bestoutside));
  qh IStracing= oldtrace;
  return bestfacet;
}  /* findbestnew */

/* ============ hyperplane functions -- keep code together [?] ============ */

/*---------------------------------

  qh_backnormal( rows, numrow, numcol, sign, normal, nearzero )
    given an upper-triangular rows array and a sign,
    solve for normal equation x using back substitution over rows U

  returns:
     normal= x

     if will not be able to divzero() when normalized(qh.MINdenom_2 and qh.MINdenom_1_2),
       if fails on last row
         this means that the hyperplane intersects [0,..,1]
         sets last coordinate of normal to sign
       otherwise
         sets tail of normal to [...,sign,0,...], i.e., solves for b= [0...0]
         sets nearzero

  notes:
     assumes numrow == numcol-1

     see Golub & van Loan, 1983, Eq. 4.4-9 for "Gaussian elimination with complete pivoting"

     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) {
    *nearzero= True;
    trace4((qh ferr, 4005, "qh_backnormal: zero diagonal at column %d.\n", i));
    zzinc_(Zback0);
    qh_joggle_restart("zero diagonal on back substitution");
  }
} /* backnormal */

/*---------------------------------

  qh_gausselim( rows, numrow, numcol, sign )
    Gaussian elimination with partial pivoting

  returns:
    rows is upper triangular (includes row exchanges)
    flips sign for each row exchange
    sets nearzero if pivot[k] < qh.NEARzero[k], else clears it

  notes:
    if nearzero, the determinant's sign may be incorrect.
    assumes numrow <= numcol

  design:
    for each row
      determine pivot and exchange rows if necessary
      test for near zero
      perform gaussian elimination step
*/
void qh_gausselim(realT **rows, int numrow, int numcol, boolT *sign, boolT *nearzero) {
  realT *ai, *ak, *rowp, *pivotrow;
  realT n, pivot, pivot_abs= 0.0, temp;
  int i, j, k, pivoti, flip=0;

  *nearzero= False;
  for (k=0; k < numrow; k++) {
    pivot_abs= fabs_((rows[k])[k]);
    pivoti= k;
    for (i=k+1; i < numrow; i++) {
      if ((temp= fabs_((rows[i])[k])) > pivot_abs) {
        pivot_abs= temp;
        pivoti= i;
      }
    }
    if (pivoti != k) {
      rowp= rows[pivoti];
      rows[pivoti]= rows[k];
      rows[k]= rowp;
      *sign ^= 1;
      flip ^= 1;
    }
    if (pivot_abs <= qh NEARzero[k]) {
      *nearzero= True;
      if (pivot_abs == 0.0) {   /* remainder of column == 0 */
#ifndef qh_NOtrace
        if (qh IStracing >= 4) {
          qh_fprintf(qh ferr, 8011, "qh_gausselim: 0 pivot at column %d. (%2.2g < %2.2g)\n", k, pivot_abs, qh DISTround);
          qh_printmatrix(qh ferr, "Matrix:", rows, numrow, numcol);
        }
#endif
        zzinc_(Zgauss0);
        qh_joggle_restart("zero pivot for Gaussian elimination");
        goto LABELnextcol;
      }
    }
    pivotrow= rows[k] + k;
    pivot= *pivotrow++;  /* signed value of pivot, and remainder of row */
    for (i=k+1; i < numrow; i++) {
      ai= rows[i] + k;
      ak= pivotrow;
      n= (*ai++)/pivot;   /* divzero() not needed since |pivot| >= |*ai| */
      for (j= numcol - (k+1); j--; )
        *ai++ -= n * *ak++;
    }
  LABELnextcol:
    ;
  }
  wmin_(Wmindenom, pivot_abs);  /* last pivot element */
  if (qh IStracing >= 5)
    qh_printmatrix(qh ferr, "qh_gausselem: result", rows, numrow, numcol);
} /* gausselim */


/*---------------------------------

  qh_getangle( vect1, vect2 )
    returns the dot product of two vectors
    if qh.RANDOMdist, joggles result

  notes:
    the angle may be > 1.0 or < -1.0 because of roundoff errors

*/
realT qh_getangle(pointT *vect1, pointT *vect2) {
  realT angle= 0, randr;
  int k;

  for (k=qh hull_dim; k--; )
    angle += *vect1++ * *vect2++;
  if (qh RANDOMdist) {
    randr= qh_RANDOMint;
    angle += (2.0 * randr / qh_RANDOMmax - 1.0) *
      qh RANDOMfactor;
  }
  trace4((qh ferr, 4006, "qh_getangle: %4.4g\n", angle));
  return(angle);
} /* getangle */


/*---------------------------------

  qh_getcenter( vertices )
    returns arithmetic center of a set of vertices as a new point

  notes:
    allocates point array for center
*/
pointT *qh_getcenter(setT *vertices) {
  int k;
  pointT *center, *coord;
  vertexT *vertex, **vertexp;
  int count= qh_setsize(vertices);

  if (count < 2) {
    qh_fprintf(qh ferr, 6003, "qhull internal error (qh_getcenter): not defined for %d points\n", count);
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  center= (pointT *)qh_memalloc(qh normal_size);
  for (k=0; k < qh hull_dim; k++) {
    coord= center+k;
    *coord= 0.0;
    FOREACHvertex_(vertices)
      *coord += vertex->point[k];
    *coord /= count;  /* count>=2 by QH6003 */
  }
  return(center);
} /* getcenter */


/*---------------------------------

  qh_getcentrum( facet )
    returns the centrum for a facet as a new point

  notes:
    allocates the centrum
*/
pointT *qh_getcentrum(facetT *facet) {
  realT dist;
  pointT *centrum, *point;

  point= qh_getcenter(facet->vertices);
  zzinc_(Zcentrumtests);
  qh_distplane(point, facet, &dist);
  centrum= qh_projectpoint(point, facet, dist);
  qh_memfree(point, qh normal_size);
  trace4((qh ferr, 4007, "qh_getcentrum: for f%d, %d vertices dist= %2.2g\n",
          facet->id, qh_setsize(facet->vertices), dist));
  return centrum;
} /* getcentrum */


/*---------------------------------

  qh_getdistance( facet, neighbor, mindist, maxdist )
    returns the min and max distance to neighbor of non-neighbor vertices in facet

  returns:
    the max absolute value

  design:
    for each vertex of facet that is not in neighbor
      test the distance from vertex to neighbor
*/
coordT qh_getdistance(facetT *facet, facetT *neighbor, coordT *mindist, coordT *maxdist) {
  vertexT *vertex, **vertexp;
  coordT dist, maxd, mind;

  FOREACHvertex_(facet->vertices)
    vertex->seen= False;
  FOREACHvertex_(neighbor->vertices)
    vertex->seen= True;
  mind= 0.0;
  maxd= 0.0;
  FOREACHvertex_(facet->vertices) {
    if (!vertex->seen) {
      zzinc_(Zbestdist);
      qh_distplane(vertex->point, neighbor, &dist);
      if (dist < mind)
        mind= dist;
      else if (dist > maxd)
        maxd= dist;
    }
  }
  *mindist= mind;
  *maxdist= maxd;
  mind= -mind;
  if (maxd > mind)
    return maxd;
  else
    return mind;
} /* getdistance */


/*---------------------------------

  qh_normalize( normal, dim, toporient )
    normalize a vector and report if too small
    does not use min norm

  see:
    qh_normalize2
*/
void qh_normalize(coordT *normal, int dim, boolT toporient) {
  qh_normalize2(normal, dim, toporient, NULL, NULL);
} /* normalize */

/*---------------------------------

  qh_normalize2( normal, dim, toporient, minnorm, ismin )
    normalize a vector and report if too small
    qh.MINdenom/MINdenom1 are the upper limits for divide overflow

  returns:
    normalized vector
    flips sign if !toporient
    if minnorm non-NULL,
      sets ismin if normal < minnorm

  notes:
    if zero norm
       sets all elements to sqrt(1.0/dim)
    if divide by zero (divzero())
       sets largest element to   +/-1
       bumps Znearlysingular

  design:
    computes norm
    test for minnorm
    if not near zero
      normalizes normal
    else if zero norm
      sets normal to standard value
    else
      uses qh_divzero to normalize
      if nearzero
        sets norm to direction of maximum value
*/
void qh_normalize2(coordT *normal, int dim, boolT toporient,
            realT *minnorm, boolT *ismin) {
  int k;
  realT *colp, *maxp, norm= 0, temp, *norm1, *norm2, *norm3;
  boolT zerodiv;

  norm1= normal+1;
  norm2= normal+2;
  norm3= normal+3;
  if (dim == 2)
    norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1));
  else if (dim == 3)
    norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2));
  else if (dim == 4) {
    norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2)
               + (*norm3)*(*norm3));
  }else if (dim > 4) {
    norm= (*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2)
               + (*norm3)*(*norm3);
    for (k=dim-4, colp=normal+4; k--; colp++)
      norm += (*colp) * (*colp);
    norm= sqrt(norm);
  }
  if (minnorm) {
    if (norm < *minnorm)
      *ismin= True;
    else
      *ismin= False;
  }
  wmin_(Wmindenom, norm);
  if (norm > qh MINdenom) {
    if (!toporient)
      norm= -norm;
    *normal /= norm;
    *norm1 /= norm;
    if (dim == 2)
      ; /* all done */
    else if (dim == 3)
      *norm2 /= norm;
    else if (dim == 4) {
      *norm2 /= norm;
      *norm3 /= norm;
    }else if (dim >4) {
      *norm2 /= norm;
      *norm3 /= norm;
      for (k=dim-4, colp=normal+4; k--; )
        *colp++ /= norm;
    }
  }else if (norm == 0.0) {
    temp= sqrt(1.0/dim);
    for (k=dim, colp=normal; k--; )
      *colp++= temp;
  }else {
    if (!toporient)
      norm= -norm;
    for (k=dim, colp=normal; k--; colp++) { /* k used below */
      temp= qh_divzero(*colp, norm, qh MINdenom_1, &zerodiv);
      if (!zerodiv)
        *colp= temp;
      else {
        maxp= qh_maxabsval(normal, dim);
        temp= ((*maxp * norm >= 0.0) ? 1.0 : -1.0);
        for (k=dim, colp=normal; k--; colp++)
          *colp= 0.0;
        *maxp= temp;
        zzinc_(Znearlysingular);
        /* qh_joggle_restart ignored for Znearlysingular, normal part of qh_sethyperplane_gauss */
        trace0((qh ferr, 1, "qh_normalize: norm=%2.2g too small during p%d\n",
               norm, qh furthest_id));
        return;
      }
    }
  }
} /* normalize */


/*---------------------------------

  qh_projectpoint( point, facet, dist )
    project point onto a facet by dist

  returns:
    returns a new point

  notes:
    if dist= distplane(point,facet)
      this projects point to hyperplane
    assumes qh_memfree_() is valid for normal_size
*/
pointT *qh_projectpoint(pointT *point, facetT *facet, realT dist) {
  pointT *newpoint, *np, *normal;
  int normsize= qh normal_size;
  int k;
  void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */

  qh_memalloc_(normsize, freelistp, newpoint, pointT);
  np= newpoint;
  normal= facet->normal;
  for (k=qh hull_dim; k--; )
    *(np++)= *point++ - dist * *normal++;
  return(newpoint);
} /* projectpoint */


/*---------------------------------

  qh_setfacetplane( facet )
    sets the hyperplane for a facet
    if qh.RANDOMdist, joggles hyperplane

  notes:
    uses global buffers qh.gm_matrix and qh.gm_row
    overwrites facet->normal if already defined
    updates Wnewvertex if PRINTstatistics
    sets facet->upperdelaunay if upper envelope of Delaunay triangulation

  design:
    copy vertex coordinates to qh.gm_matrix/gm_row
    compute determinate
    if nearzero
      recompute determinate with gaussian elimination
      if nearzero
        force outside orientation by testing interior point
*/
void qh_setfacetplane(facetT *facet) {
  pointT *point;
  vertexT *vertex, **vertexp;
  int normsize= qh normal_size;
  int k,i, oldtrace= 0;
  realT dist;
  void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */
  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);
#ifndef qh_NOtrace
  if (facet == qh tracefacet) {
    oldtrace= qh IStracing;
    qh IStracing= 5;
    qh_fprintf(qh ferr, 8012, "qh_setfacetplane: facet f%d created.\n", facet->id);
    qh_fprintf(qh ferr, 8013, "  Last point added to hull was p%d.", qh furthest_id);
    if (zzval_(Ztotmerge))
      qh_fprintf(qh ferr, 8014, "  Last merge was #%d.", zzval_(Ztotmerge));
    qh_fprintf(qh ferr, 8015, "\n\nCurrent summary is:\n");
      qh_printsummary(qh ferr);
  }
#endif
  if (qh hull_dim <= 4) {
    i= 0;
    if (qh RANDOMdist) {
      gmcoord= qh gm_matrix;
      FOREACHvertex_(facet->vertices) {
        qh gm_row[i++]= gmcoord;
        coord= vertex->point;
        for (k=qh hull_dim; k--; )
          *(gmcoord++)= *coord++ * qh_randomfactor(qh RANDOMa, qh RANDOMb);
      }
    }else {
      FOREACHvertex_(facet->vertices)
       qh gm_row[i++]= vertex->point;
    }
    qh_sethyperplane_det(qh hull_dim, qh gm_row, point0, facet->toporient,
                facet->normal, &facet->offset, &nearzero);
  }
  if (qh hull_dim > 4 || nearzero) {
    i= 0;
    gmcoord= qh gm_matrix;
    FOREACHvertex_(facet->vertices) {
      if (vertex->point != point0) {
        qh gm_row[i++]= gmcoord;
        coord= vertex->point;
        point= point0;
        for (k=qh hull_dim; k--; )
          *(gmcoord++)= *coord++ - *point++;
      }
    }
    qh gm_row[i]= gmcoord;  /* for areasimplex */
    if (qh RANDOMdist) {
      gmcoord= qh gm_matrix;
      for (i=qh hull_dim-1; i--; ) {
        for (k=qh hull_dim; k--; )
          *(gmcoord++) *= qh_randomfactor(qh RANDOMa, qh RANDOMb);
      }
    }
    qh_sethyperplane_gauss(qh hull_dim, qh gm_row, point0, facet->toporient,
                facet->normal, &facet->offset, &nearzero);
    if (nearzero) {
      if (qh_orientoutside(facet)) {
        trace0((qh ferr, 2, "qh_setfacetplane: flipped orientation due to nearzero gauss and interior_point test.  During p%d\n", qh furthest_id));
      /* this is part of using Gaussian Elimination.  For example in 5-d
           1 1 1 1 0
           1 1 1 1 1
           0 0 0 1 0
           0 1 0 0 0
           1 0 0 0 0
           norm= 0.38 0.38 -0.76 0.38 0
         has a determinate of 1, but g.e. after subtracting pt. 0 has
         0's in the diagonal, even with full pivoting.  It does work
         if you subtract pt. 4 instead. */
      }
    }
  }
  facet->upperdelaunay= False;
  if (qh DELAUNAY) {
    if (qh UPPERdelaunay) {     /* matches qh_triangulate_facet and qh.lower_threshold in qh_initbuild */
      if (facet->normal[qh hull_dim -1] >= qh ANGLEround * qh_ZEROdelaunay)
        facet->upperdelaunay= True;
    }else {
      if (facet->normal[qh hull_dim -1] > -qh ANGLEround * qh_ZEROdelaunay)
        facet->upperdelaunay= True;
    }
  }
  if (qh PRINTstatistics || qh IStracing || qh TRACElevel || qh JOGGLEmax < REALmax) {
    qh old_randomdist= qh RANDOMdist;
    qh RANDOMdist= False;
    FOREACHvertex_(facet->vertices) {
      if (vertex->point != point0) {
        boolT istrace= False;
        zinc_(Zdiststat);
        qh_distplane(vertex->point, facet, &dist);
        dist= fabs_(dist);
        zinc_(Znewvertex);
        wadd_(Wnewvertex, dist);
        if (dist > wwval_(Wnewvertexmax)) {
          wwval_(Wnewvertexmax)= dist;
          if (dist > qh max_outside) {
            qh max_outside= dist;  /* used by qh_maxouter() */
            if (dist > qh TRACEdist)
              istrace= True;
          }
        }else if (-dist > qh TRACEdist)
          istrace= True;
        if (istrace) {
          qh_fprintf(qh ferr, 3060, "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;
  }
#ifndef qh_NOtrace
  if (qh IStracing >= 4) {
    qh_fprintf(qh ferr, 8017, "qh_setfacetplane: f%d offset %2.2g normal: ",
             facet->id, facet->offset);
    for (k=0; k < qh hull_dim; k++)
      qh_fprintf(qh ferr, 8018, "%2.2g ", facet->normal[k]);
    qh_fprintf(qh ferr, 8019, "\n");
  }
#endif
  qh_checkflipped(facet, NULL, qh_ALL);
  if (facet == qh tracefacet) {
    qh IStracing= oldtrace;
    qh_printfacet(qh ferr, facet);
  }
} /* setfacetplane */


/*---------------------------------

  qh_sethyperplane_det( dim, rows, point0, toporient, normal, offset, nearzero )
    given dim X dim array indexed by rows[], one row per point,
        toporient(flips all signs),
        and point0 (any row)
    set normalized hyperplane equation from oriented simplex

  returns:
    normal (normalized)
    offset (places point0 on the hyperplane)
    sets nearzero if hyperplane not through points

  notes:
    only defined for dim == 2..4
    rows[] is not modified
    solves det(P-V_0, V_n-V_0, ..., V_1-V_0)=0, i.e. every point is on hyperplane
    see Bower & Woodworth, A programmer's geometry, Butterworths 1983.

  derivation of 3-d minnorm
    Goal: all vertices V_i within qh.one_merge of hyperplane
    Plan: exactly translate the facet so that V_0 is the origin
          exactly rotate the facet so that V_1 is on the x-axis and y_2=0.
          exactly rotate the effective perturbation to only effect n_0
             this introduces a factor of sqrt(3)
    n_0 = ((y_2-y_0)*(z_1-z_0) - (z_2-z_0)*(y_1-y_0)) / norm
    Let M_d be the max coordinate difference
    Let M_a be the greater of M_d and the max abs. coordinate
    Let u be machine roundoff and distround be max error for distance computation
    The max error for n_0 is sqrt(3) u M_a M_d / norm.  n_1 is approx. 1 and n_2 is approx. 0
    The max error for distance of V_1 is sqrt(3) u M_a M_d M_d / norm.  Offset=0 at origin
    Then minnorm = 1.8 u M_a M_d M_d / qh.ONEmerge
    Note that qh.one_merge is approx. 45.5 u M_a and norm is usually about M_d M_d

  derivation of 4-d minnorm
    same as above except rotate the facet so that V_1 on x-axis and w_2, y_3, w_3=0
     [if two vertices fixed on x-axis, can rotate the other two in yzw.]
    n_0 = det3_(...) = y_2 det2_(z_1, w_1, z_3, w_3) = - y_2 w_1 z_3
     [all other terms contain at least two factors nearly zero.]
    The max error for n_0 is sqrt(4) u M_a M_d M_d / norm
    Then minnorm = 2 u M_a M_d M_d M_d / qh.ONEmerge
    Note that qh.one_merge is approx. 82 u M_a and norm is usually about M_d M_d M_d
*/
void qh_sethyperplane_det(int dim, coordT **rows, coordT *point0,
          boolT toporient, coordT *normal, realT *offset, boolT *nearzero) {
  realT maxround, dist;
  int i;
  pointT *point;


  if (dim == 2) {
    normal[0]= dY(1,0);
    normal[1]= dX(0,1);
    qh_normalize2(normal, dim, toporient, NULL, NULL);
    *offset= -(point0[0]*normal[0]+point0[1]*normal[1]);
    *nearzero= False;  /* since nearzero norm => incident points */
  }else if (dim == 3) {
    normal[0]= det2_(dY(2,0), dZ(2,0),
                     dY(1,0), dZ(1,0));
    normal[1]= det2_(dX(1,0), dZ(1,0),
                     dX(2,0), dZ(2,0));
    normal[2]= det2_(dX(2,0), dY(2,0),
                     dX(1,0), dY(1,0));
    qh_normalize2(normal, dim, toporient, NULL, NULL);
    *offset= -(point0[0]*normal[0] + point0[1]*normal[1]
               + point0[2]*normal[2]);
    maxround= qh DISTround;
    for (i=dim; i--; ) {
      point= rows[i];
      if (point != point0) {
        dist= *offset + (point[0]*normal[0] + point[1]*normal[1]
               + point[2]*normal[2]);
        if (dist > maxround || dist < -maxround) {
          *nearzero= True;
          break;
        }
      }
    }
  }else if (dim == 4) {
    normal[0]= - det3_(dY(2,0), dZ(2,0), dW(2,0),
                        dY(1,0), dZ(1,0), dW(1,0),
                        dY(3,0), dZ(3,0), dW(3,0));
    normal[1]=   det3_(dX(2,0), dZ(2,0), dW(2,0),
                        dX(1,0), dZ(1,0), dW(1,0),
                        dX(3,0), dZ(3,0), dW(3,0));
    normal[2]= - det3_(dX(2,0), dY(2,0), dW(2,0),
                        dX(1,0), dY(1,0), dW(1,0),
                        dX(3,0), dY(3,0), dW(3,0));
    normal[3]=   det3_(dX(2,0), dY(2,0), dZ(2,0),
                        dX(1,0), dY(1,0), dZ(1,0),
                        dX(3,0), dY(3,0), dZ(3,0));
    qh_normalize2(normal, dim, toporient, NULL, NULL);
    *offset= -(point0[0]*normal[0] + point0[1]*normal[1]
               + point0[2]*normal[2] + point0[3]*normal[3]);
    maxround= qh DISTround;
    for (i=dim; i--; ) {
      point= rows[i];
      if (point != point0) {
        dist= *offset + (point[0]*normal[0] + point[1]*normal[1]
               + point[2]*normal[2] + point[3]*normal[3]);
        if (dist > maxround || dist < -maxround) {
          *nearzero= True;
          break;
        }
      }
    }
  }
  if (*nearzero) {
    zzinc_(Zminnorm);
    /* qh_joggle_restart not needed, will call qh_sethyperplane_gauss instead */
    trace0((qh ferr, 3, "qh_sethyperplane_det: degenerate norm during p%d, use qh_sethyperplane_gauss instead.\n", qh furthest_id));
  }
} /* sethyperplane_det */


/*---------------------------------

  qh_sethyperplane_gauss( dim, rows, point0, toporient, normal, offset, nearzero )
    given(dim-1) X dim array of rows[i]= V_{i+1} - V_0 (point0)
    set normalized hyperplane equation from oriented simplex

  returns:
    normal (normalized)
    offset (places point0 on the hyperplane)

  notes:
    if nearzero
      orientation may be incorrect because of incorrect sign flips in gausselim
    solves [V_n-V_0,...,V_1-V_0, 0 .. 0 1] * N == [0 .. 0 1]
        or [V_n-V_0,...,V_1-V_0, 0 .. 0 1] * N == [0]
    i.e., N is normal to the hyperplane, and the unnormalized
        distance to [0 .. 1] is either 1 or   0

  design:
    perform gaussian elimination
    flip sign for negative values
    perform back substitution
    normalize result
    compute offset
*/
void qh_sethyperplane_gauss(int dim, coordT **rows, pointT *point0,
                boolT toporient, coordT *normal, coordT *offset, boolT *nearzero) {
  coordT *pointcoord, *normalcoef;
  int k;
  boolT sign= toporient, nearzero2= False;

  qh_gausselim(rows, dim-1, dim, &sign, nearzero);
  for (k=dim-1; k--; ) {
    if ((rows[k])[k] < 0)
      sign ^= 1;
  }
  if (*nearzero) {
    zzinc_(Znearlysingular);
    /* qh_joggle_restart ignored for Znearlysingular, normal part of qh_sethyperplane_gauss */
    trace0((qh ferr, 4, "qh_sethyperplane_gauss: nearly singular or axis parallel hyperplane during p%d.\n", qh furthest_id));
    qh_backnormal(rows, dim-1, dim, sign, normal, &nearzero2);
  }else {
    qh_backnormal(rows, dim-1, dim, sign, normal, &nearzero2);
    if (nearzero2) {
      zzinc_(Znearlysingular);
      trace0((qh ferr, 5, "qh_sethyperplane_gauss: singular or axis parallel hyperplane at normalization during p%d.\n", qh furthest_id));
    }
  }
  if (nearzero2)
    *nearzero= True;
  qh_normalize2(normal, dim, True, NULL, NULL);
  pointcoord= point0;
  normalcoef= normal;
  *offset= -(*pointcoord++ * *normalcoef++);
  for (k=dim-1; k--; )
    *offset -= *pointcoord++ * *normalcoef++;
} /* sethyperplane_gauss */



qhull-2020.2/src/libqhull/geom.h0000644060175106010010000001660713661631132014705 0ustar  bbarber/*
  ---------------------------------

  geom.h
    header file for geometric routines

   see qh-geom.htm and geom.c

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull/geom.h#2 $$Change: 2953 $
   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
*/

#ifndef qhDEFgeom
#define qhDEFgeom 1

#include "libqhull.h"

/* ============ -macros- ======================== */

/*----------------------------------

  fabs_(a)
    returns the absolute value of a
*/
#define fabs_( a ) ((( a ) < 0 ) ? -( a ):( a ))

/*----------------------------------

  fmax_(a,b)
    returns the maximum value of a and b
*/
#define fmax_( a,b )  ( ( a ) < ( b ) ? ( b ) : ( a ) )

/*----------------------------------

  fmin_(a,b)
    returns the minimum value of a and b
*/
#define fmin_( a,b )  ( ( a ) > ( b ) ? ( b ) : ( a ) )

/*----------------------------------

  maximize_(maxval, val)
    set maxval to val if val is greater than maxval
*/
#define maximize_( maxval, val ) { if (( maxval ) < ( val )) ( maxval )= ( val ); }

/*----------------------------------

  minimize_(minval, val)
    set minval to val if val is less than minval
*/
#define minimize_( minval, val ) { if (( minval ) > ( val )) ( minval )= ( val ); }

/*----------------------------------

  det2_(a1, a2,
        b1, b2)

    compute a 2-d determinate
*/
#define det2_( a1,a2,b1,b2 ) (( a1 )*( b2 ) - ( a2 )*( b1 ))

/*----------------------------------

  det3_(a1, a2, a3,
       b1, b2, b3,
       c1, c2, c3)

    compute a 3-d determinate
*/
#define det3_( a1,a2,a3,b1,b2,b3,c1,c2,c3 ) ( ( a1 )*det2_( b2,b3,c2,c3 ) \
                - ( b1 )*det2_( a2,a3,c2,c3 ) + ( c1 )*det2_( a2,a3,b2,b3 ) )

/*----------------------------------

  dX( p1, p2 )
  dY( p1, p2 )
  dZ( p1, p2 )

    given two indices into rows[],

    compute the difference between X, Y, or Z coordinates
*/
#define dX( p1,p2 )  ( *( rows[p1] ) - *( rows[p2] ))
#define dY( p1,p2 )  ( *( rows[p1]+1 ) - *( rows[p2]+1 ))
#define dZ( p1,p2 )  ( *( rows[p1]+2 ) - *( rows[p2]+2 ))
#define dW( p1,p2 )  ( *( rows[p1]+3 ) - *( rows[p2]+3 ))

/*============= prototypes in alphabetical order, infrequent at end ======= */

void    qh_backnormal(realT **rows, int numrow, int numcol, boolT sign, coordT *normal, boolT *nearzero);
void    qh_distplane(pointT *point, facetT *facet, realT *dist);
facetT *qh_findbest(pointT *point, facetT *startfacet,
                     boolT bestoutside, boolT isnewfacets, boolT noupper,
                     realT *dist, boolT *isoutside, int *numpart);
facetT *qh_findbesthorizon(boolT ischeckmax, pointT *point,
                     facetT *startfacet, boolT noupper, realT *bestdist, int *numpart);
facetT *qh_findbestnew(pointT *point, facetT *startfacet, realT *dist,
                     boolT bestoutside, boolT *isoutside, int *numpart);
void    qh_gausselim(realT **rows, int numrow, int numcol, boolT *sign, boolT *nearzero);
realT   qh_getangle(pointT *vect1, pointT *vect2);
pointT *qh_getcenter(setT *vertices);
pointT *qh_getcentrum(facetT *facet);
coordT  qh_getdistance(facetT *facet, facetT *neighbor, coordT *mindist, coordT *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_detmaxoutside(void);
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);
vertexT *qh_furthestnewvertex(unsigned int unvisited, facetT *facet, realT *maxdistp /* qh.newvertex_list */);
vertexT *qh_furthestvertex(facetT *facetA, facetT *facetB, realT *maxdistp, realT *mindistp);
void    qh_getarea(facetT *facetlist);
boolT   qh_gram_schmidt(int dim, realT **rows);
boolT   qh_inthresholds(coordT *normal, realT *angle);
void    qh_joggleinput(void);
realT  *qh_maxabsval(realT *normal, int dim);
setT   *qh_maxmin(pointT *points, int numpoints, int dimension);
realT   qh_maxouter(void);
void    qh_maxsimplex(int dim, setT *maxpoints, pointT *points, int numpoints, setT **simplex);
realT   qh_minabsval(realT *normal, int dim);
int     qh_mindiff(realT *vecA, realT *vecB, int dim);
boolT   qh_orientoutside(facetT *facet);
void    qh_outerinner(facetT *facet, realT *outerplane, realT *innerplane);
coordT  qh_pointdist(pointT *point1, pointT *point2, int dim);
void    qh_printmatrix(FILE *fp, const char *string, realT **rows, int numrow, int numcol);
void    qh_printpoints(FILE *fp, const char *string, setT *points);
void    qh_projectinput(void);
void    qh_projectpoints(signed char *project, int n, realT *points,
             int numpoints, int dim, realT *newpoints, int newdim);
void    qh_rotateinput(realT **rows);
void    qh_rotatepoints(realT *points, int numpoints, int dim, realT **rows);
void    qh_scaleinput(void);
void    qh_scalelast(coordT *points, int numpoints, int dim, coordT low,
                   coordT high, coordT newhigh);
void    qh_scalepoints(pointT *points, int numpoints, int dim,
                realT *newlows, realT *newhighs);
boolT   qh_sethalfspace(int dim, coordT *coords, coordT **nextp,
              coordT *normal, coordT *offset, coordT *feasible);
coordT *qh_sethalfspace_all(int dim, int count, coordT *halfspaces, pointT *feasible);
coordT  qh_vertex_bestdist(setT *vertices);
coordT  qh_vertex_bestdist2(setT *vertices, vertexT **vertexp, vertexT **vertexp2);
pointT *qh_voronoi_center(int dim, setT *points);

#endif /* qhDEFgeom */



qhull-2020.2/src/libqhull/geom2.c0000644060175106010010000022267613723576500014775 0ustar  bbarber/*
  ---------------------------------


   geom2.c
   infrequently used geometric routines of qhull

   see qh-geom.htm and geom.h

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull/geom2.c#14 $$Change: 3037 $
   $DateTime: 2020/09/03 17:28:32 $$Author: bbarber $

   frequently used code goes into geom.c
*/

#include "qhull_a.h"

/*================== functions in alphabetic order ============*/

/*---------------------------------

  qh_copypoints( points, numpoints, dimension )
    return qh_malloc'd copy of points

  notes:
    qh_free the returned points to avoid a memory leak
*/
coordT *qh_copypoints(coordT *points, int numpoints, int dimension)
{
  int size;
  coordT *newpoints;

  size= numpoints * dimension * (int)sizeof(coordT);
  if (!(newpoints= (coordT *)qh_malloc((size_t)size))) {
    qh_fprintf(qh ferr, 6004, "qhull error: insufficient memory to copy %d points\n",
        numpoints);
    qh_errexit(qh_ERRmem, NULL, NULL);
  }
  memcpy((char *)newpoints, (char *)points, (size_t)size); /* newpoints!=0 by QH6004 */
  return newpoints;
} /* copypoints */

/*---------------------------------

  qh_crossproduct( dim, vecA, vecB, vecC )
    crossproduct of 2 dim vectors
    C= A x B

  notes:
    from Glasner, Graphics Gems I, p. 639
    only defined for dim==3
*/
void qh_crossproduct(int dim, realT vecA[3], realT vecB[3], realT vecC[3]){

  if (dim == 3) {
    vecC[0]=   det2_(vecA[1], vecA[2],
                     vecB[1], vecB[2]);
    vecC[1]= - det2_(vecA[0], vecA[2],
                     vecB[0], vecB[2]);
    vecC[2]=   det2_(vecA[0], vecA[1],
                     vecB[0], vecB[1]);
  }
} /* vcross */

/*---------------------------------

  qh_determinant( rows, dim, nearzero )
    compute signed determinant of a square matrix
    uses qh.NEARzero to test for degenerate matrices

  returns:
    determinant
    overwrites rows and the matrix
    if dim == 2 or 3
      nearzero iff determinant < qh NEARzero[dim-1]
      (!quite correct, not critical)
    if dim >= 4
      nearzero iff diagonal[k] < qh NEARzero[k]
*/
realT qh_determinant(realT **rows, int dim, boolT *nearzero) {
  realT det=0;
  int i;
  boolT sign= False;

  *nearzero= False;
  if (dim < 2) {
    qh_fprintf(qh ferr, 6005, "qhull internal error (qh_determinate): only implemented for dimension >= 2\n");
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }else if (dim == 2) {
    det= det2_(rows[0][0], rows[0][1],
                 rows[1][0], rows[1][1]);
    if (fabs_(det) < 10*qh NEARzero[1])  /* QH11031 FIX: 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) < 10*qh NEARzero[2])  /* QH11031 FIX: what should this be?  det 5.5e-12 was flat for qh_maxsimplex of qdelaunay 0,0 27,27 -36,36 -9,63 */
      *nearzero= True;
  }else {
    qh_gausselim(rows, dim, dim, &sign, nearzero);  /* if nearzero, diagonal still ok */
    det= 1.0;
    for (i=dim; i--; )
      det *= (rows[i])[i];
    if (sign)
      det= -det;
  }
  return det;
} /* determinant */

/*---------------------------------

  qh_detjoggle( points, numpoints, dimension )
    determine default max joggle for point array
      as qh_distround * qh_JOGGLEdefault

  returns:
    initial value for JOGGLEmax from points and REALepsilon

  notes:
    computes DISTround since qh_maxmin not called yet
    if qh SCALElast, last dimension will be scaled later to MAXwidth

    loop duplicated from qh_maxmin
*/
realT qh_detjoggle(pointT *points, int numpoints, int dimension) {
  realT abscoord, distround, joggle, maxcoord, mincoord;
  pointT *point, *pointtemp;
  realT maxabs= -REALmax;
  realT sumabs= 0;
  realT maxwidth= 0;
  int k;

  if (qh SETroundoff)
    distround= qh DISTround; /* 'En' */
  else{
    for (k=0; k < dimension; k++) {
      if (qh SCALElast && k == dimension-1)
        abscoord= maxwidth;
      else if (qh DELAUNAY && k == dimension-1) /* will qh_setdelaunay() */
        abscoord= 2 * maxabs * maxabs;  /* may be low by qh hull_dim/2 */
      else {
        maxcoord= -REALmax;
        mincoord= REALmax;
        FORALLpoint_(points, numpoints) {
          maximize_(maxcoord, point[k]);
          minimize_(mincoord, point[k]);
        }
        maximize_(maxwidth, maxcoord-mincoord);
        abscoord= fmax_(maxcoord, -mincoord);
      }
      sumabs += abscoord;
      maximize_(maxabs, abscoord);
    } /* for k */
    distround= qh_distround(qh hull_dim, maxabs, sumabs);
  }
  joggle= distround * qh_JOGGLEdefault;
  maximize_(joggle, REALepsilon * qh_JOGGLEdefault);
  trace2((qh ferr, 2001, "qh_detjoggle: joggle=%2.2g maxwidth=%2.2g\n", joggle, maxwidth));
  return joggle;
} /* detjoggle */

/*---------------------------------

  qh_detmaxoutside();
    determine qh.MAXoutside target for qh_RATIO... tests of distance
    updates option '_max-outside'

  notes:
    called from qh_addpoint and qh_detroundoff
    accounts for qh.ONEmerge, qh.DISTround, qh.MINoutside ('Wn'), qh.max_outside
    see qh_maxout for qh.max_outside with qh.DISTround
*/

void qh_detmaxoutside(void) {
  realT maxoutside;

  maxoutside= fmax_(qh max_outside, qh ONEmerge + qh DISTround);
  maximize_(maxoutside, qh MINoutside);
  qh MAXoutside= maxoutside;
  trace3((qh ferr, 3056, "qh_detmaxoutside: MAXoutside %2.2g from qh.max_outside %2.2g, ONEmerge %2.2g, MINoutside %2.2g, DISTround %2.2g\n",
      qh MAXoutside, qh max_outside, qh ONEmerge, qh MINoutside, qh DISTround));
} /* detmaxoutside */

/*---------------------------------

  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);
    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;
    trace4((qh ferr, 4096, "qh_detroundoff: increase qh.ANGLEround by option 'R%2.2g'\n", qh RANDOMfactor));
  }
  if (qh premerge_cos < REALmax/2) {
    qh premerge_cos -= qh ANGLEround;
    if (qh RANDOMdist)
      qh_option("Angle-premerge-with-random", NULL, &qh premerge_cos);
  }
  if (qh postmerge_cos < REALmax/2) {
    qh postmerge_cos -= qh ANGLEround;
    if (qh RANDOMdist)
      qh_option("Angle-postmerge-with-random", NULL, &qh postmerge_cos);
  }
  qh premerge_centrum += 2 * qh DISTround;    /*2 for centrum and distplane()*/
  qh postmerge_centrum += 2 * qh DISTround;
  if (qh RANDOMdist && (qh MERGEexact || qh PREmerge))
    qh_option("Centrum-premerge-with-random", NULL, &qh premerge_centrum);
  if (qh RANDOMdist && qh POSTmerge)
    qh_option("Centrum-postmerge-with-random", NULL, &qh postmerge_centrum);
  { /* compute ONEmerge, max vertex offset for merging simplicial facets */
    realT maxangle= 1.0, maxrho;

    minimize_(maxangle, qh premerge_cos);
    minimize_(maxangle, qh postmerge_cos);
    /* max diameter * sin theta + DISTround for vertex to its hyperplane */
    qh ONEmerge= sqrt((realT)qh hull_dim) * qh MAXwidth *
      sqrt(1.0 - maxangle * maxangle) + qh DISTround;
    maxrho= qh hull_dim * qh premerge_centrum + qh DISTround;
    maximize_(qh ONEmerge, maxrho);
    maxrho= qh hull_dim * qh postmerge_centrum + qh DISTround;
    maximize_(qh ONEmerge, maxrho);
    if (qh MERGING)
      qh_option("_one-merge", NULL, &qh ONEmerge);
  }
  qh NEARinside= qh ONEmerge * qh_RATIOnearinside; /* only used if qh KEEPnearinside */
  if (qh JOGGLEmax < REALmax/2 && (qh KEEPcoplanar || qh KEEPinside)) {
    realT maxdist;             /* adjust qh.NEARinside for joggle */
    qh KEEPnearinside= True;
    maxdist= sqrt((realT)qh hull_dim) * qh JOGGLEmax + qh DISTround;
    maxdist= 2*maxdist;        /* vertex and coplanar point can joggle in opposite directions */
    maximize_(qh NEARinside, maxdist);  /* must agree with qh_nearcoplanar() */
  }
  if (qh KEEPnearinside)
    qh_option("_near-inside", NULL, &qh NEARinside);
  if (qh JOGGLEmax < qh DISTround) {
    qh_fprintf(qh ferr, 6006, "qhull option 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-max-coplanar", NULL, &qh MAXcoplanar);
  }
  if (!qh APPROXhull) {             /* user may specify qh MINoutside */
    qh MINoutside= 2 * qh MINvisible;
    if (qh premerge_cos < REALmax/2)
      maximize_(qh MINoutside, (1- qh premerge_cos) * qh MAXabs_coord);
    qh_option("Width-outside", NULL, &qh MINoutside);
  }
  qh WIDEfacet= qh MINoutside;
  maximize_(qh WIDEfacet, qh_WIDEcoplanar * qh MAXcoplanar);
  maximize_(qh WIDEfacet, qh_WIDEcoplanar * qh MINvisible);
  qh_option("_wide-facet", NULL, &qh WIDEfacet);
  if (qh MINvisible > qh MINoutside + 3 * REALepsilon
  && !qh BESToutside && !qh FORCEoutput)
    qh_fprintf(qh ferr, 7001, "qhull input warning: minimum visibility V%.2g is greater than \nminimum outside W%.2g.  Flipped facets are likely.\n",
             qh MINvisible, qh MINoutside);
  qh max_vertex= qh DISTround;
  qh min_vertex= -qh DISTround;
  /* numeric constants reported in printsummary */
  qh_detmaxoutside();
} /* detroundoff */

/*---------------------------------

  qh_detsimplex( apex, points, dim, nearzero )
    compute determinant of a simplex with point apex and base points

  returns:
     signed determinant and nearzero from qh_determinant

  notes:
     called by qh_maxsimplex and qh_initialvertices
     uses qh.gm_matrix/qh.gm_row (assumes they're big enough)

  design:
    construct qm_matrix by subtracting apex from points
    compute determinate
*/
realT qh_detsimplex(pointT *apex, setT *points, int dim, boolT *nearzero) {
  pointT *coorda, *coordp, *gmcoord, *point, **pointp;
  coordT **rows;
  int k,  i=0;
  realT det;

  zinc_(Zdetsimplex);
  gmcoord= qh gm_matrix;
  rows= qh gm_row;
  FOREACHpoint_(points) {
    if (i == dim)
      break;
    rows[i++]= gmcoord;
    coordp= point;
    coorda= apex;
    for (k=dim; k--; )
      *(gmcoord++)= *coordp++ - *coorda++;
  }
  if (i < dim) {
    qh_fprintf(qh ferr, 6007, "qhull internal error (qh_detsimplex): #points %d < dimension %d\n",
               i, dim);
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  det= qh_determinant(rows, dim, nearzero);
  trace2((qh ferr, 2002, "qh_detsimplex: det=%2.2g for point p%d, dim %d, nearzero? %d\n",
          det, qh_pointid(apex), dim, *nearzero));
  return det;
} /* detsimplex */

/*---------------------------------

  qh_distnorm( dim, point, normal, offset )
    return distance from point to hyperplane at normal/offset

  returns:
    dist

  notes:
    dist > 0 if point is outside of hyperplane

  see:
    qh_distplane in geom.c
*/
realT qh_distnorm(int dim, pointT *point, pointT *normal, realT *offsetp) {
  coordT *normalp= normal, *coordp= point;
  realT dist;
  int k;

  dist= *offsetp;
  for (k=dim; k--; )
    dist += *(coordp++) * *(normalp++);
  return dist;
} /* distnorm */

/*---------------------------------

  qh_distround( dimension, maxabs, maxsumabs )
    compute maximum round-off error for a distance computation
      to a normalized hyperplane
    maxabs is the maximum absolute value of a coordinate
    maxsumabs is the maximum possible sum of absolute coordinate values
    if qh.RANDOMdist ('Qr'), adjusts qh_distround

  returns:
    max dist round for qh.REALepsilon and qh.RANDOMdist

  notes:
    calculate roundoff error according to Golub & van Loan, 1983, Lemma 3.2-1, "Rounding Errors"
    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, delta;

  maxdistsum= sqrt((realT)dimension) * maxabs;
  minimize_( maxdistsum, maxsumabs);
  maxround= REALepsilon * (dimension * maxdistsum * 1.01 + maxabs);
              /* adds maxabs for offset */
  if (qh RANDOMdist) {
    delta= qh RANDOMfactor * maxabs;
    maxround += delta;
    trace4((qh ferr, 4092, "qh_distround: increase roundoff by random delta %2.2g for option 'R%2.2g'\n", delta, qh RANDOMfactor));
  }
  trace4((qh ferr, 4008, "qh_distround: %2.2g, maxabs %2.2g, maxsumabs %2.2g, maxdistsum %2.2g\n",
            maxround, maxabs, maxsumabs, maxdistsum));
  return maxround;
} /* distround */

/*---------------------------------

  qh_divzero( numer, denom, mindenom1, zerodiv )
    divide by a number that's nearly zero
    mindenom1= minimum denominator for dividing into 1.0

  returns:
    quotient
    sets zerodiv and returns 0.0 if it would overflow

  design:
    if numer is nearly zero and abs(numer) < abs(denom)
      return numer/denom
    else if numer is nearly zero
      return 0 and zerodiv
    else if denom/numer non-zero
      return numer/denom
    else
      return 0 and zerodiv
*/
realT qh_divzero(realT numer, realT denom, realT mindenom1, boolT *zerodiv) {
  realT temp, numerx, denomx;


  if (numer < mindenom1 && numer > -mindenom1) {
    numerx= fabs_(numer);
    denomx= fabs_(denom);
    if (numerx < denomx) {
      *zerodiv= False;
      return numer/denom;
    }else {
      *zerodiv= True;
      return 0.0;
    }
  }
  temp= denom/numer;
  if (temp > mindenom1 || temp < -mindenom1) {
    *zerodiv= False;
    return numer/denom;
  }else {
    *zerodiv= True;
    return 0.0;
  }
} /* divzero */


/*---------------------------------

  qh_facetarea( facet )
    return area for a facet

  notes:
    if non-simplicial,
      uses centrum to triangulate facet and sums the projected areas.
    if (qh DELAUNAY),
      computes projected area instead for last coordinate
    assumes facet->normal exists
    projecting tricoplanar facets to the hyperplane does not appear to make a difference

  design:
    if simplicial
      compute area
    else
      for each ridge
        compute area from centrum to ridge
    negate area if upper Delaunay facet
*/
realT qh_facetarea(facetT *facet) {
  vertexT *apex;
  pointT *centrum;
  realT area= 0.0;
  ridgeT *ridge, **ridgep;

  if (facet->simplicial) {
    apex= SETfirstt_(facet->vertices, vertexT);
    area= qh_facetarea_simplex(qh hull_dim, apex->point, facet->vertices,
                    apex, facet->toporient, facet->normal, &facet->offset);
  }else {
    if (qh CENTERtype == qh_AScentrum)
      centrum= facet->center;
    else
      centrum= qh_getcentrum(facet);
    FOREACHridge_(facet->ridges)
      area += qh_facetarea_simplex(qh hull_dim, centrum, ridge->vertices,
                 NULL, (boolT)(ridge->top == facet),  facet->normal, &facet->offset);
    if (qh CENTERtype != qh_AScentrum)
      qh_memfree(centrum, qh normal_size);
  }
  if (facet->upperdelaunay && qh DELAUNAY)
    area= -area;  /* the normal should be [0,...,1] */
  trace4((qh ferr, 4009, "qh_facetarea: f%d area %2.2g\n", facet->id, area));
  return area;
} /* facetarea */

/*---------------------------------

  qh_facetarea_simplex( dim, apex, vertices, notvertex, toporient, normal, offset )
    return area for a simplex defined by
      an apex, a base of vertices, an orientation, and a unit normal
    if simplicial or tricoplanar facet,
      notvertex is defined and it is skipped in vertices

  returns:
    computes area of simplex projected to plane [normal,offset]
    returns 0 if vertex too far below plane (qh WIDEfacet)
      vertex can't be apex of tricoplanar facet

  notes:
    if (qh DELAUNAY),
      computes projected area instead for last coordinate
    uses qh gm_matrix/gm_row and qh hull_dim
    helper function for qh_facetarea

  design:
    if Notvertex
      translate simplex to apex
    else
      project simplex to normal/offset
      translate simplex to apex
    if Delaunay
      set last row/column to 0 with -1 on diagonal
    else
      set last row to Normal
    compute determinate
    scale and flip sign for area
*/
realT qh_facetarea_simplex(int dim, coordT *apex, setT *vertices,
        vertexT *notvertex,  boolT toporient, coordT *normal, realT *offset) {
  pointT *coorda, *coordp, *gmcoord;
  coordT **rows, *normalp;
  int k,  i=0;
  realT area, dist;
  vertexT *vertex, **vertexp;
  boolT nearzero;

  gmcoord= qh gm_matrix;
  rows= qh gm_row;
  FOREACHvertex_(vertices) {
    if (vertex == notvertex)
      continue;
    rows[i++]= gmcoord;
    coorda= apex;
    coordp= vertex->point;
    normalp= normal;
    if (notvertex) {
      for (k=dim; k--; )
        *(gmcoord++)= *coordp++ - *coorda++;
    }else {
      dist= *offset;
      for (k=dim; k--; )
        dist += *coordp++ * *normalp++;
      if (dist < -qh WIDEfacet) {
        zinc_(Znoarea);
        return 0.0;
      }
      coordp= vertex->point;
      normalp= normal;
      for (k=dim; k--; )
        *(gmcoord++)= (*coordp++ - dist * *normalp++) - *coorda++;
    }
  }
  if (i != dim-1) {
    qh_fprintf(qh ferr, 6008, "qhull internal error (qh_facetarea_simplex): #points %d != dim %d -1\n",
               i, dim);
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  rows[i]= gmcoord;
  if (qh DELAUNAY) {
    for (i=0; i < dim-1; i++)
      rows[i][dim-1]= 0.0;
    for (k=dim; k--; )
      *(gmcoord++)= 0.0;
    rows[dim-1][dim-1]= -1.0;
  }else {
    normalp= normal;
    for (k=dim; k--; )
      *(gmcoord++)= *normalp++;
  }
  zinc_(Zdetfacetarea);
  area= qh_determinant(rows, dim, &nearzero);
  if (toporient)
    area= -area;
  area *= qh AREAfactor;
  trace4((qh ferr, 4010, "qh_facetarea_simplex: area=%2.2g for point p%d, toporient %d, nearzero? %d\n",
          area, qh_pointid(apex), toporient, nearzero));
  return area;
} /* facetarea_simplex */

/*---------------------------------

  qh_facetcenter( vertices )
    return Voronoi center (Voronoi vertex) for a facet's vertices

  returns:
    return temporary point equal to the center

  see:
    qh_voronoi_center()
*/
pointT *qh_facetcenter(setT *vertices) {
  setT *points= qh_settemp(qh_setsize(vertices));
  vertexT *vertex, **vertexp;
  pointT *center;

  FOREACHvertex_(vertices)
    qh_setappend(&points, vertex->point);
  center= qh_voronoi_center(qh hull_dim-1, points);
  qh_settempfree(&points);
  return center;
} /* facetcenter */

/*---------------------------------

  qh_findgooddist( point, facetA, dist, facetlist )
    find best good facet visible for point from facetA
    assumes facetA is visible from point

  returns:
    best facet, i.e., good facet that is furthest from point
      distance to best facet
      NULL if none

    moves good, visible facets (and some other visible facets)
      to end of qh facet_list

  notes:
    uses qh visit_id

  design:
    initialize bestfacet if facetA is good
    move facetA to end of facetlist
    for each facet on facetlist
      for each unvisited neighbor of facet
        move visible neighbors to end of facetlist
        update best good neighbor
        if no good neighbors, update best facet
*/
facetT *qh_findgooddist(pointT *point, facetT *facetA, realT *distp,
               facetT **facetlist) {
  realT bestdist= -REALmax, dist;
  facetT *neighbor, **neighborp, *bestfacet=NULL, *facet;
  boolT goodseen= False;

  if (facetA->good) {
    zzinc_(Zcheckpart);  /* calls from check_bestdist occur after print stats */
    qh_distplane(point, facetA, &bestdist);
    bestfacet= facetA;
    goodseen= True;
  }
  qh_removefacet(facetA);
  qh_appendfacet(facetA);
  *facetlist= facetA;
  facetA->visitid= ++qh visit_id;
  FORALLfacet_(*facetlist) {
    FOREACHneighbor_(facet) {
      if (neighbor->visitid == qh visit_id)
        continue;
      neighbor->visitid= qh visit_id;
      if (goodseen && !neighbor->good)
        continue;
      zzinc_(Zcheckpart);
      qh_distplane(point, neighbor, &dist);
      if (dist > 0) {
        qh_removefacet(neighbor);
        qh_appendfacet(neighbor);
        if (neighbor->good) {
          goodseen= True;
          if (dist > bestdist) {
            bestdist= dist;
            bestfacet= neighbor;
          }
        }
      }
    }
  }
  if (bestfacet) {
    *distp= bestdist;
    trace2((qh ferr, 2003, "qh_findgooddist: p%d is %2.2g above good facet f%d\n",
      qh_pointid(point), bestdist, bestfacet->id));
    return bestfacet;
  }
  trace4((qh ferr, 4011, "qh_findgooddist: no good facet for p%d above f%d\n",
      qh_pointid(point), facetA->id));
  return NULL;
}  /* findgooddist */

/*---------------------------------

  qh_furthestnewvertex( unvisited, facet, &maxdist )
    return furthest unvisited, new vertex to a facet

  return:
    NULL if no vertex is above facet
    maxdist to facet
    updates v.visitid

  notes:
    Ignores vertices in facetB
    Does not change qh.vertex_visit.  Use in conjunction with qh_furthestvertex
*/
vertexT *qh_furthestnewvertex(unsigned int unvisited, facetT *facet, realT *maxdistp /* qh.newvertex_list */) {
  vertexT *maxvertex= NULL, *vertex;
  coordT dist, maxdist= 0.0;

  FORALLvertex_(qh newvertex_list) {
    if (vertex->newfacet && vertex->visitid <= unvisited) {
      vertex->visitid= qh vertex_visit;
      qh_distplane(vertex->point, facet, &dist);
      if (dist > maxdist) {
        maxdist= dist;
        maxvertex= vertex;
      }
    }
  }
  trace4((qh ferr, 4085, "qh_furthestnewvertex: v%d dist %2.2g is furthest new vertex for f%d\n",
    getid_(maxvertex), maxdist, facet->id));
  *maxdistp= maxdist;
  return maxvertex;
} /* furthestnewvertex */

/*---------------------------------

  qh_furthestvertex( facetA, facetB, &maxdist, &mindist )
    return furthest vertex in facetA from facetB, or NULL if none

  return:
    maxdist and mindist to facetB or 0.0 if none
    updates qh.vertex_visit

  notes:
    Ignores vertices in facetB
*/
vertexT *qh_furthestvertex(facetT *facetA, facetT *facetB, realT *maxdistp, realT *mindistp) {
  vertexT *maxvertex= NULL, *vertex, **vertexp;
  coordT dist, maxdist= -REALmax, mindist= REALmax;

  qh vertex_visit++;
  FOREACHvertex_(facetB->vertices)
    vertex->visitid= qh vertex_visit;
  FOREACHvertex_(facetA->vertices) {
    if (vertex->visitid != qh vertex_visit) {
      vertex->visitid= qh vertex_visit;
      zzinc_(Zvertextests);
      qh_distplane(vertex->point, facetB, &dist);
      if (!maxvertex) {
        maxdist= dist;
        mindist= dist;
        maxvertex= vertex;
      }else if (dist > maxdist) {
        maxdist= dist;
        maxvertex= vertex;
      }else if (dist < mindist)
        mindist= dist;
    }
  }
  if (!maxvertex) {
    trace3((qh ferr, 3067, "qh_furthestvertex: all vertices of f%d are in f%d.  Returning 0.0 for max and mindist\n",
      facetA->id, facetB->id));
    maxdist= mindist= 0.0;
  }else {
    trace4((qh ferr, 4084, "qh_furthestvertex: v%d dist %2.2g is furthest (mindist %2.2g) of f%d above f%d\n",
      maxvertex->id, maxdist, mindist, facetA->id, facetB->id));
  }
  *maxdistp= maxdist;
  *mindistp= mindist;
  return maxvertex;
} /* furthestvertex */

/*---------------------------------

  qh_getarea( facetlist )
    set area of all facets in facetlist
    collect statistics
    nop if hasAreaVolume

  returns:
    sets qh totarea/totvol to total area and volume of convex hull
    for Delaunay triangulation, computes projected area of the lower or upper hull
      ignores upper hull if qh ATinfinity

  notes:
    could compute outer volume by expanding facet area by rays from interior
    the following attempt at perpendicular projection underestimated badly:
      qh.totoutvol += (-dist + facet->maxoutside + qh DISTround)
                            * area/ qh hull_dim;
  design:
    for each facet on facetlist
      compute facet->area
      update qh.totarea and qh.totvol
*/
void qh_getarea(facetT *facetlist) {
  realT area;
  realT dist;
  facetT *facet;

  if (qh hasAreaVolume)
    return;
  if (qh REPORTfreq)
    qh_fprintf(qh ferr, 8020, "computing area of each facet and volume of the convex hull\n");
  else
    trace1((qh ferr, 1001, "qh_getarea: computing area for each facet and its volume to qh.interior_point (dist*area/dim)\n"));
  qh totarea= qh totvol= 0.0;
  FORALLfacet_(facetlist) {
    if (!facet->normal)
      continue;
    if (facet->upperdelaunay && qh ATinfinity)
      continue;
    if (!facet->isarea) {
      facet->f.area= qh_facetarea(facet);
      facet->isarea= True;
    }
    area= facet->f.area;
    if (qh DELAUNAY) {
      if (facet->upperdelaunay == qh UPPERdelaunay)
        qh totarea += area;
    }else {
      qh totarea += area;
      qh_distplane(qh interior_point, facet, &dist);
      qh totvol += -dist * area/ qh hull_dim;
    }
    if (qh PRINTstatistics) {
      wadd_(Wareatot, area);
      wmax_(Wareamax, area);
      wmin_(Wareamin, area);
    }
  }
  qh hasAreaVolume= True;
} /* getarea */

/*---------------------------------

  qh_gram_schmidt( dim, row )
    implements Gram-Schmidt orthogonalization by rows

  returns:
    false if zero norm
    overwrites rows[dim][dim]

  notes:
    see Golub & van Loan, 1983, Algorithm 6.2-2, "Modified Gram-Schmidt"
    overflow due to small divisors not handled

  design:
    for each row
      compute norm for row
      if non-zero, normalize row
      for each remaining rowA
        compute inner product of row and rowA
        reduce rowA by row * inner product
*/
boolT qh_gram_schmidt(int dim, realT **row) {
  realT *rowi, *rowj, norm;
  int i, j, k;

  for (i=0; i < dim; i++) {
    rowi= row[i];
    for (norm=0.0, k=dim; k--; rowi++)
      norm += *rowi * *rowi;
    norm= sqrt(norm);
    wmin_(Wmindenom, norm);
    if (norm == 0.0)  /* either 0 or overflow due to sqrt */
      return False;
    for (k=dim; k--; )
      *(--rowi) /= norm;
    for (j=i+1; j < dim; j++) {
      rowj= row[j];
      for (norm=0.0, k=dim; k--; )
        norm += *rowi++ * *rowj++;
      for (k=dim; k--; )
        *(--rowj) -= *(--rowi) * norm;
    }
  }
  return True;
} /* gram_schmidt */


/*---------------------------------

  qh_inthresholds( normal, angle )
    return True if normal within qh.lower_/upper_threshold

  returns:
    estimate of angle by summing of threshold diffs
      angle may be NULL
      smaller "angle" is better

  notes:
    invalid if qh.SPLITthresholds

  see:
    qh.lower_threshold in qh_initbuild()
    qh_initthresholds()

  design:
    for each dimension
      test threshold
*/
boolT qh_inthresholds(coordT *normal, realT *angle) {
  boolT within= True;
  int k;
  realT threshold;

  if (angle)
    *angle= 0.0;
  for (k=0; k < qh hull_dim; k++) {
    threshold= qh lower_threshold[k];
    if (threshold > -REALmax/2) {
      if (normal[k] < threshold)
        within= False;
      if (angle) {
        threshold -= normal[k];
        *angle += fabs_(threshold);
      }
    }
    if (qh upper_threshold[k] < REALmax/2) {
      threshold= qh upper_threshold[k];
      if (normal[k] > threshold)
        within= False;
      if (angle) {
        threshold -= normal[k];
        *angle += fabs_(threshold);
      }
    }
  }
  return within;
} /* inthresholds */


/*---------------------------------

  qh_joggleinput( )
    randomly joggle input to Qhull by qh.JOGGLEmax
    initial input is qh.first_point/qh.num_points of qh.hull_dim
      repeated calls use qh.input_points/qh.num_points

  returns:
    joggles points at qh.first_point/qh.num_points
    copies data to qh.input_points/qh.input_malloc if first time
    determines qh.JOGGLEmax if it was zero
    if qh.DELAUNAY
      computes the Delaunay projection of the joggled points

  notes:
    if qh.DELAUNAY, unnecessarily joggles the last coordinate
    the initial 'QJn' may be set larger than qh_JOGGLEmaxincrease

  design:
    if qh.DELAUNAY
      set qh.SCALElast for reduced precision errors
    if first call
      initialize qh.input_points to the original input points
      if qh.JOGGLEmax == 0
        determine default qh.JOGGLEmax
    else
      increase qh.JOGGLEmax according to qh.build_cnt
    joggle the input by adding a random number in [-qh.JOGGLEmax,qh.JOGGLEmax]
    if qh.DELAUNAY
      sets the Delaunay projection
*/
void qh_joggleinput(void) {
  int i, seed, size;
  coordT *coordp, *inputp;
  realT randr, randa, randb;

  if (!qh input_points) { /* first call */
    qh input_points= qh first_point;
    qh input_malloc= qh POINTSmalloc;
    size= qh num_points * qh hull_dim * (int)sizeof(coordT);
    if (!(qh first_point= (coordT *)qh_malloc((size_t)size))) {
      qh_fprintf(qh ferr, 6009, "qhull error: insufficient memory to joggle %d points\n",
          qh num_points);
      qh_errexit(qh_ERRmem, NULL, NULL);
    }
    qh POINTSmalloc= True;
    if (qh JOGGLEmax == 0.0) {
      qh JOGGLEmax= qh_detjoggle(qh input_points, qh num_points, qh hull_dim);
      qh_option("QJoggle", NULL, &qh JOGGLEmax);
    }
  }else {                 /* repeated call */
    if (!qh RERUN && qh build_cnt > qh_JOGGLEretry) {
      if (((qh build_cnt-qh_JOGGLEretry-1) % qh_JOGGLEagain) == 0) {
        realT maxjoggle= qh MAXwidth * qh_JOGGLEmaxincrease;
        if (qh JOGGLEmax < maxjoggle) {
          qh JOGGLEmax *= qh_JOGGLEincrease;
          minimize_(qh JOGGLEmax, maxjoggle);
        }
      }
    }
    qh_option("QJoggle", NULL, &qh JOGGLEmax);
  }
  if (qh build_cnt > 1 && qh JOGGLEmax > fmax_(qh MAXwidth/4, 0.1)) {
      qh_fprintf(qh ferr, 6010, "qhull input error (qh_joggleinput): 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_ERRinput, NULL, NULL);
  }
  /* for some reason, using qh ROTATErandom and qh_RANDOMseed does not repeat the run. Use 'TRn' instead */
  seed= qh_RANDOMint;
  qh_option("_joggle-seed", &seed, NULL);
  trace0((qh ferr, 6, "qh_joggleinput: joggle input by %4.4g with seed %d\n",
    qh JOGGLEmax, seed));
  inputp= qh input_points;
  coordp= qh first_point;
  randa= 2.0 * qh JOGGLEmax/qh_RANDOMmax;
  randb= -qh JOGGLEmax;
  size= qh num_points * qh hull_dim;
  for (i=size; i--; ) {
    randr= qh_RANDOMint;
    *(coordp++)= *(inputp++) + (randr * randa + randb);
  }
  if (qh DELAUNAY) {
    qh last_low= qh last_high= qh last_newhigh= REALmax;
    qh_setdelaunay(qh hull_dim, qh num_points, qh first_point);
  }
} /* joggleinput */

/*---------------------------------

  qh_maxabsval( normal, dim )
    return pointer to maximum absolute value of a dim vector
    returns NULL if dim=0
*/
realT *qh_maxabsval(realT *normal, int dim) {
  realT maxval= -REALmax;
  realT *maxp= NULL, *colp, absval;
  int k;

  for (k=dim, colp= normal; k--; colp++) {
    absval= fabs_(*colp);
    if (absval > maxval) {
      maxval= absval;
      maxp= colp;
    }
  }
  return maxp;
} /* maxabsval */


/*---------------------------------

  qh_maxmin( points, numpoints, dimension )
    return max/min points for each dimension
    determine max and min coordinates

  returns:
    returns a temporary set of max and min points
      may include duplicate points. Does not include qh.GOODpoint
    sets qh.NEARzero, qh.MAXabs_coord, qh.MAXsumcoord, qh.MAXwidth
         qh.MAXlastcoord, qh.MINlastcoord
    initializes qh.max_outside, qh.min_vertex, qh.WAScoplanar, qh.ZEROall_ok

  notes:
    loop duplicated in qh_detjoggle()

  design:
    initialize global precision variables
    checks definition of REAL...
    for each dimension
      for each point
        collect maximum and minimum point
      collect maximum of maximums and minimum of minimums
      determine qh.NEARzero for Gaussian Elimination
*/
setT *qh_maxmin(pointT *points, int numpoints, int dimension) {
  int k;
  realT maxcoord, temp;
  pointT *minimum, *maximum, *point, *pointtemp;
  setT *set;

  qh max_outside= 0.0;
  qh MAXabs_coord= 0.0;
  qh MAXwidth= -REALmax;
  qh MAXsumcoord= 0.0;
  qh min_vertex= 0.0;
  qh WAScoplanar= False;
  if (qh ZEROcentrum)
    qh ZEROall_ok= True;
  if (REALmin < REALepsilon && REALmin < REALmax && REALmin > -REALmax
  && REALmax > 0.0 && -REALmax < 0.0)
    ; /* all ok */
  else {
    qh_fprintf(qh ferr, 6011, "qhull error: one or more floating point constants in user.h are inconsistent. REALmin %g, -REALmax %g, 0.0, REALepsilon %g, REALmax %g\n",
          REALmin, -REALmax, REALepsilon, REALmax);
    qh_errexit(qh_ERRinput, NULL, NULL);
  }
  set= qh_settemp(2*dimension);
  trace1((qh ferr, 8082, "qh_maxmin: dim             min             max           width    nearzero  min-point  max-point\n"));
  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 MAXabs_coord;
    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, minimum);
    qh_setappend(&set, maximum);
    /* calculation of qh NEARzero is based on Golub & van Loan, 1983,
       Eq. 4.4-13 for "Gaussian elimination with complete pivoting".
       Golub & van Loan say that n^3 can be ignored and 10 be used in
       place of rho */
    qh NEARzero[k]= 80 * qh MAXsumcoord * REALepsilon;
    trace1((qh ferr, 8106, "           %3d % 14.8e % 14.8e % 14.8e  %4.4e  p%-9d p%-d\n",
            k, minimum[k], maximum[k], maximum[k]-minimum[k], qh NEARzero[k], qh_pointid(minimum), qh_pointid(maximum)));
    if (qh SCALElast && k == dimension-1)
      trace1((qh ferr, 8107, "           last coordinate scaled to (%4.4g, %4.4g), width %4.4e for option 'Qbb'\n",
            qh MAXabs_coord - qh MAXwidth, qh MAXabs_coord, qh MAXwidth));
  }
  if (qh IStracing >= 1)
    qh_printpoints(qh ferr, "qh_maxmin: found the max and min points (by dim):", set);
  return(set);
} /* maxmin */

/*---------------------------------

  qh_maxouter( )
    return maximum distance from facet to outer plane
    normally this is qh.max_outside+qh.DISTround
    does not include qh.JOGGLEmax

  see:
    qh_outerinner()

  notes:
    need to add another qh.DISTround if testing actual point with computation
    see qh_detmaxoutside for a qh_RATIO... target

  for joggle:
    qh_setfacetplane() updated qh.max_outer for Wnewvertexmax (max distance to vertex)
    need to use Wnewvertexmax since could have a coplanar point for a high
      facet that is replaced by a low facet
    need to add qh.JOGGLEmax if testing input points
*/
realT qh_maxouter(void) {
  realT dist;

  dist= fmax_(qh max_outside, qh DISTround);
  dist += qh DISTround;
  trace4((qh ferr, 4012, "qh_maxouter: max distance from facet to outer plane is %4.4g, qh.max_outside is %4.4g\n", dist, qh max_outside));
  return dist;
} /* maxouter */

/*---------------------------------

  qh_maxsimplex( dim, maxpoints, points, numpoints, simplex )
    determines maximum simplex for a set of points
    maxpoints is the subset of points with a min or max coordinate
    may start with points already in simplex
    skips qh.GOODpointp (assumes that it isn't in maxpoints)

  returns:
    simplex with dim+1 points

  notes:
    called by qh_initialvertices, qh_detvnorm, and qh_voronoi_center
    requires qh.MAXwidth to estimate determinate for each vertex
    assumes at least needed 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)
    create a simplex of dim+1 vertices as follows
      add point from maxpoints that maximizes the determinate of the point and the simplex vertices  
      if last point and maxdet/prevdet < qh_RATIOmaxsimplex (3.0e-2)
        flag maybe_falsenarrow
      if no maxpoint or maxnearzero or maybe_falsenarrow
        search all points for maximum determinate
        early exit if maybe_falsenarrow and !maxnearzero and maxdet > prevdet
*/
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, maybe_falsenarrow;
  int i, sizinit;
  realT maxdet= -1.0, prevdet= -1.0, det, mincoord= REALmax, maxcoord= -REALmax, mindet, ratio, targetdet;

  if (qh MAXwidth <= 0.0) {
    qh_fprintf(qh ferr, 6421, "qhull internal error (qh_maxsimplex): qh.MAXwidth required for qh_maxsimplex.  Used to estimate determinate\n");
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  sizinit= qh_setsize(*simplex);
  if (sizinit >= 2) {
    maxdet= pow(qh MAXwidth, sizinit - 1);
  }else {
    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;
        }
      }
    }
    maxdet= maxcoord - mincoord;
    qh_setunique(simplex, minx);
    if (qh_setsize(*simplex) < 2)
      qh_setunique(simplex, maxx);
    sizinit= qh_setsize(*simplex);
    if (sizinit < 2) {
      qh_joggle_restart("input has same x coordinate");
      if (zzval_(Zsetplane) > qh hull_dim+1) {
        qh_fprintf(qh ferr, 6012, "qhull precision error (qh_maxsimplex for voronoi_center): %d points with the same x coordinate %4.4g\n",
                 qh_setsize(maxpoints)+numpoints, mincoord);
        qh_errexit(qh_ERRprec, NULL, NULL);
      }else {
        qh_fprintf(qh ferr, 6013, "qhull input error: input is less than %d-dimensional since all points have the same x coordinate %4.4g\n",
                 qh hull_dim, mincoord);
        qh_errexit(qh_ERRinput, NULL, NULL);
      }
    }
  }
  for (i=sizinit; i < dim+1; i++) {
    prevdet= maxdet;
    maxpoint= NULL;
    maxdet= -1.0;
    FOREACHpoint_(maxpoints) {
      if (!qh_setin(*simplex, point) && point != maxpoint) {
        det= qh_detsimplex(point, *simplex, i, &nearzero); /* retests maxpoints if duplicate or multiple iterations */
        if ((det= fabs_(det)) > maxdet) {
          maxdet= det;
          maxpoint= point;
          maxnearzero= nearzero;
        }
      }
    }
    maybe_falsenarrow= False;
    ratio= 1.0;
    targetdet= prevdet * qh MAXwidth;
    mindet= 10 * qh_RATIOmaxsimplex * targetdet;
    if (maxdet > 0.0) {
      ratio= maxdet / targetdet;
      if (ratio < qh_RATIOmaxsimplex)
        maybe_falsenarrow= True;
    }
    if (!maxpoint || maxnearzero || maybe_falsenarrow) {
      zinc_(Zsearchpoints);
      if (!maxpoint) {
        trace0((qh ferr, 7, "qh_maxsimplex: searching all points for %d-th initial vertex, better than mindet %4.4g, targetdet %4.4g\n",
                i+1, mindet, targetdet));
      }else if (qh ALLpoints) {
        trace0((qh ferr, 30, "qh_maxsimplex: searching all points ('Qs') for %d-th initial vertex, better than p%d det %4.4g, targetdet %4.4g, ratio %4.4g\n",
                i+1, qh_pointid(maxpoint), maxdet, targetdet, ratio));
      }else if (maybe_falsenarrow) {
        trace0((qh ferr, 17, "qh_maxsimplex: searching all points for %d-th initial vertex, better than p%d det %4.4g and mindet %4.4g, ratio %4.4g\n",
                i+1, qh_pointid(maxpoint), maxdet, mindet, ratio));
      }else {
        trace0((qh ferr, 8, "qh_maxsimplex: searching all points for %d-th initial vertex, better than p%d det %2.2g and mindet %4.4g, targetdet %4.4g\n",
                i+1, qh_pointid(maxpoint), maxdet, mindet, targetdet));
      }
      FORALLpoint_(points, numpoints) {
        if (point == qh GOODpointp)
          continue;
        if (!qh_setin(maxpoints, point) && !qh_setin(*simplex, point)) {
          det= qh_detsimplex(point, *simplex, i, &nearzero);
          if ((det= fabs_(det)) > maxdet) {
            maxdet= det;
            maxpoint= point;
            maxnearzero= nearzero;
            if (!maxnearzero && !qh ALLpoints && maxdet > mindet)
              break;
          }
        }
      }
    } /* !maxpoint */
    if (!maxpoint) {
      qh_fprintf(qh ferr, 6014, "qhull internal error (qh_maxsimplex): not enough points available\n");
      qh_errexit(qh_ERRqhull, NULL, NULL);
    }
    qh_setappend(simplex, maxpoint);
    trace1((qh ferr, 1002, "qh_maxsimplex: selected point p%d for %d`th initial vertex, det=%4.4g, targetdet=%4.4g, mindet=%4.4g\n",
            qh_pointid(maxpoint), i+1, maxdet, prevdet * qh MAXwidth, mindet));
  } /* i */
} /* maxsimplex */

/*---------------------------------

  qh_minabsval( normal, dim )
    return minimum absolute value of a dim vector
*/
realT qh_minabsval(realT *normal, int dim) {
  realT minval= 0;
  realT maxval= 0;
  realT *colp;
  int k;

  for (k=dim, colp=normal; k--; colp++) {
    maximize_(maxval, *colp);
    minimize_(minval, *colp);
  }
  return fmax_(maxval, -minval);
} /* minabsval */


/*---------------------------------

  qh_mindif( vecA, vecB, dim )
    return index of min abs. difference of two vectors
*/
int qh_mindiff(realT *vecA, realT *vecB, int dim) {
  realT mindiff= REALmax, diff;
  realT *vecAp= vecA, *vecBp= vecB;
  int k, mink= 0;

  for (k=0; k < dim; k++) {
    diff= *vecAp++ - *vecBp++;
    diff= fabs_(diff);
    if (diff < mindiff) {
      mindiff= diff;
      mink= k;
    }
  }
  return mink;
} /* mindiff */



/*---------------------------------

  qh_orientoutside( facet  )
    make facet outside oriented via qh.interior_point

  returns:
    True if facet reversed orientation.
*/
boolT qh_orientoutside(facetT *facet) {
  int k;
  realT dist;

  qh_distplane(qh interior_point, facet, &dist);
  if (dist > 0) {
    for (k=qh hull_dim; k--; )
      facet->normal[k]= -facet->normal[k];
    facet->offset= -facet->offset;
    return True;
  }
  return False;
} /* orientoutside */

/*---------------------------------

  qh_outerinner( facet, outerplane, innerplane  )
    if facet and qh.maxoutdone (i.e., qh_check_maxout)
      returns outer and inner plane for facet
    else
      returns maximum outer and inner plane
    accounts for qh.JOGGLEmax

  see:
    qh_maxouter(), qh_check_bestdist(), qh_check_points()

  notes:
    outerplaner or innerplane may be NULL
    facet is const
    Does not error (QhullFacet)

    includes qh.DISTround for actual points
    adds another qh.DISTround if testing with floating point arithmetic
*/
void qh_outerinner(facetT *facet, realT *outerplane, realT *innerplane) {
  realT dist, mindist;
  vertexT *vertex, **vertexp;

  if (outerplane) {
    if (!qh_MAXoutside || !facet || !qh maxoutdone) {
      *outerplane= qh_maxouter();       /* includes qh.DISTround */
    }else { /* qh_MAXoutside ... */
#if qh_MAXoutside
      *outerplane= facet->maxoutside + qh DISTround;
#endif

    }
    if (qh JOGGLEmax < REALmax/2)
      *outerplane += qh JOGGLEmax * sqrt((realT)qh hull_dim);
  }
  if (innerplane) {
    if (facet) {
      mindist= REALmax;
      FOREACHvertex_(facet->vertices) {
        zinc_(Zdistio);
        qh_distplane(vertex->point, facet, &dist);
        minimize_(mindist, dist);
      }
      *innerplane= mindist - qh DISTround;
    }else
      *innerplane= qh min_vertex - qh DISTround;
    if (qh JOGGLEmax < REALmax/2)
      *innerplane -= qh JOGGLEmax * sqrt((realT)qh hull_dim);
  }
} /* outerinner */

/*---------------------------------

  qh_pointdist( point1, point2, dim )
    return distance between two points

  notes:
    returns distance squared if 'dim' is negative
*/
coordT qh_pointdist(pointT *point1, pointT *point2, int dim) {
  coordT dist, diff;
  int k;

  dist= 0.0;
  for (k= (dim > 0 ? dim : -dim); k--; ) {
    diff= *point1++ - *point2++;
    dist += diff * diff;
  }
  if (dim > 0)
    return(sqrt(dist));
  return dist;
} /* pointdist */


/*---------------------------------

  qh_printmatrix( fp, string, rows, numrow, numcol )
    print matrix to fp given by row vectors
    print string as header

  notes:
    print a vector by qh_printmatrix(fp, "", &vect, 1, len)
*/
void qh_printmatrix(FILE *fp, const char *string, realT **rows, int numrow, int numcol) {
  realT *rowp;
  realT r; /*bug fix*/
  int i,k;

  qh_fprintf(fp, 9001, "%s\n", string);
  for (i=0; i < numrow; i++) {
    rowp= rows[i];
    for (k=0; k < numcol; k++) {
      r= *rowp++;
      qh_fprintf(fp, 9002, "%6.3g ", r);
    }
    qh_fprintf(fp, 9003, "\n");
  }
} /* printmatrix */


/*---------------------------------

  qh_printpoints( fp, string, points )
    print pointids to fp for a set of points
    if string, prints string and 'p' point ids
*/
void qh_printpoints(FILE *fp, const char *string, setT *points) {
  pointT *point, **pointp;

  if (string) {
    qh_fprintf(fp, 9004, "%s", string);
    FOREACHpoint_(points)
      qh_fprintf(fp, 9005, " p%d", qh_pointid(point));
    qh_fprintf(fp, 9006, "\n");
  }else {
    FOREACHpoint_(points)
      qh_fprintf(fp, 9007, " %d", qh_pointid(point));
    qh_fprintf(fp, 9008, "\n");
  }
} /* printpoints */


/*---------------------------------

  qh_projectinput( )
    project input points using qh.lower_bound/upper_bound and qh DELAUNAY
    if qh.lower_bound[k]=qh.upper_bound[k]= 0,
      removes dimension k
    if halfspace intersection
      removes dimension k from qh.feasible_point
    input points in qh first_point, num_points, input_dim

  returns:
    new point array in qh first_point of qh hull_dim coordinates
    sets qh POINTSmalloc
    if qh DELAUNAY
      projects points to paraboloid
      lowbound/highbound is also projected
    if qh ATinfinity
      adds point "at-infinity"
    if qh POINTSmalloc
      frees old point array

  notes:
    checks that qh.hull_dim agrees with qh.input_dim, PROJECTinput, and DELAUNAY


  design:
    sets project[k] to -1 (delete), 0 (keep), 1 (add for Delaunay)
    determines newdim and newnum for qh hull_dim and qh num_points
    projects points to newpoints
    projects qh.lower_bound to itself
    projects qh.upper_bound to itself
    if qh DELAUNAY
      if qh ATINFINITY
        projects points to paraboloid
        computes "infinity" point as vertex average and 10% above all points
      else
        uses qh_setdelaunay to project points to paraboloid
*/
void qh_projectinput(void) {
  int k,i;
  int newdim= qh input_dim, newnum= qh num_points;
  signed char *project;
  int projectsize= (qh input_dim + 1) * (int)sizeof(*project);
  pointT *newpoints, *coord, *infinity;
  realT paraboloid, maxboloid= 0;

  project= (signed char *)qh_memalloc(projectsize);
  memset((char *)project, 0, (size_t)projectsize);
  for (k=0; k < qh input_dim; k++) {   /* skip Delaunay bound */
    if (qh lower_bound[k] == 0.0 && qh upper_bound[k] == 0.0) {
      project[k]= -1;
      newdim--;
    }
  }
  if (qh DELAUNAY) {
    project[k]= 1;
    newdim++;
    if (qh ATinfinity)
      newnum++;
  }
  if (newdim != qh hull_dim) {
    qh_memfree(project, projectsize);
    qh_fprintf(qh ferr, 6015, "qhull internal error (qh_projectinput): dimension after projection %d != hull_dim %d\n", newdim, qh hull_dim);
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  if (!(newpoints= qh temp_malloc= (coordT *)qh_malloc((size_t)(newnum * newdim) * sizeof(coordT)))) {
    qh_memfree(project, projectsize);
    qh_fprintf(qh ferr, 6016, "qhull error: insufficient memory to project %d points\n",
           qh num_points);
    qh_errexit(qh_ERRmem, NULL, NULL);
  }
  /* qh_projectpoints throws error if mismatched dimensions */
  qh_projectpoints(project, qh input_dim+1, qh first_point,
                    qh num_points, qh input_dim, newpoints, newdim);
  trace1((qh ferr, 1003, "qh_projectinput: updating lower and upper_bound\n"));
  qh_projectpoints(project, qh input_dim+1, qh lower_bound,
                    1, qh input_dim+1, qh lower_bound, newdim+1);
  qh_projectpoints(project, qh input_dim+1, qh upper_bound,
                    1, qh input_dim+1, qh upper_bound, newdim+1);
  if (qh HALFspace) {
    if (!qh feasible_point) {
      qh_memfree(project, projectsize);
      qh_fprintf(qh ferr, 6017, "qhull internal error (qh_projectinput): HALFspace defined without qh.feasible_point\n");
      qh_errexit(qh_ERRqhull, NULL, NULL);
    }
    qh_projectpoints(project, qh input_dim, qh feasible_point,
                      1, qh input_dim, qh feasible_point, newdim);
  }
  qh_memfree(project, projectsize);
  if (qh POINTSmalloc)
    qh_free(qh first_point);
  qh first_point= newpoints;
  qh POINTSmalloc= True;
  qh temp_malloc= NULL;
  if (qh DELAUNAY && qh ATinfinity) {
    coord= qh first_point;
    infinity= qh first_point + qh hull_dim * qh num_points;
    for (k=qh hull_dim-1; k--; )
      infinity[k]= 0.0;
    for (i=qh num_points; i--; ) {
      paraboloid= 0.0;
      for (k=0; k < qh hull_dim-1; k++) {
        paraboloid += *coord * *coord;
        infinity[k] += *coord;
        coord++;
      }
      *(coord++)= paraboloid;
      maximize_(maxboloid, paraboloid);
    }
    /* coord == infinity */
    for (k=qh hull_dim-1; k--; )
      *(coord++) /= qh num_points;
    *(coord++)= maxboloid * 1.1;
    qh num_points++;
    trace0((qh ferr, 9, "qh_projectinput: projected points to paraboloid for Delaunay\n"));
  }else if (qh DELAUNAY)  /* !qh ATinfinity */
    qh_setdelaunay(qh hull_dim, qh num_points, qh first_point);
} /* projectinput */


/*---------------------------------

  qh_projectpoints( project, n, points, numpoints, dim, newpoints, newdim )
    project points/numpoints/dim to newpoints/newdim
    if project[k] == -1
      delete dimension k
    if project[k] == 1
      add dimension k by duplicating previous column
    n is size of project

  notes:
    newpoints may be points if only adding dimension at end

  design:
    check that 'project' and 'newdim' agree
    for each dimension
      if project == -1
        skip dimension
      else
        determine start of column in newpoints
        determine start of column in points
          if project == +1, duplicate previous column
        copy dimension (column) from points to newpoints
*/
void qh_projectpoints(signed char *project, int n, realT *points,
        int numpoints, int dim, realT *newpoints, int newdim) {
  int testdim= dim, oldk=0, newk=0, i,j=0,k;
  realT *newp, *oldp;

  for (k=0; k < n; k++)
    testdim += project[k];
  if (testdim != newdim) {
    qh_fprintf(qh ferr, 6018, "qhull internal error (qh_projectpoints): newdim %d should be %d after projection\n",
      newdim, testdim);
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  for (j=0; j= dim)
          continue;
        oldp= points+oldk;
      }else
        oldp= points+oldk++;
      for (i=numpoints; i--; ) {
        *newp= *oldp;
        newp += newdim;
        oldp += dim;
      }
    }
    if (oldk >= dim)
      break;
  }
  trace1((qh ferr, 1004, "qh_projectpoints: projected %d points from dim %d to dim %d\n",
    numpoints, dim, newdim));
} /* projectpoints */


/*---------------------------------

  qh_rotateinput( rows )
    rotate input using row matrix
    input points given by qh first_point, num_points, hull_dim
    assumes rows[dim] is a scratch buffer
    if qh POINTSmalloc, overwrites input points, else mallocs a new array

  returns:
    rotated input
    sets qh POINTSmalloc

  design:
    see qh_rotatepoints
*/
void qh_rotateinput(realT **rows) {

  if (!qh POINTSmalloc) {
    qh first_point= qh_copypoints(qh first_point, qh num_points, qh hull_dim);
    qh POINTSmalloc= True;
  }
  qh_rotatepoints(qh first_point, qh num_points, qh hull_dim, rows);
}  /* rotateinput */

/*---------------------------------

  qh_rotatepoints( points, numpoints, dim, row )
    rotate numpoints points by a d-dim row matrix
    assumes rows[dim] is a scratch buffer

  returns:
    rotated points in place

  design:
    for each point
      for each coordinate
        use row[dim] to compute partial inner product
      for each coordinate
        rotate by partial inner product
*/
void qh_rotatepoints(realT *points, int numpoints, int dim, realT **row) {
  realT *point, *rowi, *coord= NULL, sum, *newval;
  int i,j,k;

  if (qh IStracing >= 1)
    qh_printmatrix(qh ferr, "qh_rotatepoints: rotate points by", row, dim, dim);
  for (point=points, j=numpoints; j--; point += dim) {
    newval= row[dim];
    for (i=0; i < dim; i++) {
      rowi= row[i];
      coord= point;
      for (sum=0.0, k=dim; k--; )
        sum += *rowi++ * *coord++;
      *(newval++)= sum;
    }
    for (k=dim; k--; )
      *(--coord)= *(--newval);
  }
} /* rotatepoints */


/*---------------------------------

  qh_scaleinput( )
    scale input points using qh low_bound/high_bound
    input points given by qh first_point, num_points, hull_dim
    if qh POINTSmalloc, overwrites input points, else mallocs a new array

  returns:
    scales coordinates of points to low_bound[k], high_bound[k]
    sets qh POINTSmalloc

  design:
    see qh_scalepoints
*/
void qh_scaleinput(void) {

  if (!qh POINTSmalloc) {
    qh first_point= qh_copypoints(qh first_point, qh num_points, qh hull_dim);
    qh POINTSmalloc= True;
  }
  qh_scalepoints(qh first_point, qh num_points, qh hull_dim,
       qh lower_bound, qh upper_bound);
}  /* scaleinput */

/*---------------------------------

  qh_scalelast( points, numpoints, dim, low, high, newhigh )
    scale last coordinate to [0.0, newhigh], for Delaunay triangulation
    input points given by points, numpoints, dim

  returns:
    changes scale of last coordinate from [low, high] to [0.0, newhigh]
    overwrites last coordinate of each point
    saves low/high/newhigh in qh.last_low, etc. for qh_setdelaunay()

  notes:
    to reduce precision issues, qh_scalelast makes the last coordinate similar to other coordinates
      the last coordinate for Delaunay triangulation is the sum of squares of input coordinates
      note that the range [0.0, newwidth] is wrong for narrow distributions with large positive coordinates (e.g., [995933.64, 995963.48])

    when called by qh_setdelaunay, low/high may not match the data passed to qh_setdelaunay

  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, newlow;
  int i;
  boolT nearzero= False;

  newlow= 0.0;
  trace4((qh ferr, 4013, "qh_scalelast: scale last coordinate from [%2.2g, %2.2g] to [%2.2g, %2.2g]\n",
    low, high, newlow, newhigh));
  qh last_low= low;
  qh last_high= high;
  qh last_newhigh= newhigh;
  scale= qh_divzero(newhigh - newlow, high - low,
                  qh MINdenom_1, &nearzero);
  if (nearzero) {
    if (qh DELAUNAY)
      qh_fprintf(qh ferr, 6019, "qhull input error (qh_scalelast): can not scale last coordinate to [%4.4g, %4.4g].  Input is cocircular or cospherical.   Use option 'Qz' to add a point at infinity.\n",
             newlow, newhigh);
    else
      qh_fprintf(qh ferr, 6020, "qhull input error (qh_scalelast): can not scale last coordinate to [%4.4g, %4.4g].  New bounds are too wide for compared to existing bounds [%4.4g, %4.4g] (width %4.4g)\n",
             newlow, newhigh, low, high, high-low);
    qh_errexit(qh_ERRinput, NULL, NULL);
  }
  shift= newlow - low * scale;
  coord= points + dim - 1;
  for (i=numpoints; i--; coord += dim)
    *coord= *coord * scale + shift;
} /* scalelast */

/*---------------------------------

  qh_scalepoints( points, numpoints, dim, newlows, newhighs )
    scale points to new lowbound and highbound
    retains old bound when newlow= -REALmax or newhigh= +REALmax

  returns:
    scaled points
    overwrites old points

  design:
    for each coordinate
      compute current low and high bound
      compute scale and shift factors
      scale all points
      enforce new low and high bound for all points
*/
void qh_scalepoints(pointT *points, int numpoints, int dim,
        realT *newlows, realT *newhighs) {
  int i,k;
  realT shift, scale, *coord, low, high, newlow, newhigh, mincoord, maxcoord;
  boolT nearzero= False;

  for (k=0; k < dim; k++) {
    newhigh= newhighs[k];
    newlow= newlows[k];
    if (newhigh > REALmax/2 && newlow < -REALmax/2)
      continue;
    low= REALmax;
    high= -REALmax;
    for (i=numpoints, coord=points+k; i--; coord += dim) {
      minimize_(low, *coord);
      maximize_(high, *coord);
    }
    if (newhigh > REALmax/2)
      newhigh= high;
    if (newlow < -REALmax/2)
      newlow= low;
    if (qh DELAUNAY && k == dim-1 && newhigh < newlow) {
      qh_fprintf(qh ferr, 6021, "qhull input error: 'Qb%d' or 'QB%d' inverts paraboloid since high bound %.2g < low bound %.2g\n",
               k, k, newhigh, newlow);
      qh_errexit(qh_ERRinput, NULL, NULL);
    }
    scale= qh_divzero(newhigh - newlow, high - low,
                  qh MINdenom_1, &nearzero);
    if (nearzero) {
      qh_fprintf(qh ferr, 6022, "qhull input error: %d'th dimension's new bounds [%2.2g, %2.2g] too wide for\nexisting bounds [%2.2g, %2.2g]\n",
              k, newlow, newhigh, low, high);
      qh_errexit(qh_ERRinput, NULL, NULL);
    }
    shift= (newlow * high - low * newhigh)/(high-low);
    coord= points+k;
    for (i=numpoints; i--; coord += dim)
      *coord= *coord * scale + shift;
    coord= points+k;
    if (newlow < newhigh) {
      mincoord= newlow;
      maxcoord= newhigh;
    }else {
      mincoord= newhigh;
      maxcoord= newlow;
    }
    for (i=numpoints; i--; coord += dim) {
      minimize_(*coord, maxcoord);  /* because of roundoff error */
      maximize_(*coord, mincoord);
    }
    trace0((qh ferr, 10, "qh_scalepoints: scaled %d'th coordinate [%2.2g, %2.2g] to [%.2g, %.2g] for %d points by %2.2g and shifted %2.2g\n",
      k, low, high, newlow, newhigh, numpoints, scale, shift));
  }
} /* scalepoints */


/*---------------------------------

  qh_setdelaunay( dim, count, points )
    project count points to dim-d paraboloid for Delaunay triangulation

    dim is one more than the dimension of the input set
    assumes dim is at least 3 (i.e., at least a 2-d Delaunay triangulation)

    points is a dim*count realT array.  The first dim-1 coordinates
    are the coordinates of the first input point.  array[dim] is
    the first coordinate of the second input point.  array[2*dim] is
    the first coordinate of the third input point.

    if qh.last_low defined (i.e., 'Qbb' called qh_scalelast)
      calls qh_scalelast to scale the last coordinate the same as the other points

  returns:
    for each point
      sets point[dim-1] to sum of squares of coordinates
    scale points to 'Qbb' if needed

  notes:
    to project one point, use
      qh_setdelaunay(qh hull_dim, 1, point)

    Do not use options 'Qbk', 'QBk', or 'QbB' since they scale
    the coordinates after the original projection.

*/
void qh_setdelaunay(int dim, int count, pointT *points) {
  int i, k;
  coordT *coordp, coord;
  realT paraboloid;

  trace0((qh ferr, 11, "qh_setdelaunay: project %d points to paraboloid for Delaunay triangulation\n", count));
  coordp= points;
  for (i=0; i < count; i++) {
    coord= *coordp++;
    paraboloid= coord*coord;
    for (k=dim-2; k--; ) {
      coord= *coordp++;
      paraboloid += coord*coord;
    }
    *coordp++= paraboloid;
  }
  if (qh last_low < REALmax/2)
    qh_scalelast(points, count, dim, qh last_low, qh last_high, qh last_newhigh);
} /* setdelaunay */


/*---------------------------------

  qh_sethalfspace( dim, coords, nextp, normal, offset, feasible )
    set point to dual of halfspace relative to feasible point
    halfspace is normal coefficients and offset.

  returns:
    false and prints error if feasible point is outside of hull
    overwrites coordinates for point at dim coords
    nextp= next point (coords)
    does not call qh_errexit

  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;
#ifndef qh_NOtrace
  if (qh IStracing >= 4) {
    qh_fprintf(qh ferr, 8021, "qh_sethalfspace: halfspace at offset %6.2g to point: ", *offset);
    for (k=dim, coordp=coords; k--; ) {
      r= *coordp++;
      qh_fprintf(qh ferr, 8022, " %6.2g", r);
    }
    qh_fprintf(qh ferr, 8023, "\n");
  }
#endif
  return True;
LABELerroroutside:
  feasiblep= feasible;
  normp= normal;
  qh_fprintf(qh ferr, 6023, "qhull input error: feasible point is not clearly inside halfspace\nfeasible point: ");
  for (k=dim; k--; )
    qh_fprintf(qh ferr, 8024, qh_REAL_1, r=*(feasiblep++));
  qh_fprintf(qh ferr, 8025, "\n     halfspace: ");
  for (k=dim; k--; )
    qh_fprintf(qh ferr, 8026, qh_REAL_1, r=*(normp++));
  qh_fprintf(qh ferr, 8027, "\n     at offset: ");
  qh_fprintf(qh ferr, 8028, qh_REAL_1, *offset);
  qh_fprintf(qh ferr, 8029, " and distance: ");
  qh_fprintf(qh ferr, 8030, qh_REAL_1, dist);
  qh_fprintf(qh ferr, 8031, "\n");
  return False;
} /* sethalfspace */

/*---------------------------------

  qh_sethalfspace_all( dim, count, halfspaces, feasible )
    generate dual for halfspace intersection with feasible point
    array of count halfspaces
      each halfspace is normal coefficients followed by offset
      the origin is inside the halfspace if the offset is negative
    feasible is a point inside all halfspaces (http://www.qhull.org/html/qhalf.htm#notes)

  returns:
    malloc'd array of count X dim-1 points

  notes:
    call before qh_init_B or qh_initqhull_globals
    free memory when done
    unused/untested code: please email bradb@shore.net if this works ok for you
    if using option 'Fp', qh.feasible_point must be set (e.g., to 'feasible')
    qh feasible_point is a malloc'd array that is freed by qh_freebuffers.

  design:
    see qh_sethalfspace
*/
coordT *qh_sethalfspace_all(int dim, int count, coordT *halfspaces, pointT *feasible) {
  int i, newdim;
  pointT *newpoints;
  coordT *coordp, *normalp, *offsetp;

  trace0((qh ferr, 12, "qh_sethalfspace_all: compute dual for halfspace intersection\n"));
  newdim= dim - 1;
  if (!(newpoints= (coordT *)qh_malloc((size_t)(count * newdim) * sizeof(coordT)))){
    qh_fprintf(qh ferr, 6024, "qhull error: insufficient memory to compute dual of %d halfspaces\n",
          count);
    qh_errexit(qh_ERRmem, NULL, NULL);
  }
  coordp= newpoints;
  normalp= halfspaces;
  for (i=0; i < count; i++) {
    offsetp= normalp + newdim;
    if (!qh_sethalfspace(newdim, coordp, &coordp, normalp, offsetp, feasible)) {
      qh_free(newpoints);  /* feasible is not inside halfspace as reported by qh_sethalfspace */
      qh_fprintf(qh ferr, 8032, "The halfspace was at index %d\n", i);
      qh_errexit(qh_ERRinput, NULL, NULL);
    }
    normalp= offsetp + 1;
  }
  return newpoints;
} /* sethalfspace_all */


/*---------------------------------

  qh_sharpnewfacets( )

  returns:
    true if could be an acute angle (facets in different quadrants)

  notes:
    for qh_findbest

  design:
    for all facets on qh.newfacet_list
      if two facets are in different quadrants
        set issharp
*/
boolT qh_sharpnewfacets(void) {
  facetT *facet;
  boolT issharp= False;
  int *quadrant, k;

  quadrant= (int *)qh_memalloc(qh hull_dim * (int)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 * (int)sizeof(int));
  trace3((qh ferr, 3001, "qh_sharpnewfacets: %d\n", issharp));
  return issharp;
} /* sharpnewfacets */

/*---------------------------------

  qh_vertex_bestdist( vertices )
  qh_vertex_bestdist2( vertices, vertexp, vertexp2 )
    return nearest distance between vertices
    optionally returns vertex and vertex2

  notes:
    called by qh_partitioncoplanar, qh_mergefacet, qh_check_maxout, qh_checkpoint
*/
coordT qh_vertex_bestdist(setT *vertices) {
  vertexT *vertex, *vertex2;

  return qh_vertex_bestdist2(vertices, &vertex, &vertex2);
} /* vertex_bestdist */

coordT qh_vertex_bestdist2(setT *vertices, vertexT **vertexp/*= NULL*/, vertexT **vertexp2/*= NULL*/) {
  vertexT *vertex, *vertexA, *bestvertex= NULL, *bestvertex2= NULL;
  coordT dist, bestdist= REALmax;
  int k, vertex_i, vertex_n;

  FOREACHvertex_i_(vertices) {
    for (k= vertex_i+1; k < vertex_n; k++) {
      vertexA= SETelemt_(vertices, k, vertexT);
      dist= qh_pointdist(vertex->point, vertexA->point, -qh hull_dim);
      if (dist < bestdist) {
        bestdist= dist;
        bestvertex= vertex;
        bestvertex2= vertexA;
      }
    }
  }
  *vertexp= bestvertex;
  *vertexp2= bestvertex2;
  return sqrt(bestdist);
} /* vertex_bestdist */

/*---------------------------------

  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 (qh_memalloc)
    if non-simplicial,
      returns center for max simplex of points

  notes:
    only called by qh_facetcenter
    from Bowyer & Woodwark, A Programmer's Geometry, 1983, p. 65

  design:
    if non-simplicial
      determine max simplex for points
    translate point0 of simplex to origin
    compute sum of squares of diagonal
    compute determinate
    compute Voronoi center (see Bowyer & Woodwark)
*/
pointT *qh_voronoi_center(int dim, setT *points) {
  pointT *point, **pointp, *point0;
  pointT *center= (pointT *)qh_memalloc(qh center_size);
  setT *simplex;
  int i, j, k, size= qh_setsize(points);
  coordT *gmcoord;
  realT *diffp, sum2, *sum2row, *sum2p, det, factor;
  boolT nearzero, infinite;

  if (size == dim+1)
    simplex= points;
  else if (size < dim+1) {
    qh_memfree(center, qh center_size);
    qh_fprintf(qh ferr, 6025, "qhull internal error (qh_voronoi_center):  need at least %d points to construct a Voronoi center\n",
             dim+1);
    qh_errexit(qh_ERRqhull, NULL, NULL);
    simplex= points;  /* never executed -- avoids warning */
  }else {
    simplex= qh_settemp(dim+1);
    qh_maxsimplex(dim, points, NULL, 0, &simplex);
  }
  point0= SETfirstt_(simplex, pointT);
  gmcoord= qh gm_matrix;
  for (k=0; k < dim; k++) {
    qh gm_row[k]= gmcoord;
    FOREACHpoint_(simplex) {
      if (point != point0)
        *(gmcoord++)= point[k] - point0[k];
    }
  }
  sum2row= gmcoord;
  for (i=0; i < dim; i++) {
    sum2= 0.0;
    for (k=0; k < dim; k++) {
      diffp= qh gm_row[k] + i;
      sum2 += *diffp * *diffp;
    }
    *(gmcoord++)= sum2;
  }
  det= qh_determinant(qh gm_row, dim, &nearzero);
  factor= qh_divzero(0.5, det, qh MINdenom, &infinite);
  if (infinite) {
    for (k=dim; k--; )
      center[k]= qh_INFINITE;
    if (qh IStracing)
      qh_printpoints(qh ferr, "qh_voronoi_center: at infinity for ", simplex);
  }else {
    for (i=0; i < dim; i++) {
      gmcoord= qh gm_matrix;
      sum2p= sum2row;
      for (k=0; k < dim; k++) {
        qh gm_row[k]= gmcoord;
        if (k == i) {
          for (j=dim; j--; )
            *(gmcoord++)= *sum2p++;
        }else {
          FOREACHpoint_(simplex) {
            if (point != point0)
              *(gmcoord++)= point[k] - point0[k];
          }
        }
      }
      center[i]= qh_determinant(qh gm_row, dim, &nearzero)*factor + point0[i];
    }
#ifndef qh_NOtrace
    if (qh IStracing >= 3) {
      qh_fprintf(qh ferr, 3061, "qh_voronoi_center: det %2.2g factor %2.2g ", det, factor);
      qh_printmatrix(qh ferr, "center:", ¢er, 1, dim);
      if (qh IStracing >= 5) {
        qh_printpoints(qh ferr, "points", simplex);
        FOREACHpoint_(simplex)
          qh_fprintf(qh ferr, 8034, "p%d dist %.2g, ", qh_pointid(point),
                   qh_pointdist(point, center, dim));
        qh_fprintf(qh ferr, 8035, "\n");
      }
    }
#endif
  }
  if (simplex != points)
    qh_settempfree(&simplex);
  return center;
} /* voronoi_center */

qhull-2020.2/src/libqhull/global.c0000644060175106010010000024533313724257514015221 0ustar  bbarber
/*
  ---------------------------------

   global.c
   initializes all the globals of the qhull application

   see README

   see libqhull.h for qh.globals and function prototypes

   see qhull_a.h for internal functions

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull/global.c#16 $$Change: 3037 $
   $DateTime: 2020/09/03 17:28:32 $$Author: bbarber $
 */

#include "qhull_a.h"

/*========= qh definition -- globals defined in libqhull.h =======================*/

#if qh_QHpointer
qhT *qh_qh= NULL;       /* pointer to all global variables */
#else
qhT qh_qh;              /* all global variables.
                           Add "= {0}" if this causes a compiler error.
                           Also qh_qhstat in stat.c and qhmem in mem.c.  */
#endif

/*----------------------------------

  qh_version
    version string by year and date
    qh_version2 for Unix users and -V

    the revision increases on code changes only

  notes:
    change date:    Changes.txt, Announce.txt, index.htm, README.txt,
                    qhull-news.html, Eudora signatures, CMakeLists.txt
    change version: README.txt, qh-get.htm, File_id.diz, Makefile.txt, CMakeLists.txt
    check that CMakeLists.txt @version is the same as qh_version2
    change year:    Copying.txt
    check download size
    recompile user_eg.c, rbox.c, libqhull.c, qconvex.c, qdelaun.c qvoronoi.c, qhalf.c, testqset.c
*/

const char qh_version[]= "2020.2 2020/08/31";
const char qh_version2[]= "qhull 8.0.2 (2020.2 2020/08/31)";

/*---------------------------------

  qh_appendprint( printFormat )
    append printFormat to qh.PRINTout unless already defined
*/
void qh_appendprint(qh_PRINT format) {
  int i;

  for (i=0; i < qh_PRINTEND; i++) {
    if (qh PRINTout[i] == format && format != qh_PRINTqhull)
      break;
    if (!qh PRINTout[i]) {
      qh PRINTout[i]= format;
      break;
    }
  }
} /* appendprint */

/*---------------------------------

  qh_checkflags( commandStr, hiddenFlags )
    errors if commandStr contains hiddenFlags
    hiddenFlags starts and ends with a space and is space delimited (checked)

  notes:
    ignores first word (e.g., "qconvex i")
    use qh_strtol/strtod since strtol/strtod may or may not skip trailing spaces

  see:
    qh_initflags() initializes Qhull according to commandStr
*/
void qh_checkflags(char *command, char *hiddenflags) {
  char *s= command, *t, *chkerr; /* qh_skipfilename is non-const */
  char key, opt, prevopt;
  char chkkey[]=  "   ";    /* check one character options ('s') */
  char chkopt[]=  "    ";   /* check two character options ('Ta') */
  char chkopt2[]= "     ";  /* check three character options ('Q12') */
  boolT waserr= False;

  if (*hiddenflags != ' ' || hiddenflags[strlen(hiddenflags)-1] != ' ') {
    qh_fprintf(qh ferr, 6026, "qhull internal error (qh_checkflags): hiddenflags must start and end with a space: \"%s\"\n", hiddenflags);
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  if (strpbrk(hiddenflags, ",\n\r\t")) {
    qh_fprintf(qh ferr, 6027, "qhull internal error (qh_checkflags): hiddenflags contains commas, newlines, or tabs: \"%s\"\n", hiddenflags);
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  while (*s && !isspace(*s))  /* skip program name */
    s++;
  while (*s) {
    while (*s && isspace(*s))
      s++;
    if (*s == '-')
      s++;
    if (!*s)
      break;
    key= *s++;
    chkerr= NULL;
    if (key == 'T' && (*s == 'I' || *s == 'O')) {  /* TI or TO 'file name' */
      s= qh_skipfilename(++s);
      continue;
    }
    chkkey[1]= key;
    if (strstr(hiddenflags, chkkey)) {
      chkerr= chkkey;
    }else if (isupper(key)) {
      opt= ' ';
      prevopt= ' ';
      chkopt[1]= key;
      chkopt2[1]= key;
      while (!chkerr && *s && !isspace(*s)) {
        opt= *s++;
        if (isalpha(opt)) {
          chkopt[2]= opt;
          if (strstr(hiddenflags, chkopt))
            chkerr= chkopt;
          if (prevopt != ' ') {
            chkopt2[2]= prevopt;
            chkopt2[3]= opt;
            if (strstr(hiddenflags, chkopt2))
              chkerr= chkopt2;
          }
        }else if (key == 'Q' && isdigit(opt) && prevopt != 'b'
              && (prevopt == ' ' || islower(prevopt))) {
            if (isdigit(*s)) {  /* Q12 */
              chkopt2[2]= opt;
              chkopt2[3]= *s++;
              if (strstr(hiddenflags, chkopt2))
                chkerr= chkopt2;
            }else {
              chkopt[2]= opt;
              if (strstr(hiddenflags, chkopt))
                chkerr= chkopt;
            }
        }else {
          qh_strtod(s-1, &t);
          if (s < t)
            s= t;
        }
        prevopt= opt;
      }
    }
    if (chkerr) {
      *chkerr= '\'';
      chkerr[strlen(chkerr)-1]=  '\'';
      qh_fprintf(qh ferr, 6029, "qhull option error: option %s is not used with this program.\n             It may be used with qhull.\n", chkerr);
      waserr= True;
    }
  }
  if (waserr)
    qh_errexit(qh_ERRinput, NULL, NULL);
} /* checkflags */

/*---------------------------------

  qh_clear_outputflags( )
    Clear output flags for QhullPoints
*/
void qh_clear_outputflags(void) {
  int i,k;

  qh ANNOTATEoutput= False;
  qh DOintersections= False;
  qh DROPdim= -1;
  qh FORCEoutput= False;
  qh GETarea= False;
  qh GOODpoint= 0;
  qh GOODpointp= NULL;
  qh GOODthreshold= False;
  qh GOODvertex= 0;
  qh GOODvertexp= NULL;
  qh IStracing= 0;
  qh KEEParea= False;
  qh KEEPmerge= False;
  qh KEEPminArea= REALmax;
  qh PRINTcentrums= False;
  qh PRINTcoplanar= False;
  qh PRINTdots= False;
  qh PRINTgood= False;
  qh PRINTinner= False;
  qh PRINTneighbors= False;
  qh PRINTnoplanes= False;
  qh PRINToptions1st= False;
  qh PRINTouter= False;
  qh PRINTprecision= True;
  qh PRINTridges= False;
  qh PRINTspheres= False;
  qh PRINTstatistics= False;
  qh PRINTsummary= False;
  qh PRINTtransparent= False;
  qh SPLITthresholds= False;
  qh TRACElevel= 0;
  qh TRInormals= False;
  qh USEstdout= False;
  qh VERIFYoutput= False;
  for (k=qh input_dim+1; k--; ) {  /* duplicated in qh_initqhull_buffers and qh_clear_outputflags */
    qh lower_threshold[k]= -REALmax;
    qh upper_threshold[k]= REALmax;
    qh lower_bound[k]= -REALmax;
    qh upper_bound[k]= REALmax;
  }

  for (i=0; i < qh_PRINTEND; i++) {
    qh PRINTout[i]= qh_PRINTnone;
  }

  if (!qh qhull_commandsiz2)
      qh qhull_commandsiz2= (int)strlen(qh qhull_command); /* WARN64 */
  else {
      qh qhull_command[qh qhull_commandsiz2]= '\0';
  }
  if (!qh qhull_optionsiz2)
    qh qhull_optionsiz2= (int)strlen(qh qhull_options);  /* WARN64 */
  else {
    qh qhull_options[qh qhull_optionsiz2]= '\0';
    qh qhull_optionlen= qh_OPTIONline;  /* start a new line */
  }
} /* clear_outputflags */

/*---------------------------------

  qh_clock()
    return user CPU time in 100ths (qh_SECtick)
    only defined for qh_CLOCKtype == 2

  notes:
    use first value to determine time 0
    from Stevens '92 8.15
*/
unsigned long qh_clock(void) {

#if (qh_CLOCKtype == 2)
  struct tms time;
  static long clktck;  /* initialized first call and never updated */
  double ratio, cpu;
  unsigned long ticks;

  if (!clktck) {
    if ((clktck= sysconf(_SC_CLK_TCK)) < 0) {
      qh_fprintf(qh ferr, 6030, "qhull internal error (qh_clock): sysconf() failed.  Use qh_CLOCKtype 1 in user.h\n");
      qh_errexit(qh_ERRqhull, NULL, NULL);
    }
  }
  if (times(&time) == -1) {
    qh_fprintf(qh ferr, 6031, "qhull internal error (qh_clock): times() failed.  Use qh_CLOCKtype 1 in user.h\n");
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  ratio= qh_SECticks / (double)clktck;
  ticks= time.tms_utime * ratio;
  return ticks;
#else
  qh_fprintf(qh ferr, 6032, "qhull internal error (qh_clock): use qh_CLOCKtype 2 in user.h\n");
  qh_errexit(qh_ERRqhull, NULL, NULL); /* never returns */
  return 0;
#endif
} /* clock */

/*---------------------------------

  qh_freebuffers()
    free up global memory buffers

  notes:
    must match qh_initbuffers()
*/
void qh_freebuffers(void) {

  trace5((qh ferr, 5001, "qh_freebuffers: freeing up global memory buffers\n"));
  /* allocated by qh_initqhull_buffers */
  qh_setfree(&qh other_points);
  qh_setfree(&qh del_vertices);
  qh_setfree(&qh coplanarfacetset);
  qh_memfree(qh NEARzero, qh hull_dim * (int)sizeof(realT));
  qh_memfree(qh lower_threshold, (qh input_dim+1) * (int)sizeof(realT));
  qh_memfree(qh upper_threshold, (qh input_dim+1) * (int)sizeof(realT));
  qh_memfree(qh lower_bound, (qh input_dim+1) * (int)sizeof(realT));
  qh_memfree(qh upper_bound, (qh input_dim+1) * (int)sizeof(realT));
  qh_memfree(qh gm_matrix, (qh hull_dim+1) * qh hull_dim * (int)sizeof(coordT));
  qh_memfree(qh gm_row, (qh hull_dim+1) * (int)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;

  if (qh line)                /* allocated by qh_readinput, freed if no error */
    qh_free(qh line);
  if (qh half_space)
    qh_free(qh half_space);
  if (qh temp_malloc)
    qh_free(qh temp_malloc);
  if (qh feasible_point)      /* allocated by qh_readfeasible */
    qh_free(qh feasible_point);
  if (qh feasible_string)     /* allocated by qh_initflags */
    qh_free(qh feasible_string);
  qh line= qh feasible_string= NULL;
  qh half_space= qh feasible_point= qh temp_malloc= NULL;
  /* usually allocated by qh_readinput */
  if (qh first_point && qh POINTSmalloc) {
    qh_free(qh first_point);
    qh first_point= NULL;
  }
  if (qh input_points && qh input_malloc) { /* set by qh_joggleinput */
    qh_free(qh input_points);
    qh input_points= NULL;
  }
  trace5((qh ferr, 5002, "qh_freebuffers: finished\n"));
} /* freebuffers */


/*---------------------------------

  qh_freebuild( allmem )
    free global memory used by qh_initbuild and qh_buildhull
    if !allmem,
      does not free short memory (e.g., facetT, freed by qh_memfreeshort)

  design:
    free centrums
    free each vertex
    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 sets
    free temporary sets
*/
void qh_freebuild(boolT allmem) {
  facetT *facet, *previousfacet= NULL;
  vertexT *vertex, *previousvertex= NULL;
  ridgeT *ridge, **ridgep, *previousridge= NULL;
  mergeT *merge, **mergep;
  int newsize;
  boolT freeall;

  /* free qhT global sets first, includes references from qh_buildhull */
  trace5((qh ferr, 5004, "qh_freebuild: free global sets\n"));
  FOREACHmerge_(qh facet_mergeset)  /* usually empty */
    qh_memfree(merge, (int)sizeof(mergeT));
  FOREACHmerge_(qh degen_mergeset)  /* usually empty */
    qh_memfree(merge, (int)sizeof(mergeT));
  FOREACHmerge_(qh vertex_mergeset)  /* usually empty */
    qh_memfree(merge, (int)sizeof(mergeT));
  qh facet_mergeset= NULL;  /* temp set freed by qh_settempfree_all */
  qh degen_mergeset= NULL;  /* temp set freed by qh_settempfree_all */
  qh vertex_mergeset= NULL;  /* temp set freed by qh_settempfree_all */
  qh_setfree(&(qh hash_table));
  trace5((qh ferr, 5003, "qh_freebuild: free temporary sets (qh_settempfree_all)\n"));
  qh_settempfree_all();
  trace1((qh ferr, 1005, "qh_freebuild: free memory from qh_inithull and qh_buildhull\n"));
  if (qh del_vertices)
    qh_settruncate(qh del_vertices, 0);
  if (allmem) {
    while ((vertex= qh vertex_list)) {
      if (vertex->next)
        qh_delvertex(vertex);
      else {
        qh_memfree(vertex, (int)sizeof(vertexT)); /* sentinel */
        qh newvertex_list= qh vertex_list= NULL;
        break;
      }
      previousvertex= vertex; /* in case of memory fault */
      QHULL_UNUSED(previousvertex)
    }
  }else if (qh VERTEXneighbors) {
    FORALLvertices
      qh_setfreelong(&(vertex->neighbors));
  }
  qh VERTEXneighbors= False;
  qh GOODclosest= NULL;
  if (allmem) {
    FORALLfacets {
      FOREACHridge_(facet->ridges)
        ridge->seen= False;
    }
    while ((facet= qh facet_list)) {
      if (!facet->newfacet || !qh NEWtentative || qh_setsize(facet->ridges) > 1) { /* skip tentative horizon ridges */
        trace4((qh ferr, 4095, "qh_freebuild: delete the previously-seen ridges of f%d\n", facet->id));
        FOREACHridge_(facet->ridges) {
          if (ridge->seen)
            qh_delridge(ridge);
          else
            ridge->seen= True;
          previousridge= ridge; /* in case of memory fault */
          QHULL_UNUSED(previousridge)
        }
      }
      qh_setfree(&(facet->outsideset));
      qh_setfree(&(facet->coplanarset));
      qh_setfree(&(facet->neighbors));
      qh_setfree(&(facet->ridges));
      qh_setfree(&(facet->vertices));
      if (facet->next)
        qh_delfacet(facet);
      else {
        qh_memfree(facet, (int)sizeof(facetT));
        qh visible_list= qh newfacet_list= qh facet_list= NULL;
      }
      previousfacet= facet; /* in case of memory fault */
      QHULL_UNUSED(previousfacet)
    }
  }else {
    freeall= True;
    if (qh_setlarger_quick(qh hull_dim + 1, &newsize))
      freeall= False;
    FORALLfacets {
      qh_setfreelong(&(facet->outsideset));
      qh_setfreelong(&(facet->coplanarset));
      if (!facet->simplicial || freeall) {
        qh_setfreelong(&(facet->neighbors));
        qh_setfreelong(&(facet->ridges));
        qh_setfreelong(&(facet->vertices));
      }
    }
  }
  /* qh internal constants */
  qh_memfree(qh interior_point, qh normal_size);
  qh interior_point= NULL;
} /* freebuild */

/*---------------------------------

  qh_freeqhull( allmem )
    see qh_freeqhull2
    if qh_QHpointer, frees qh_qh
*/
void qh_freeqhull(boolT allmem) {
    qh_freeqhull2(allmem);
#if qh_QHpointer
    qh_free(qh_qh);
    qh_qh= NULL;
#endif
}

/*---------------------------------

qh_freeqhull2( allmem )
  free global memory and set qhT to 0
  if !allmem,
    does not free short memory (freed by qh_memfreeshort unless qh_NOmem)

notes:
  sets qh.NOerrexit in case caller forgets to
  Does not throw errors

see:
  see qh_initqhull_start2()

design:
  free global and temporary memory from qh_initbuild and qh_buildhull
  free buffers
  free statistics
*/
void qh_freeqhull2(boolT allmem) {

  qh NOerrexit= True;  /* no more setjmp since called at exit and ~QhullQh */
  trace1((qh ferr, 1006, "qh_freeqhull: free global memory\n"));
  qh_freebuild(allmem);
  qh_freebuffers();
  qh_freestatistics();
#if qh_QHpointer
  memset((char *)qh_qh, 0, sizeof(qhT));
  /* qh_qh freed by caller, qh_freeqhull() */
#else
  memset((char *)&qh_qh, 0, sizeof(qhT));
#endif
  qh NOerrexit= True;
} /* freeqhull2 */

/*---------------------------------

  qh_init_A( infile, outfile, errfile, argc, argv )
    initialize memory and stdio files
    convert input options to option string (qh.qhull_command)

  notes:
    infile may be NULL if qh_readpoints() is not called

    errfile should always be defined.  It is used for reporting
    errors.  outfile is used for output and format options.

    argc/argv may be 0/NULL

    called before error handling initialized
    qh_errexit() may not be used
*/
void qh_init_A(FILE *infile, FILE *outfile, FILE *errfile, int argc, char *argv[]) {
  qh_meminit(errfile);
  qh_initqhull_start(infile, outfile, errfile);
  qh_init_qhull_command(argc, argv);
} /* init_A */

/*---------------------------------

  qh_init_B( points, numpoints, dim, ismalloc )
    initialize globals for points array

    points has numpoints dim-dimensional points
      points[0] is the first coordinate of the first point
      points[1] is the second coordinate of the first point
      points[dim] is the first coordinate of the second point

    ismalloc=True
      Qhull will call qh_free(points) on exit or input transformation
    ismalloc=False
      Qhull will allocate a new point array if needed for input transformation

    qh.qhull_command
      is the option string.
      It is defined by qh_init_B(), qh_qhull_command(), or qh_initflags

  returns:
    if qh.PROJECTinput or (qh.DELAUNAY and qh.PROJECTdelaunay)
      projects the input to a new point array

        if qh.DELAUNAY,
          qh.hull_dim is increased by one
        if qh.ATinfinity,
          qh_projectinput adds point-at-infinity for Delaunay tri.

    if qh.SCALEinput
      changes the upper and lower bounds of the input, see qh_scaleinput

    if qh.ROTATEinput
      rotates the input by a random rotation, see qh_rotateinput
      if qh.DELAUNAY
        rotates about the last coordinate

  notes:
    called after points are defined
    qh_errexit() may be used
*/
void qh_init_B(coordT *points, int numpoints, int dim, boolT ismalloc) {
  qh_initqhull_globals(points, numpoints, dim, ismalloc);
  if (qhmem.LASTsize == 0)
    qh_initqhull_mem();
  /* mem.c and qset.c are initialized */
  qh_initqhull_buffers();
  qh_initthresholds(qh qhull_command);
  if (qh PROJECTinput || (qh DELAUNAY && qh PROJECTdelaunay))
    qh_projectinput();
  if (qh SCALEinput)
    qh_scaleinput();
  if (qh ROTATErandom >= 0) {
    qh_randommatrix(qh gm_matrix, qh hull_dim, qh gm_row);
    if (qh DELAUNAY) {
      int k, lastk= qh hull_dim-1;
      for (k=0; k < lastk; k++) {
        qh gm_row[k][lastk]= 0.0;
        qh gm_row[lastk][k]= 0.0;
      }
      qh gm_row[lastk][lastk]= 1.0;
    }
    qh_gram_schmidt(qh hull_dim, qh gm_row);
    qh_rotateinput(qh gm_row);
  }
} /* init_B */

/*---------------------------------

  qh_init_qhull_command( argc, argv )
    build qh.qhull_command from argc/argv
    Calls qh_exit if qhull_command is too short

  returns:
    a space-delimited string of options (just as typed)

  notes:
    makes option string easy to input and output

    argc/argv may be 0/NULL
*/
void qh_init_qhull_command(int argc, char *argv[]) {

  if (!qh_argv_to_command(argc, argv, qh qhull_command, (int)sizeof(qh qhull_command))){
    /* Assumes qh.ferr is defined. */
    qh_fprintf(qh ferr, 6033, "qhull input error: more than %d characters in command line.\n",
          (int)sizeof(qh qhull_command));
    qh_exit(qh_ERRinput);  /* error reported, can not use qh_errexit */
  }
} /* init_qhull_command */

/*---------------------------------

  qh_initflags( commandStr )
    set flags and initialized constants from commandStr
    calls qh_exit() if qh.NOerrexit

  returns:
    sets qh.qhull_command to command if needed

  notes:
    ignores first word (e.g., 'qhull' in "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-delimited option group
      if top-level option
        check syntax
        append appropriate option to option string
        set appropriate global variable or append printFormat to print options
      else
        for each sub-option
          check syntax
          append appropriate 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, *lastwarning= NULL;
  boolT isgeom= False, wasproject;
  realT r;

  if(qh NOerrexit){
    qh_fprintf(qh ferr, 6245, "qhull internal error (qh_initflags): qh.NOerrexit was not cleared before calling qh_initflags().  It should be cleared after setjmp().  Exit qhull.\n");
    qh_exit(qh_ERRqhull);
  }
#ifdef qh_RANDOMdist
  qh RANDOMfactor= qh_RANDOMdist;
  qh_option("Random-qh_RANDOMdist", NULL, &qh RANDOMfactor);
  qh RANDOMdist= True;
#endif
  if (command <= &qh qhull_command[0] || command > &qh qhull_command[0] + sizeof(qh qhull_command)) {
    if (command != &qh qhull_command[0]) {
      *qh qhull_command= '\0';
      strncat(qh qhull_command, command, sizeof(qh qhull_command)-strlen(qh qhull_command)-1);
    }
    while (*s && !isspace(*s))  /* skip program name */
      s++;
  }
  if (qh_QHpointer)
    qh_option("qh_QHpointer", NULL, NULL);
  while (*s) {
    while (*s && isspace(*s))
      s++;
    if (*s == '-')
      s++;
    if (!*s)
      break;
    prev_s= s;
    switch (*s++) {
    case 'd':
      qh_option("delaunay", NULL, NULL);
      qh DELAUNAY= True;
      break;
    case 'f':
      qh_option("facets", NULL, NULL);
      qh_appendprint(qh_PRINTfacets);
      break;
    case 'i':
      qh_option("incidence", NULL, NULL);
      qh_appendprint(qh_PRINTincidences);
      break;
    case 'm':
      qh_option("mathematica", NULL, NULL);
      qh_appendprint(qh_PRINTmathematica);
      break;
    case 'n':
      qh_option("normals", NULL, NULL);
      qh_appendprint(qh_PRINTnormals);
      break;
    case 'o':
      qh_option("offFile", NULL, NULL);
      qh_appendprint(qh_PRINToff);
      break;
    case 'p':
      qh_option("points", NULL, NULL);
      qh_appendprint(qh_PRINTpoints);
      break;
    case 's':
      qh_option("summary", NULL, NULL);
      qh PRINTsummary= True;
      break;
    case 'v':
      qh_option("voronoi", NULL, NULL);
      qh VORONOI= True;
      qh DELAUNAY= True;
      break;
    case 'A':
      if (!isdigit(*s) && *s != '.' && *s != '-') {
        qh_fprintf(qh ferr, 7002, "qhull input warning: no maximum cosine angle given for option 'An'.  A1.0 is coplanar\n");
        lastwarning= s-1;
      }else {
        if (*s == '-') {
          qh premerge_cos= -qh_strtod(s, &s);
          qh_option("Angle-premerge-", NULL, &qh premerge_cos);
          qh PREmerge= True;
        }else {
          qh postmerge_cos= qh_strtod(s, &s);
          qh_option("Angle-postmerge", NULL, &qh postmerge_cos);
          qh POSTmerge= True;
        }
        qh MERGING= True;
      }
      break;
    case 'C':
      if (!isdigit(*s) && *s != '.' && *s != '-') {
        qh_fprintf(qh ferr, 7003, "qhull input warning: no centrum radius given for option 'Cn'\n");
        lastwarning= s-1;
      }else {
        if (*s == '-') {
          qh premerge_centrum= -qh_strtod(s, &s);
          qh_option("Centrum-premerge-", NULL, &qh premerge_centrum);
          qh PREmerge= True;
        }else {
          qh postmerge_centrum= qh_strtod(s, &s);
          qh_option("Centrum-postmerge", NULL, &qh postmerge_centrum);
          qh POSTmerge= True;
        }
        qh MERGING= True;
      }
      break;
    case 'E':
      if (*s == '-') {
        qh_fprintf(qh ferr, 6363, "qhull option error: expecting a positive number for maximum roundoff 'En'.  Got '%s'\n", s-1);
        qh_errexit(qh_ERRinput, NULL, NULL);
      }else if (!isdigit(*s)) {
        qh_fprintf(qh ferr, 7005, "qhull option warning: no maximum roundoff given for option 'En'\n");
        lastwarning= s-1;
      }else {
        qh DISTround= qh_strtod(s, &s);
        qh_option("Distance-roundoff", NULL, &qh DISTround);
        qh SETroundoff= True;
      }
      break;
    case 'H':
      start= s;
      qh HALFspace= True;
      qh_strtod(s, &t);
      while (t > s)  {
        if (*t && !isspace(*t)) {
          if (*t == ',')
            t++;
          else {
            qh_fprintf(qh ferr, 6364, "qhull option error: expecting 'Hn,n,n,...' for feasible point of halfspace intersection. Got '%s'\n", start-1);
            qh_errexit(qh_ERRinput, NULL, NULL);
          }
        }
        s= t;
        qh_strtod(s, &t);
      }
      if (start < t) {
        if (!(qh feasible_string= (char *)calloc((size_t)(t-start+1), (size_t)1))) {
          qh_fprintf(qh ferr, 6034, "qhull error: insufficient memory for 'Hn,n,n'\n");
          qh_errexit(qh_ERRmem, NULL, NULL);
        }
        strncpy(qh feasible_string, start, (size_t)(t-start));
        qh_option("Halfspace-about", NULL, NULL);
        qh_option(qh feasible_string, NULL, NULL);
      }else
        qh_option("Halfspace", NULL, NULL);
      break;
    case 'R':
      if (!isdigit(*s)) {
        qh_fprintf(qh ferr, 7007, "qhull option warning: missing random perturbation for option 'Rn'\n");
        lastwarning= s-1;
      }else {
        qh RANDOMfactor= qh_strtod(s, &s);
        qh_option("Random-perturb", NULL, &qh RANDOMfactor);
        qh RANDOMdist= True;
      }
      break;
    case 'V':
      if (!isdigit(*s) && *s != '-') {
        qh_fprintf(qh ferr, 7008, "qhull option warning: missing visible distance for option 'Vn'\n");
        lastwarning= s-1;
      }else {
        qh MINvisible= qh_strtod(s, &s);
        qh_option("Visible", NULL, &qh MINvisible);
      }
      break;
    case 'U':
      if (!isdigit(*s) && *s != '-') {
        qh_fprintf(qh ferr, 7009, "qhull option warning: missing coplanar distance for option 'Un'\n");
        lastwarning= s-1;
      }else {
        qh MAXcoplanar= qh_strtod(s, &s);
        qh_option("U-coplanar", NULL, &qh MAXcoplanar);
      }
      break;
    case 'W':
      if (*s == '-') {
        qh_fprintf(qh ferr, 6365, "qhull option error: expecting a positive number for outside width 'Wn'.  Got '%s'\n", s-1);
        qh_errexit(qh_ERRinput, NULL, NULL);
      }else if (!isdigit(*s)) {
        qh_fprintf(qh ferr, 7011, "qhull option warning: missing outside width for option 'Wn'\n");
        lastwarning= s-1;
      }else {
        qh MINoutside= qh_strtod(s, &s);
        qh_option("W-outside", NULL, &qh MINoutside);
        qh APPROXhull= True;
      }
      break;
    /************  sub menus ***************/
    case 'F':
      while (*s && !isspace(*s)) {
        switch (*s++) {
        case 'a':
          qh_option("Farea", NULL, NULL);
          qh_appendprint(qh_PRINTarea);
          qh GETarea= True;
          break;
        case 'A':
          qh_option("FArea-total", NULL, NULL);
          qh GETarea= True;
          break;
        case 'c':
          qh_option("Fcoplanars", NULL, NULL);
          qh_appendprint(qh_PRINTcoplanars);
          break;
        case 'C':
          qh_option("FCentrums", NULL, NULL);
          qh_appendprint(qh_PRINTcentrums);
          break;
        case 'd':
          qh_option("Fd-cdd-in", NULL, NULL);
          qh CDDinput= True;
          break;
        case 'D':
          qh_option("FD-cdd-out", NULL, NULL);
          qh CDDoutput= True;
          break;
        case 'F':
          qh_option("FFacets-xridge", NULL, NULL);
          qh_appendprint(qh_PRINTfacets_xridge);
          break;
        case 'i':
          qh_option("Finner", NULL, NULL);
          qh_appendprint(qh_PRINTinner);
          break;
        case 'I':
          qh_option("FIDs", NULL, NULL);
          qh_appendprint(qh_PRINTids);
          break;
        case 'm':
          qh_option("Fmerges", NULL, NULL);
          qh_appendprint(qh_PRINTmerges);
          break;
        case 'M':
          qh_option("FMaple", NULL, NULL);
          qh_appendprint(qh_PRINTmaple);
          break;
        case 'n':
          qh_option("Fneighbors", NULL, NULL);
          qh_appendprint(qh_PRINTneighbors);
          break;
        case 'N':
          qh_option("FNeighbors-vertex", NULL, NULL);
          qh_appendprint(qh_PRINTvneighbors);
          break;
        case 'o':
          qh_option("Fouter", NULL, NULL);
          qh_appendprint(qh_PRINTouter);
          break;
        case 'O':
          if (qh PRINToptions1st) {
            qh_option("FOptions", NULL, NULL);
            qh_appendprint(qh_PRINToptions);
          }else
            qh PRINToptions1st= True;
          break;
        case 'p':
          qh_option("Fpoint-intersect", NULL, NULL);
          qh_appendprint(qh_PRINTpointintersect);
          break;
        case 'P':
          qh_option("FPoint-nearest", NULL, NULL);
          qh_appendprint(qh_PRINTpointnearest);
          break;
        case 'Q':
          qh_option("FQhull", NULL, NULL);
          qh_appendprint(qh_PRINTqhull);
          break;
        case 's':
          qh_option("Fsummary", NULL, NULL);
          qh_appendprint(qh_PRINTsummary);
          break;
        case 'S':
          qh_option("FSize", NULL, NULL);
          qh_appendprint(qh_PRINTsize);
          qh GETarea= True;
          break;
        case 't':
          qh_option("Ftriangles", NULL, NULL);
          qh_appendprint(qh_PRINTtriangles);
          break;
        case 'v':
          /* option set in qh_initqhull_globals */
          qh_appendprint(qh_PRINTvertices);
          break;
        case 'V':
          qh_option("FVertex-average", NULL, NULL);
          qh_appendprint(qh_PRINTaverage);
          break;
        case 'x':
          qh_option("Fxtremes", NULL, NULL);
          qh_appendprint(qh_PRINTextremes);
          break;
        default:
          s--;
          qh_fprintf(qh ferr, 7012, "qhull option warning: unknown 'F' output option 'F%c', skip to next space\n", (int)s[0]);
          lastwarning= s-1;
          while (*++s && !isspace(*s));
          break;
        }
      }
      break;
    case 'G':
      isgeom= True;
      qh_appendprint(qh_PRINTgeom);
      while (*s && !isspace(*s)) {
        switch (*s++) {
        case 'a':
          qh_option("Gall-points", NULL, NULL);
          qh PRINTdots= True;
          break;
        case 'c':
          qh_option("Gcentrums", NULL, NULL);
          qh PRINTcentrums= True;
          break;
        case 'h':
          qh_option("Gintersections", NULL, NULL);
          qh DOintersections= True;
          break;
        case 'i':
          qh_option("Ginner", NULL, NULL);
          qh PRINTinner= True;
          break;
        case 'n':
          qh_option("Gno-planes", NULL, NULL);
          qh PRINTnoplanes= True;
          break;
        case 'o':
          qh_option("Gouter", NULL, NULL);
          qh PRINTouter= True;
          break;
        case 'p':
          qh_option("Gpoints", NULL, NULL);
          qh PRINTcoplanar= True;
          break;
        case 'r':
          qh_option("Gridges", NULL, NULL);
          qh PRINTridges= True;
          break;
        case 't':
          qh_option("Gtransparent", NULL, NULL);
          qh PRINTtransparent= True;
          break;
        case 'v':
          qh_option("Gvertices", NULL, NULL);
          qh PRINTspheres= True;
          break;
        case 'D':
          if (!isdigit(*s)) {
            qh_fprintf(qh ferr, 7004, "qhull option warning: missing dimension for option 'GDn'\n");
            lastwarning= s-2;
          }else {
            if (qh DROPdim >= 0) {
              qh_fprintf(qh ferr, 7013, "qhull option warning: can only drop one dimension.  Previous 'GD%d' ignored\n",
                   qh DROPdim);
              lastwarning= s-2;
            }
            qh DROPdim= qh_strtol(s, &s);
            qh_option("GDrop-dim", &qh DROPdim, NULL);
          }
          break;
        default:
          s--;
          qh_fprintf(qh ferr, 7014, "qhull option warning: unknown 'G' geomview option 'G%c', skip to next space\n", (int)s[0]);
          lastwarning= s-1;
          while (*++s && !isspace(*s));
          break;
        }
      }
      break;
    case 'P':
      while (*s && !isspace(*s)) {
        switch (*s++) {
        case 'd': case 'D':  /* see qh_initthresholds() */
          key= s[-1];
          i= qh_strtol(s, &s);
          r= 0;
          if (*s == ':') {
            s++;
            r= qh_strtod(s, &s);
          }
          if (key == 'd')
            qh_option("Pdrop-facets-dim-less", &i, &r);
          else
            qh_option("PDrop-facets-dim-more", &i, &r);
          break;
        case 'g':
          qh_option("Pgood-facets", NULL, NULL);
          qh PRINTgood= True;
          break;
        case 'G':
          qh_option("PGood-facet-neighbors", NULL, NULL);
          qh PRINTneighbors= True;
          break;
        case 'o':
          qh_option("Poutput-forced", NULL, NULL);
          qh FORCEoutput= True;
          break;
        case 'p':
          qh_option("Pprecision-ignore", NULL, NULL);
          qh PRINTprecision= False;
          break;
        case 'A':
          if (!isdigit(*s)) {
            qh_fprintf(qh ferr, 7006, "qhull option warning: missing facet count for keep area option 'PAn'\n");
            lastwarning= s-2;
          }else {
            qh KEEParea= qh_strtol(s, &s);
            qh_option("PArea-keep", &qh KEEParea, NULL);
            qh GETarea= True;
          }
          break;
        case 'F':
          if (!isdigit(*s)) {
            qh_fprintf(qh ferr, 7010, "qhull option warning: missing facet area for option 'PFn'\n");
            lastwarning= s-2;
          }else {
            qh KEEPminArea= qh_strtod(s, &s);
            qh_option("PFacet-area-keep", NULL, &qh KEEPminArea);
            qh GETarea= True;
          }
          break;
        case 'M':
          if (!isdigit(*s)) {
            qh_fprintf(qh ferr, 7090, "qhull option warning: missing merge count for option 'PMn'\n");
            lastwarning= s-2;
          }else {
            qh KEEPmerge= qh_strtol(s, &s);
            qh_option("PMerge-keep", &qh KEEPmerge, NULL);
          }
          break;
        default:
          s--;
          qh_fprintf(qh ferr, 7015, "qhull option warning: unknown 'P' print option 'P%c', skip to next space\n", (int)s[0]);
          lastwarning= s-1;
          while (*++s && !isspace(*s));
          break;
        }
      }
      break;
    case 'Q':
      lastproject= -1;
      while (*s && !isspace(*s)) {
        switch (*s++) {
        case 'a':
          qh_option("Qallow-short", NULL, NULL);
          qh ALLOWshort= True;
          break;
        case 'b': case 'B':  /* handled by qh_initthresholds */
          key= s[-1];
          if (key == 'b' && *s == 'B') {
            s++;
            r= qh_DEFAULTbox;
            qh SCALEinput= True;
            qh_option("QbBound-unit-box", NULL, &r);
            break;
          }
          if (key == 'b' && *s == 'b') {
            s++;
            qh SCALElast= True;
            qh_option("Qbbound-last", NULL, NULL);
            break;
          }
          k= qh_strtol(s, &s);
          r= 0.0;
          wasproject= False;
          if (*s == ':') {
            s++;
            if ((r= qh_strtod(s, &s)) == 0.0) {
              t= s;            /* need true dimension for memory allocation */
              while (*t && !isspace(*t)) {
                if (toupper(*t++) == 'B'
                 && k == qh_strtol(t, &t)
                 && *t++ == ':'
                 && qh_strtod(t, &t) == 0.0) {
                  qh PROJECTinput++;
                  trace2((qh ferr, 2004, "qh_initflags: project dimension %d\n", k));
                  qh_option("Qb-project-dim", &k, NULL);
                  wasproject= True;
                  lastproject= k;
                  break;
                }
              }
            }
          }
          if (!wasproject) {
            if (lastproject == k && r == 0.0)
              lastproject= -1;  /* doesn't catch all possible sequences */
            else if (key == 'b') {
              qh SCALEinput= True;
              if (r == 0.0)
                r= -qh_DEFAULTbox;
              qh_option("Qbound-dim-low", &k, &r);
            }else {
              qh SCALEinput= True;
              if (r == 0.0)
                r= qh_DEFAULTbox;
              qh_option("QBound-dim-high", &k, &r);
            }
          }
          break;
        case 'c':
          qh_option("Qcoplanar-keep", NULL, NULL);
          qh KEEPcoplanar= True;
          break;
        case 'f':
          qh_option("Qfurthest-outside", NULL, NULL);
          qh BESToutside= True;
          break;
        case 'g':
          qh_option("Qgood-facets-only", NULL, NULL);
          qh ONLYgood= True;
          break;
        case 'i':
          qh_option("Qinterior-keep", NULL, NULL);
          qh KEEPinside= True;
          break;
        case 'm':
          qh_option("Qmax-outside-only", NULL, NULL);
          qh ONLYmax= True;
          break;
        case 'r':
          qh_option("Qrandom-outside", NULL, NULL);
          qh RANDOMoutside= True;
          break;
        case 's':
          qh_option("Qsearch-initial-simplex", NULL, NULL);
          qh ALLpoints= True;
          break;
        case 't':
          qh_option("Qtriangulate", NULL, NULL);
          qh TRIangulate= True;
          break;
        case 'T':
          qh_option("QTestPoints", NULL, NULL);
          if (!isdigit(*s)) {
            qh_fprintf(qh ferr, 7091, "qhull option warning: missing number of test points for option 'QTn'\n");
            lastwarning= s-2;
          }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-angle-merge", NULL, NULL);
            qh ANGLEmerge= True;
            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;
          case '2':
            qh_option("Q12-allow-wide", NULL, NULL);
            qh ALLOWwide= True;
            break;
          case '4':
#ifndef qh_NOmerge
            qh_option("Q14-merge-pinched-vertices", NULL, NULL);
            qh MERGEpinched= True;
#else
            /* ignore 'Q14' for q_benchmark testing of difficult cases for Qhull */
            qh_fprintf(qh ferr, 7099, "qhull option warning: option 'Q14-merge-pinched' disabled due to qh_NOmerge\n");
#endif
            break;
          case '7':
            qh_option("Q15-check-duplicates", NULL, NULL);
            qh CHECKduplicates= True;
            break;
          default:
            s--;
            qh_fprintf(qh ferr, 7016, "qhull option warning: unknown 'Q' qhull option 'Q1%c', skip to next space\n", (int)s[0]);
            lastwarning= s-1;
            while (*++s && !isspace(*s));
            break;
          }
          break;
        case '2':
          qh_option("Q2-no-merge-independent", NULL, NULL);
          qh MERGEindependent= False;
          goto LABELcheckdigit;
          break; /* no gcc warnings */
        case '3':
          qh_option("Q3-no-merge-vertices", NULL, NULL);
          qh MERGEvertices= False;
        LABELcheckdigit:
          if (isdigit(*s)) {
            qh_fprintf(qh ferr, 7017, "qhull option warning: can not follow '1', '2', or '3' with a digit.  'Q%c%c' skipped\n", *(s-1), *s);
            lastwarning= s-2;
            s++;
          }
          break;
        case '4':
          qh_option("Q4-avoid-old-into-new", NULL, NULL);
          qh AVOIDold= True;
          break;
        case '5':
          qh_option("Q5-no-check-outer", NULL, NULL);
          qh SKIPcheckmax= True;
          break;
        case '6':
          qh_option("Q6-no-concave-merge", NULL, NULL);
          qh SKIPconvex= True;
          break;
        case '7':
          qh_option("Q7-no-breadth-first", NULL, NULL);
          qh VIRTUALmemory= True;
          break;
        case '8':
          qh_option("Q8-no-near-inside", NULL, NULL);
          qh NOnearinside= True;
          break;
        case '9':
          qh_option("Q9-pick-furthest", NULL, NULL);
          qh PICKfurthest= True;
          break;
        case 'G':
          i= qh_strtol(s, &t);
          if (qh GOODpoint) {
            qh_fprintf(qh ferr, 7018, "qhull option warning: good point already defined for option 'QGn'.  Ignored\n");
            lastwarning= s-2;
          }else if (s == t) {
            qh_fprintf(qh ferr, 7019, "qhull option warning: missing good point id for option 'QGn'.  Ignored\n");
            lastwarning= s-2;
          }else if (i < 0 || *s == '-') {
            qh GOODpoint= i-1;
            qh_option("QGood-if-dont-see-point", &i, NULL);
          }else {
            qh GOODpoint= i+1;
            qh_option("QGood-if-see-point", &i, NULL);
          }
          s= t;
          break;
        case 'J':
          if (!isdigit(*s) && *s != '-')
            qh JOGGLEmax= 0.0;
          else {
            qh JOGGLEmax= (realT) qh_strtod(s, &s);
            qh_option("QJoggle", NULL, &qh JOGGLEmax);
          }
          break;
        case 'R':
          if (!isdigit(*s) && *s != '-') {
            qh_fprintf(qh ferr, 7020, "qhull option warning: missing random seed for option 'QRn'\n");
            lastwarning= s-2;
          }else {
            qh ROTATErandom= i= qh_strtol(s, &s);
            if (i > 0)
              qh_option("QRotate-id", &i, NULL );
            else if (i < -1)
              qh_option("QRandom-seed", &i, NULL );
          }
          break;
        case 'V':
          i= qh_strtol(s, &t);
          if (qh GOODvertex) {
            qh_fprintf(qh ferr, 7021, "qhull option warning: good vertex already defined for option 'QVn'.  Ignored\n");
            lastwarning= s-2;
          }else if (s == t) {
            qh_fprintf(qh ferr, 7022, "qhull option warning: no good point id given for option 'QVn'.  Ignored\n");
            lastwarning= s-2;
          }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;
        case 'w':
          qh_option("Qwarn-allow", NULL, NULL);
          qh ALLOWwarning= True;
          break;
        default:
          s--;
          qh_fprintf(qh ferr, 7023, "qhull option warning: unknown 'Q' qhull option 'Q%c', skip to next space\n", (int)s[0]);
          lastwarning= s-1;
          while (*++s && !isspace(*s));
          break;
        }
      }
      break;
    case 'T':
      while (*s && !isspace(*s)) {
        if (isdigit(*s) || *s == '-')
          qh IStracing= qh_strtol(s, &s);
        else switch (*s++) {
        case 'a':
          qh_option("Tannotate-output", NULL, NULL);
          qh ANNOTATEoutput= True;
          break;
        case 'c':
          qh_option("Tcheck-frequently", NULL, NULL);
          qh CHECKfrequently= True;
          break;
        case 'f':
          qh_option("Tflush", NULL, NULL);
          qh FLUSHprint= True;
          break;
        case 's':
          qh_option("Tstatistics", NULL, NULL);
          qh PRINTstatistics= True;
          break;
        case 'v':
          qh_option("Tverify", NULL, NULL);
          qh VERIFYoutput= True;
          break;
        case 'z':
          if (qh ferr == qh_FILEstderr) {
            /* The C++ interface captures the output in qh_fprint_qhull() */
            qh_option("Tz-stdout", NULL, NULL);
            qh USEstdout= True;
          }else if (!qh fout) {
            qh_fprintf(qh ferr, 7024, "qhull option warning: output file undefined(stdout).  Option 'Tz' ignored.\n");
            lastwarning= s-2;
          }else {
            qh_option("Tz-stdout", NULL, NULL);
            qh USEstdout= True;
            qh ferr= qh fout;
            qhmem.ferr= qh fout;
          }
          break;
        case 'C':
          if (!isdigit(*s)) {
            qh_fprintf(qh ferr, 7025, "qhull option warning: missing point id for cone for trace option 'TCn'\n");
            lastwarning= s-2;
          }else {
            i= qh_strtol(s, &s);
            qh_option("TCone-stop", &i, NULL);
            qh STOPcone= i + 1;
          }
          break;
        case 'F':
          if (!isdigit(*s)) {
            qh_fprintf(qh ferr, 7026, "qhull option warning: missing frequency count for trace option 'TFn'\n");
            lastwarning= s-2;
          }else {
            qh REPORTfreq= qh_strtol(s, &s);
            qh_option("TFacet-log", &qh REPORTfreq, NULL);
            qh REPORTfreq2= qh REPORTfreq/2;  /* for tracemerging() */
          }
          break;
        case 'I':
          while (isspace(*s))
            s++;
          t= qh_skipfilename(s);
          {
            char filename[qh_FILENAMElen];

            qh_copyfilename(filename, (int)sizeof(filename), s, (int)(t-s));   /* WARN64 */
            s= t;
            if (!freopen(filename, "r", stdin)) {
              qh_fprintf(qh ferr, 6041, "qhull option error: cannot open 'TI' file \"%s\"\n", filename);
              qh_errexit(qh_ERRinput, NULL, NULL);
            }else {
              qh_option("TInput-file", NULL, NULL);
              qh_option(filename, NULL, NULL);
            }
          }
          break;
        case 'O':
          while (isspace(*s))
            s++;
          t= qh_skipfilename(s);
          {
            char filename[qh_FILENAMElen];

            qh_copyfilename(filename, (int)sizeof(filename), s, (int)(t-s));  /* WARN64 */
            if (!qh fout) {
              qh_fprintf(qh ferr, 7092, "qhull option warning: qh.fout was not set by caller of qh_initflags.  Cannot use option 'TO' to redirect output.  Ignoring option 'TO'\n");
              lastwarning= s-2;
            }else if (!freopen(filename, "w", qh fout)) {
              qh_fprintf(qh ferr, 6044, "qhull option error: cannot open file \"%s\" for writing as option 'TO'.  It is already in use or read-only\n", filename);
              qh_errexit(qh_ERRinput, NULL, NULL);
            }else {
              qh_option("TOutput-file", NULL, NULL);
              qh_option(filename, NULL, NULL);
            }
            s= t;
          }
          break;
        case 'A':
          if (!isdigit(*s)) {
            qh_fprintf(qh ferr, 7093, "qhull option warning: missing count of added points for trace option 'TAn'\n");
            lastwarning= s-2;
          }else {
            i= qh_strtol(s, &t);
            qh STOPadd= i + 1;
            qh_option("TA-stop-add", &i, NULL);
          }
          s= t;
          break;
        case 'P':
          if (*s == '-') {
            if (s[1] == '1' && !isdigit(s[2])) {
              s += 2;
              qh TRACEpoint= qh_IDunknown; /* qh_buildhull done */
              qh_option("Trace-point", &qh TRACEpoint, NULL);
            }else {
              qh_fprintf(qh ferr, 7100, "qhull option warning: negative point id for trace option 'TPn'.  Expecting 'TP-1' for tracing after qh_buildhull and qh_postmerge\n");
              lastwarning= s-2;
              while (isdigit(*(++s)))
                ; /* skip digits */
            }
          }else if (!isdigit(*s)) {
            qh_fprintf(qh ferr, 7029, "qhull option warning: missing point id or -1 for trace option 'TPn'\n");
            lastwarning= s-2;
          }else {
            qh TRACEpoint= qh_strtol(s, &s);
            qh_option("Trace-point", &qh TRACEpoint, NULL);
          }
          break;
        case 'M':
          if (!isdigit(*s)) {
            qh_fprintf(qh ferr, 7030, "qhull option warning: missing merge id for trace option 'TMn'\n");
            lastwarning= s-2;
          }else {
            qh TRACEmerge= qh_strtol(s, &s);
            qh_option("Trace-merge", &qh TRACEmerge, NULL);
          }
          break;
        case 'R':
          if (!isdigit(*s)) {
            qh_fprintf(qh ferr, 7031, "qhull option warning: missing rerun count for trace option 'TRn'\n");
            lastwarning= s-2;
          }else {
            qh RERUN= qh_strtol(s, &s);
            qh_option("TRerun", &qh RERUN, NULL);
          }
          break;
        case 'V':
          i= qh_strtol(s, &t);
          if (s == t) {
            qh_fprintf(qh ferr, 7032, "qhull option warning: missing furthest point id for trace option 'TVn'\n");
            lastwarning= s-2;
          }else if (i < 0) {
            qh STOPpoint= i - 1;
            qh_option("TV-stop-before-point", &i, NULL);
          }else {
            qh STOPpoint= i + 1;
            qh_option("TV-stop-after-point", &i, NULL);
          }
          s= t;
          break;
        case 'W':
          if (!isdigit(*s)) {
            qh_fprintf(qh ferr, 7033, "qhull option warning: missing max width for trace option 'TWn'\n");
            lastwarning= s-2;
          }else {
            qh TRACEdist= (realT) qh_strtod(s, &s);
            qh_option("TWide-trace", NULL, &qh TRACEdist);
          }
          break;
        default:
          s--;
          qh_fprintf(qh ferr, 7034, "qhull option warning: unknown 'T' trace option 'T%c', skip to next space\n", (int)s[0]);
          lastwarning= s-2;
          while (*++s && !isspace(*s));
          break;
        }
      }
      break;
    default:
      qh_fprintf(qh ferr, 7094, "qhull option warning: unknown option '%c'(%x)\n",
        (int)s[-1], (int)s[-1]);
      lastwarning= s-2;
      break;
    }
    if (s-1 == prev_s && *s && !isspace(*s)) {
      qh_fprintf(qh ferr, 7036, "qhull option warning: missing space after option '%c'(%x), reserved for sub-options, ignoring '%c' options to next space\n",
               (int)*prev_s, (int)*prev_s, (int)*prev_s);
      lastwarning= s-1;
      while (*s && !isspace(*s))
        s++;
    }
  }
  if (qh STOPcone && qh JOGGLEmax < REALmax/2) {
    qh_fprintf(qh ferr, 7078, "qhull option warning: 'TCn' (stopCone) ignored when used with 'QJn' (joggle)\n");
    lastwarning= command;
  }
  if (isgeom && !qh FORCEoutput && qh PRINTout[1]) {
    qh_fprintf(qh ferr, 7037, "qhull option warning: additional output formats ('Fc',etc.) are not compatible with Geomview ('G').  Use option 'Po' to override\n");
    lastwarning= command;
  }
  if (lastwarning && !qh ALLOWwarning) {
    qh_fprintf(qh ferr, 6035, "qhull option error: see previous warnings, use 'Qw' to override: '%s' (last offset %d)\n",
          command, (int)(lastwarning-command));
    qh_errexit(qh_ERRinput, NULL, NULL);
  }
  trace4((qh ferr, 4093, "qh_initflags: option flags initialized\n"));
  /* set derived values in qh_initqhull_globals */
} /* initflags */


/*---------------------------------

  qh_initqhull_buffers( )
    initialize global memory buffers

  notes:
    must match qh_freebuffers()
*/
void qh_initqhull_buffers(void) {
  int k;

  qh TEMPsize= (qhmem.LASTsize - (int)sizeof(setT))/SETelemsize;
  if (qh TEMPsize <= 0 || qh TEMPsize > qhmem.LASTsize)
    qh TEMPsize= 8;  /* e.g., if qh_NOmem */
  qh other_points= qh_setnew(qh TEMPsize);
  qh del_vertices= qh_setnew(qh TEMPsize);
  qh coplanarfacetset= qh_setnew(qh TEMPsize);
  qh NEARzero= (realT *)qh_memalloc(qh hull_dim * (int)sizeof(realT));
  qh lower_threshold= (realT *)qh_memalloc((qh input_dim+1) * (int)sizeof(realT));
  qh upper_threshold= (realT *)qh_memalloc((qh input_dim+1) * (int)sizeof(realT));
  qh lower_bound= (realT *)qh_memalloc((qh input_dim+1) * (int)sizeof(realT));
  qh upper_bound= (realT *)qh_memalloc((qh input_dim+1) * (int)sizeof(realT));
  for (k=qh input_dim+1; k--; ) {  /* duplicated in qh_initqhull_buffers and qh_clear_outputflags */
    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 * (int)sizeof(coordT));
  qh gm_row= (coordT **)qh_memalloc((qh hull_dim+1) * (int)sizeof(coordT *));
} /* initqhull_buffers */

/*---------------------------------

  qh_initqhull_globals( points, numpoints, dim, ismalloc )
    initialize globals
    if ismalloc
      points were malloc'd and qhull should free at end

  returns:
    sets qh.first_point, num_points, input_dim, hull_dim and others
    seeds random number generator (seed=1 if tracing)
    modifies qh.hull_dim if ((qh.DELAUNAY and qh.PROJECTdelaunay) or qh.PROJECTinput)
    adjust user flags as needed
    also checks DIM3 dependencies and constants

  notes:
    do not use qh_point() since an input transformation may move them elsewhere
    qh_initqhull_start() sets default values for non-zero globals
    consider duplicate error checks in qh_readpoints.  It is called before qh_initqhull_globals

  design:
    initialize points array from input arguments
    test for qh.ZEROcentrum
      (i.e., use opposite vertex instead of cetrum for convexity testing)
    initialize qh.CENTERtype, qh.normal_size,
      qh.center_size, qh.TRACEpoint/level,
    initialize and test random numbers
    qh_initqhull_outputflags() -- adjust and test output flags
*/
void qh_initqhull_globals(coordT *points, int numpoints, int dim, boolT ismalloc) {
  int seed, pointsneeded, extra= 0, i, randi, k;
  realT randr;
  realT factorial;

  time_t timedata;

  trace0((qh ferr, 13, "qh_initqhull_globals: for %s | %s\n", qh rbox_command,
      qh qhull_command));
  if (numpoints < 1 || numpoints > qh_POINTSmax) {
    qh_fprintf(qh ferr, 6412, "qhull input error (qh_initqhull_globals): expecting between 1 and %d points.  Got %d %d-d points\n",
      qh_POINTSmax, numpoints, dim);
    qh_errexit(qh_ERRinput, NULL, NULL);
    /* same error message in qh_readpoints */
  }
  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 MERGEexact || qh PREmerge))
    qh_fprintf(qh ferr, 7095, "qhull option warning: 'Q0-no-premerge' ignored due to exact merge ('Qx') or pre-merge ('C-n' or 'A-n')\n");
  if (!qh NOpremerge && qh JOGGLEmax > REALmax/2) {
#ifdef qh_NOmerge
    qh JOGGLEmax= 0.0;
#endif
  }
  if (qh TRIangulate && qh JOGGLEmax < REALmax/2 && !qh PREmerge && !qh POSTmerge && qh PRINTprecision)
    qh_fprintf(qh ferr, 7038, "qhull option warning: joggle ('QJ') produces simplicial output (i.e., triangles in 2-D).  Unless merging is requested, option 'Qt' has no effect\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.0) {
    qh ZEROcentrum= True;
    qh ZEROall_ok= True;
    qh_option("_zero-centrum", NULL, NULL);
  }
  if (qh JOGGLEmax < REALmax/2 && REALepsilon > 2e-8 && qh PRINTprecision)
    qh_fprintf(qh ferr, 7039, "qhull warning: real epsilon, %2.2g, is probably too large for joggle('QJn')\nRecompile with double precision reals(see user.h).\n",
          REALepsilon);
#ifdef qh_NOmerge
  if (qh MERGING) {
    qh_fprintf(qh ferr, 6045, "qhull option error: merging not installed (qh_NOmerge) for 'Qx', 'Cn' or 'An')\n");
    qh_errexit(qh_ERRinput, NULL, NULL);
  }
#endif
  if (qh DELAUNAY && qh KEEPcoplanar && !qh KEEPinside) {
    qh KEEPinside= True;
    qh_option("Qinterior-keep", NULL, NULL);
  }
  if (qh VORONOI && !qh DELAUNAY) {
    qh_fprintf(qh ferr, 6038, "qhull internal error (qh_initqhull_globals): if qh.VORONOI is set, qh.DELAUNAY must be set.  Qhull constructs the Delaunay triangulation in order to compute the Voronoi diagram\n");
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  if (qh DELAUNAY && qh HALFspace) {
    qh_fprintf(qh ferr, 6046, "qhull option error: can not use Delaunay('d') or Voronoi('v') with halfspace intersection('H')\n");
    qh_errexit(qh_ERRinput, NULL, NULL);
    /* same error message in qh_readpoints */
  }
  if (!qh DELAUNAY && (qh UPPERdelaunay || qh ATinfinity)) {
    qh_fprintf(qh ferr, 6047, "qhull option error: use upper-Delaunay('Qu') or infinity-point('Qz') with Delaunay('d') or Voronoi('v')\n");
    qh_errexit(qh_ERRinput, NULL, NULL);
  }
  if (qh UPPERdelaunay && qh ATinfinity) {
    qh_fprintf(qh ferr, 6048, "qhull option error: can not use infinity-point('Qz') with upper-Delaunay('Qu')\n");
    qh_errexit(qh_ERRinput, NULL, NULL);
  }
  if (qh MERGEpinched && qh ONLYgood) {
    qh_fprintf(qh ferr, 6362, "qhull option error: can not use merge-pinched-vertices ('Q14') with good-facets-only ('Qg')\n");
    qh_errexit(qh_ERRinput, NULL, NULL);
  }
  if (qh MERGEpinched && qh hull_dim == 2) {
    trace2((qh ferr, 2108, "qh_initqhull_globals: disable qh.MERGEpinched for 2-d.  It has no effect"))
    qh MERGEpinched= False;
  }
  if (qh SCALElast && !qh DELAUNAY && qh PRINTprecision)
    qh_fprintf(qh ferr, 7040, "qhull option warning: option 'Qbb' (scale-last-coordinate) is normally used with 'd' or 'v'\n");
  qh DOcheckmax= (!qh SKIPcheckmax && (qh MERGING || qh APPROXhull));
  qh KEEPnearinside= (qh DOcheckmax && !(qh KEEPinside && qh KEEPcoplanar)
                          && !qh NOnearinside);
  if (qh MERGING)
    qh CENTERtype= qh_AScentrum;
  else if (qh VORONOI)
    qh CENTERtype= qh_ASvoronoi;
  if (qh TESTvneighbors && !qh MERGING) {
    qh_fprintf(qh ferr, 6049, "qhull option error: test vertex neighbors('Qv') needs a merge option\n");
    qh_errexit(qh_ERRinput, NULL ,NULL);
  }
  if (qh PROJECTinput || (qh DELAUNAY && qh PROJECTdelaunay)) {
    qh hull_dim -= qh PROJECTinput;
    if (qh DELAUNAY) {
      qh hull_dim++;
      if (qh ATinfinity)
        extra= 1;
    }
  }
  if (qh hull_dim <= 1) {
    qh_fprintf(qh ferr, 6050, "qhull error: dimension %d must be > 1\n", qh hull_dim);
    qh_errexit(qh_ERRinput, NULL, NULL);
  }
  for (k=2, factorial=1.0; k < qh hull_dim; k++)
    factorial *= k;
  qh AREAfactor= 1.0 / factorial;
  trace2((qh ferr, 2005, "qh_initqhull_globals: initialize globals.  input_dim %d, numpoints %d, malloc? %d, projected %d to hull_dim %d\n",
        qh input_dim, numpoints, ismalloc, qh PROJECTinput, qh hull_dim));
  qh normal_size= qh hull_dim * (int)sizeof(coordT);
  qh center_size= qh normal_size - (int)sizeof(coordT);
  pointsneeded= qh hull_dim+1;
  if (qh hull_dim > qh_DIMmergeVertex) {
    qh MERGEvertices= False;
    qh_option("Q3-no-merge-vertices-dim-high", NULL, NULL);
  }
  if (qh GOODpoint)
    pointsneeded++;
#ifdef qh_NOtrace
  if (qh IStracing || qh TRACEmerge || qh TRACEpoint != qh_IDnone || qh TRACEdist < REALmax/2) {
      qh_fprintf(qh ferr, 6051, "qhull option error: tracing is not installed (qh_NOtrace in user.h).  Trace options 'Tn', 'TMn', 'TPn' and 'TWn' mostly removed.  Continue with 'Qw' (allow warning)\n");
      if (!qh ALLOWwarning)
        qh_errexit(qh_ERRinput, NULL, NULL);
  }
#endif
  if (qh RERUN > 1) {
    qh TRACElastrun= qh IStracing; /* qh_build_withrestart duplicates next conditional */
    if (qh IStracing && qh IStracing != -1) {
      qh_fprintf(qh ferr, 8162, "qh_initqhull_globals: trace last of TR%d runs at level %d\n", qh RERUN, qh IStracing);
      qh IStracing= 0;
    }
  }else if (qh TRACEpoint != qh_IDnone || qh TRACEdist < REALmax/2 || qh TRACEmerge) {
    qh TRACElevel= (qh IStracing ? qh IStracing : 3);
    qh IStracing= 0;
  }
  if (qh ROTATErandom == 0 || qh ROTATErandom == -1) {
    seed= (int)time(&timedata);
    if (qh ROTATErandom  == -1) {
      seed= -seed;
      qh_option("QRandom-seed", &seed, NULL );
    }else
      qh_option("QRotate-random", &seed, NULL);
    qh ROTATErandom= seed;
  }
  seed= qh ROTATErandom;
  if (seed == INT_MIN)    /* default value */
    seed= 1;
  else if (seed < 0)
    seed= -seed;
  qh_RANDOMseed_(seed);
  randr= 0.0;
  for (i=1000; i--; ) {
    randi= qh_RANDOMint;
    randr += randi;
    if (randi > qh_RANDOMmax) {
      qh_fprintf(qh ferr, 8036, "\
qhull configuration error (qh_RANDOMmax in user.h): random integer %d > qh_RANDOMmax (%.8g)\n",
               randi, qh_RANDOMmax);
      qh_errexit(qh_ERRinput, NULL, NULL);
    }
  }
  qh_RANDOMseed_(seed);
  randr= randr/1000;
  if (randr < qh_RANDOMmax * 0.1
  || randr > qh_RANDOMmax * 0.9)
    qh_fprintf(qh ferr, 8037, "\
qhull configuration warning (qh_RANDOMmax in user.h): average of 1000 random integers (%.2g) is much different than expected (%.2g).  Is qh_RANDOMmax (%.2g) wrong?\n",
             randr, qh_RANDOMmax * 0.5, qh_RANDOMmax);
  qh RANDOMa= 2.0 * qh RANDOMfactor/qh_RANDOMmax;
  qh RANDOMb= 1.0 - qh RANDOMfactor;
  if (qh_HASHfactor < 1.1) {
    qh_fprintf(qh ferr, 6052, "qhull internal error (qh_initqhull_globals): qh_HASHfactor %d must be at least 1.1.  Qhull uses linear hash probing\n",
      qh_HASHfactor);
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  if (numpoints+extra < pointsneeded) {
    qh_fprintf(qh ferr, 6214, "qhull input error: not enough points(%d) to construct initial simplex (need %d)\n",
            numpoints, pointsneeded);
    qh_errexit(qh_ERRinput, NULL, NULL);
  }
  qh_initqhull_outputflags();
} /* initqhull_globals */

/*---------------------------------

  qh_initqhull_mem( )
    initialize mem.c for qhull
    qh.hull_dim and qh.normal_size determine some of the allocation sizes
    if qh.MERGING,
      includes ridgeT
    calls qh_user_memsizes (user.c) to add up to 10 additional sizes for quick allocation
      (see numsizes below)

  returns:
    mem.c already for qh_memalloc/qh_memfree (errors if called beforehand)

  notes:
    qh_produceoutput() prints memsizes

*/
void qh_initqhull_mem(void) {
  int numsizes;
  int i;

  numsizes= 8+10;
  qh_meminitbuffers(qh IStracing, qh_MEMalign, numsizes,
                     qh_MEMbufsize, qh_MEMinitbuf);
  qh_memsize((int)sizeof(vertexT));
  if (qh MERGING) {
    qh_memsize((int)sizeof(ridgeT));
    qh_memsize((int)sizeof(mergeT));
  }
  qh_memsize((int)sizeof(facetT));
  i= (int)sizeof(setT) + (qh hull_dim - 1) * SETelemsize;  /* ridge.vertices */
  qh_memsize(i);
  qh_memsize(qh normal_size);        /* normal */
  i += SETelemsize;                 /* facet.vertices, .ridges, .neighbors */
  qh_memsize(i);
  qh_user_memsizes();
  qh_memsetup();
} /* initqhull_mem */

/*---------------------------------

  qh_initqhull_outputflags
    initialize flags concerned with output

  returns:
    adjust user flags as needed

  see:
    qh_clear_outputflags() resets the flags

  design:
    test for qh.PRINTgood (i.e., only print 'good' facets)
    check for conflicting print output options
*/
void qh_initqhull_outputflags(void) {
  boolT printgeom= False, printmath= False, printcoplanar= False;
  int i;

  trace3((qh ferr, 3024, "qh_initqhull_outputflags: %s\n", qh qhull_command));
  if (!(qh PRINTgood || qh PRINTneighbors)) {
    if (qh DELAUNAY || qh KEEParea || qh KEEPminArea < REALmax/2 || qh KEEPmerge
        || (!qh ONLYgood && (qh GOODvertex || qh GOODpoint))) {
      qh PRINTgood= True;
      qh_option("Pgood", NULL, NULL);
    }
  }
  if (qh PRINTtransparent) {
    if (qh hull_dim != 4 || !qh DELAUNAY || qh VORONOI || qh DROPdim >= 0) {
      qh_fprintf(qh ferr, 6215, "qhull option error: transparent Delaunay('Gt') needs 3-d Delaunay('d') w/o 'GDn'\n");
      qh_errexit(qh_ERRinput, NULL, NULL);
    }
    qh DROPdim= 3;
    qh PRINTridges= True;
  }
  for (i=qh_PRINTEND; i--; ) {
    if (qh PRINTout[i] == qh_PRINTgeom)
      printgeom= True;
    else if (qh PRINTout[i] == qh_PRINTmathematica || qh PRINTout[i] == qh_PRINTmaple)
      printmath= True;
    else if (qh PRINTout[i] == qh_PRINTcoplanars)
      printcoplanar= True;
    else if (qh PRINTout[i] == qh_PRINTpointnearest)
      printcoplanar= True;
    else if (qh PRINTout[i] == qh_PRINTpointintersect && !qh HALFspace) {
      qh_fprintf(qh ferr, 6053, "qhull option error: option 'Fp' is only used for \nhalfspace intersection('Hn,n,n').\n");
      qh_errexit(qh_ERRinput, NULL, NULL);
    }else if (qh PRINTout[i] == qh_PRINTtriangles && (qh HALFspace || qh VORONOI)) {
      qh_fprintf(qh ferr, 6054, "qhull option error: option 'Ft' is not available for Voronoi vertices ('v') or halfspace intersection ('H')\n");
      qh_errexit(qh_ERRinput, NULL, NULL);
    }else if (qh PRINTout[i] == qh_PRINTcentrums && qh VORONOI) {
      qh_fprintf(qh ferr, 6055, "qhull option error: option 'FC' is not available for Voronoi vertices('v')\n");
      qh_errexit(qh_ERRinput, NULL, NULL);
    }else if (qh PRINTout[i] == qh_PRINTvertices) {
      if (qh VORONOI)
        qh_option("Fvoronoi", NULL, NULL);
      else
        qh_option("Fvertices", NULL, NULL);
    }
  }
  if (printcoplanar && qh DELAUNAY && qh JOGGLEmax < REALmax/2) {
    if (qh PRINTprecision)
      qh_fprintf(qh ferr, 7041, "qhull option warning: 'QJ' (joggle) will usually prevent coincident input sites for options 'Fc' and 'FP'\n");
  }
  if (printmath && (qh hull_dim > 3 || qh VORONOI)) {
    qh_fprintf(qh ferr, 6056, "qhull option error: Mathematica and Maple output is only available for 2-d and 3-d convex hulls and 2-d Delaunay triangulations\n");
    qh_errexit(qh_ERRinput, NULL, NULL);
  }
  if (printgeom) {
    if (qh hull_dim > 4) {
      qh_fprintf(qh ferr, 6057, "qhull option error: Geomview output is only available for 2-d, 3-d and 4-d\n");
      qh_errexit(qh_ERRinput, NULL, NULL);
    }
    if (qh PRINTnoplanes && !(qh PRINTcoplanar + qh PRINTcentrums
     + qh PRINTdots + qh PRINTspheres + qh DOintersections + qh PRINTridges)) {
      qh_fprintf(qh ferr, 6058, "qhull option error: no output specified for Geomview\n");
      qh_errexit(qh_ERRinput, NULL, NULL);
    }
    if (qh VORONOI && (qh hull_dim > 3 || qh DROPdim >= 0)) {
      qh_fprintf(qh ferr, 6059, "qhull option error: Geomview output for Voronoi diagrams only for 2-d\n");
      qh_errexit(qh_ERRinput, NULL, NULL);
    }
    /* can not warn about furthest-site Geomview output: no lower_threshold */
    if (qh hull_dim == 4 && qh DROPdim == -1 &&
        (qh PRINTcoplanar || qh PRINTspheres || qh PRINTcentrums)) {
      qh_fprintf(qh ferr, 7042, "qhull option warning: coplanars, vertices, and centrums output not available for 4-d output(ignored).  Could use 'GDn' instead.\n");
      qh PRINTcoplanar= qh PRINTspheres= qh PRINTcentrums= False;
    }
  }
  if (!qh KEEPcoplanar && !qh KEEPinside && !qh ONLYgood) {
    if ((qh PRINTcoplanar && qh PRINTspheres) || printcoplanar) {
      if (qh QHULLfinished) {
        qh_fprintf(qh ferr, 7072, "qhull output warning: ignoring coplanar points, option 'Qc' was not set for the first run of qhull.\n");
      }else {
        qh KEEPcoplanar= True;
        qh_option("Qcoplanar", NULL, NULL);
      }
    }
  }
  qh PRINTdim= qh hull_dim;
  if (qh DROPdim >=0) {    /* after Geomview checks */
    if (qh DROPdim < qh hull_dim) {
      qh PRINTdim--;
      if (!printgeom || qh hull_dim < 3)
        qh_fprintf(qh ferr, 7043, "qhull option warning: drop dimension 'GD%d' is only available for 3-d/4-d Geomview\n", qh DROPdim);
    }else
      qh DROPdim= -1;
  }else if (qh VORONOI) {
    qh DROPdim= qh hull_dim-1;
    qh PRINTdim= qh hull_dim-1;
  }
} /* qh_initqhull_outputflags */

/*---------------------------------

  qh_initqhull_start( infile, outfile, errfile )
    allocate memory if needed and call qh_initqhull_start2()
*/
void qh_initqhull_start(FILE *infile, FILE *outfile, FILE *errfile) {

#if qh_QHpointer
  if (qh_qh) {
    qh_fprintf(errfile, 6205, "qhull error (qh_initqhull_start): qh_qh already defined.  Call qh_save_qhull() first\n");
    qh_exit(qh_ERRqhull);  /* no error handler */
  }
  if (!(qh_qh= (qhT *)qh_malloc(sizeof(qhT)))) {
    qh_fprintf(errfile, 6060, "qhull error (qh_initqhull_start): insufficient memory\n");
    qh_exit(qh_ERRmem);  /* no error handler */
  }
#endif
  qh_initstatistics();
  qh_initqhull_start2(infile, outfile, errfile);
} /* initqhull_start */

/*---------------------------------

  qh_initqhull_start2( infile, outfile, errfile )
    start initialization of qhull
    initialize statistics, stdio, default values for global variables
    assumes qh_qh is defined
  notes:
    report errors elsewhere, error handling and g_qhull_output [Qhull.cpp, QhullQh()] not in initialized
  see:
    qh_maxmin() determines the precision constants
    qh_freeqhull2()
*/
void qh_initqhull_start2(FILE *infile, FILE *outfile, FILE *errfile) {
  time_t timedata;
  int seed;

  qh_CPUclock; /* start the clock(for qh_clock).  One-shot. */
#if qh_QHpointer
  memset((char *)qh_qh, 0, sizeof(qhT));   /* every field is 0, FALSE, NULL */
#else
  memset((char *)&qh_qh, 0, sizeof(qhT));
#endif
  qh NOerrexit= True;
  qh DROPdim= -1;
  qh ferr= errfile;
  qh fin= infile;
  qh fout= outfile;
  qh furthest_id= qh_IDunknown;
#ifndef qh_NOmerge
  qh JOGGLEmax= REALmax;
#else
  qh JOGGLEmax= 0.0;  /* Joggle ('QJ') if qh_NOmerge */
#endif
  qh KEEPminArea= REALmax;
  qh last_low= REALmax;
  qh last_high= REALmax;
  qh last_newhigh= REALmax;
  qh lastcpu= 0.0;
  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= qh_IDnone;    /* recompile to trace a point, or use 'TPn' */
  qh tracefacet_id= UINT_MAX;  /* recompile to trace a facet, set to UINT_MAX when done, see userprintf.c/qh_fprintf */
  qh traceridge_id= UINT_MAX;  /* recompile to trace a ridge, set to UINT_MAX when done, see userprintf.c/qh_fprintf */
  qh tracevertex_id= UINT_MAX; /* recompile to trace a vertex, set to UINT_MAX when done, see userprintf.c/qh_fprintf */
  seed= (int)time(&timedata);
  qh_RANDOMseed_(seed);
  qh run_id= qh_RANDOMint;
  if(!qh run_id)
      qh run_id++;  /* guarantee non-zero */
  qh_option("run-id", &qh run_id, NULL);
  strcat(qh qhull, "qhull");
} /* initqhull_start2 */

/*---------------------------------

  qh_initthresholds( commandString )
    set thresholds for printing and scaling from commandString

  returns:
    sets qh.GOODthreshold or qh.SPLITthreshold if 'Pd0D1' used

  see:
    qh_initflags(), 'Qbk' 'QBk' 'Pdk' and 'PDk'
    qh_inthresholds()

  design:
    for each 'Pdn' or 'PDn' option
      check syntax
      set qh.lower_threshold or qh.upper_threshold
    set qh.GOODthreshold if an unbounded threshold is used
    set qh.SPLITthreshold if a bounded threshold is used
*/
void qh_initthresholds(char *command) {
  realT value;
  int idx, maxdim, k;
  char *s= command; /* non-const due to strtol */
  char *lastoption, *lastwarning= NULL;
  char key;

  maxdim= qh input_dim;
  if (qh DELAUNAY && (qh PROJECTdelaunay || qh PROJECTinput))
    maxdim++;
  while (*s) {
    if (*s == '-')
      s++;
    if (*s == 'P') {
      lastoption= s++;
      while (*s && !isspace(key= *s++)) {
        if (key == 'd' || key == 'D') {
          if (!isdigit(*s)) {
            qh_fprintf(qh ferr, 7044, "qhull option warning: no dimension given for Print option 'P%c' at: %s.  Ignored\n",
                    key, s-1);
            lastwarning= lastoption;
            continue;
          }
          idx= qh_strtol(s, &s);
          if (idx >= qh hull_dim) {
            qh_fprintf(qh ferr, 7045, "qhull option warning: dimension %d for Print option 'P%c' is >= %d.  Ignored\n",
                idx, key, qh hull_dim);
            lastwarning= lastoption;
            continue;
          }
          if (*s == ':') {
            s++;
            value= qh_strtod(s, &s);
            if (fabs((double)value) > 1.0) {
              qh_fprintf(qh ferr, 7046, "qhull option warning: value %2.4g for Print option 'P%c' is > +1 or < -1.  Ignored\n",
                      value, key);
              lastwarning= lastoption;
              continue;
            }
          }else
            value= 0.0;
          if (key == 'd')
            qh lower_threshold[idx]= value;
          else
            qh upper_threshold[idx]= value;
        }
      }
    }else if (*s == 'Q') {
      lastoption= s++;
      while (*s && !isspace(key= *s++)) {
        if (key == 'b' && *s == 'B') {
          s++;
          for (k=maxdim; k--; ) {
            qh lower_bound[k]= -qh_DEFAULTbox;
            qh upper_bound[k]= qh_DEFAULTbox;
          }
        }else if (key == 'b' && *s == 'b')
          s++;
        else if (key == 'b' || key == 'B') {
          if (!isdigit(*s)) {
            qh_fprintf(qh ferr, 7047, "qhull option warning: no dimension given for Qhull option 'Q%c'\n",
                    key);
            lastwarning= lastoption;
            continue;
          }
          idx= qh_strtol(s, &s);
          if (idx >= maxdim) {
            qh_fprintf(qh ferr, 7048, "qhull option warning: dimension %d for Qhull option 'Q%c' is >= %d.  Ignored\n",
                idx, key, maxdim);
            lastwarning= lastoption;
            continue;
          }
          if (*s == ':') {
            s++;
            value= qh_strtod(s, &s);
          }else if (key == 'b')
            value= -qh_DEFAULTbox;
          else
            value= qh_DEFAULTbox;
          if (key == 'b')
            qh lower_bound[idx]= value;
          else
            qh upper_bound[idx]= value;
        }
      }
    }else {
      while (*s && !isspace(*s))
        s++;
    }
    while (isspace(*s))
      s++;
  }
  for (k=qh hull_dim; k--; ) {
    if (qh lower_threshold[k] > -REALmax/2) {
      qh GOODthreshold= True;
      if (qh upper_threshold[k] < REALmax/2) {
        qh SPLITthresholds= True;
        qh GOODthreshold= False;
        break;
      }
    }else if (qh upper_threshold[k] < REALmax/2)
      qh GOODthreshold= True;
  }
  if (lastwarning && !qh ALLOWwarning) {
    qh_fprintf(qh ferr, 6036, "qhull option error: see previous warnings, use 'Qw' to override: '%s' (last offset %d)\n",
      command, (int)(lastwarning-command));
    qh_errexit(qh_ERRinput, NULL, NULL);
  }
} /* initthresholds */

/*---------------------------------

  qh_lib_check( qhullLibraryType, qhTsize, vertexTsize, ridgeTsize, facetTsize, setTsize, qhmemTsize )
    Report error if library does not agree with caller

  notes:
    NOerrors -- qh_lib_check can not call qh_errexit()
*/
void qh_lib_check(int qhullLibraryType, int qhTsize, int vertexTsize, int ridgeTsize, int facetTsize, int setTsize, int qhmemTsize) {
    int last_errcode= qh_ERRnone;

#if defined(_MSC_VER) && defined(_DEBUG) && defined(QHULL_CRTDBG)  /* user.h */
    /*_CrtSetBreakAlloc(744);*/  /* Break at memalloc {744}, or 'watch' _crtBreakAlloc */
    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_DELAY_FREE_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) );
    _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG );
    _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR );
    _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG );
    _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
    _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG );
    _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );
#endif

    if (qhullLibraryType==QHULL_NON_REENTRANT) { /* 0 */
      if (qh_QHpointer) {
        qh_fprintf_stderr(6246, "qh_lib_check: Incorrect qhull library called.  Caller uses a static qhT while library uses a dynamic qhT via qh_QHpointer.  Both caller and qhull library are non-reentrant.\n");
        last_errcode= 6246;
      }
    }else if (qhullLibraryType==QHULL_QH_POINTER) { /* 1 */
      if (!qh_QHpointer) {
        qh_fprintf_stderr(6247, "qh_lib_check: Incorrect qhull library called.  Caller uses a dynamic qhT via qh_QHpointer while qhull library uses a static qhT.  Both caller and qhull library are non-reentrant.\n");
        last_errcode= 6247;
      }
    }else if (qhullLibraryType == QHULL_REENTRANT) { /* 2 */
      qh_fprintf_stderr(6248, "qh_lib_check: Incorrect qhull library called.  Caller uses reentrant Qhull while qhull library is non-reentrant\n");
      last_errcode= 6248;
    }else {
      qh_fprintf_stderr(6262, "qh_lib_check: Expecting qhullLibraryType QHULL_NON_REENTRANT(0), QHULL_QH_POINTER(1), or QHULL_REENTRANT(2).  Got %d\n", qhullLibraryType);
      last_errcode= 6262;
    }
    if (qhTsize != (int)sizeof(qhT)) {
      qh_fprintf_stderr(6249, "qh_lib_check: Incorrect qhull library called.  Size of qhT for caller is %d, but for qhull library is %d.\n", qhTsize, (int)sizeof(qhT));
      last_errcode= 6249;
    }
    if (vertexTsize != (int)sizeof(vertexT)) {
      qh_fprintf_stderr(6250, "qh_lib_check: Incorrect qhull library called.  Size of vertexT for caller is %d, but for qhull library is %d.\n", vertexTsize, (int)sizeof(vertexT));
      last_errcode= 6250;
    }
    if (ridgeTsize != (int)sizeof(ridgeT)) {
      qh_fprintf_stderr(6251, "qh_lib_check: Incorrect qhull library called.  Size of ridgeT for caller is %d, but for qhull library is %d.\n", ridgeTsize, (int)sizeof(ridgeT));
      last_errcode= 6251;
    }
    if (facetTsize != (int)sizeof(facetT)) {
      qh_fprintf_stderr(6252, "qh_lib_check: Incorrect qhull library called.  Size of facetT for caller is %d, but for qhull library is %d.\n", facetTsize, (int)sizeof(facetT));
      last_errcode= 6252;
    }
    if (setTsize && setTsize != (int)sizeof(setT)) {
      qh_fprintf_stderr(6253, "qh_lib_check: Incorrect qhull library called.  Size of setT for caller is %d, but for qhull library is %d.\n", setTsize, (int)sizeof(setT));
      last_errcode= 6253;
    }
    if (qhmemTsize && qhmemTsize != sizeof(qhmemT)) {
      qh_fprintf_stderr(6254, "qh_lib_check: Incorrect qhull library called.  Size of qhmemT for caller is %d, but for qhull library is %d.\n", qhmemTsize, sizeof(qhmemT));
      last_errcode= 6254;
    }
    if (last_errcode) {
      if(qh_QHpointer){
        qh_fprintf_stderr(6255, "qhull internal error (qh_lib_check): Cannot continue due to QH%d.  Library '%s' should use a dynamic qhT via qh_QHpointer (e.g., qhull_p.so).  It may be out-of-date.  Exit with %d\n",
              last_errcode, qh_version2, last_errcode - 6200);
      }else {
        qh_fprintf_stderr(6256, "qhull internal error (qh_lib_check): Cannot continue due to QH%d..  Library '%s' should use a static qhT (e.g., libqhull.so).  It may be out-of-date.  Exit with %d\n",
              last_errcode, qh_version2, last_errcode - 6200);
      }
      qh_exit(last_errcode - 6200);  /* can not use qh_errexit(), must be less than 255 */
    }
} /* lib_check */

/*---------------------------------

  qh_option( option, intVal, realVal )
    add an option description to qh.qhull_options

  notes:
    NOerrors -- qh_option can not call qh_errexit() [qh_initqhull_start2]
    will be printed with statistics ('Ts') and errors
    strlen(option) < 40
*/
void qh_option(const char *option, int *i, realT *r) {
  char buf[200];
  int buflen, remainder;

  if (strlen(option) > sizeof(buf)-30-30) {
    qh_fprintf(qh ferr, 6408, "qhull internal error (qh_option): option (%d chars) has more than %d chars.  May overflow temporary buffer.  Option '%s'\n",
        (int)strlen(option), (int)sizeof(buf)-30-30, option);
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  sprintf(buf, "  %s", option);
  if (i)
    sprintf(buf+strlen(buf), " %d", *i);
  if (r)
    sprintf(buf+strlen(buf), " %2.2g", *r);
  buflen= (int)strlen(buf);   /* WARN64 */
  qh qhull_optionlen += buflen;
  remainder= (int)(sizeof(qh qhull_options) - strlen(qh qhull_options)) - 1;    /* WARN64 */
  maximize_(remainder, 0);
  if (qh qhull_optionlen >= qh_OPTIONline && remainder > 0) {
    strncat(qh qhull_options, "\n", (unsigned int)remainder);
    --remainder;
    qh qhull_optionlen= buflen;
  }
  if (buflen > remainder) {
    trace1((qh ferr, 1058, "qh_option: option would overflow qh.qhull_options. Truncated '%s'\n", buf));
  }
  strncat(qh qhull_options, buf, (unsigned int)remainder);
} /* option */

#if qh_QHpointer
/*---------------------------------

  qh_restore_qhull( oldqh )
    restores a previously saved qhull
    also restores qh_qhstat and qhmem.tempstack
    Sets *oldqh to NULL
  notes:
    errors if current qhull hasn't been saved or freed
    uses qhmem for error reporting

  NOTE 1998/5/11:
    Freeing memory after qh_save_qhull and qh_restore_qhull
    is complicated.  The procedures will be redesigned.

  see:
    qh_save_qhull(), UsingLibQhull
*/
void qh_restore_qhull(qhT **oldqh) {

  if (*oldqh && strcmp((*oldqh)->qhull, "qhull")) {
    qh_fprintf(qhmem.ferr, 6061, "qhull internal error (qh_restore_qhull): %p is not a qhull data structure\n",
                  *oldqh);
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  if (qh_qh) {
    qh_fprintf(qhmem.ferr, 6062, "qhull internal error (qh_restore_qhull): did not save or free existing qhull\n");
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  if (!*oldqh || !(*oldqh)->old_qhstat) {
    qh_fprintf(qhmem.ferr, 6063, "qhull internal error (qh_restore_qhull): did not previously save qhull %p\n",
                  *oldqh);
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  qh_qh= *oldqh;
  *oldqh= NULL;
  qh_qhstat= qh old_qhstat;
  qhmem.tempstack= qh old_tempstack;
  qh old_qhstat= 0;
  qh old_tempstack= 0;
  trace1((qh ferr, 1007, "qh_restore_qhull: restored qhull from %p\n", *oldqh));
} /* restore_qhull */

/*---------------------------------

  qh_save_qhull(  )
    saves qhull for a later qh_restore_qhull
    also saves qh_qhstat and qhmem.tempstack

  returns:
    qh_qh=NULL

  notes:
    need to initialize qhull or call qh_restore_qhull before continuing

  NOTE 1998/5/11:
    Freeing memory after qh_save_qhull and qh_restore_qhull
    is complicated.  The procedures will be redesigned.

  see:
    qh_restore_qhull()
*/
qhT *qh_save_qhull(void) {
  qhT *oldqh;

  trace1((qhmem.ferr, 1045, "qh_save_qhull: save qhull %p\n", qh_qh));
  if (!qh_qh) {
    qh_fprintf(qhmem.ferr, 6064, "qhull internal error (qh_save_qhull): qhull not initialized\n");
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  qh old_qhstat= qh_qhstat;
  qh_qhstat= NULL;
  qh old_tempstack= qhmem.tempstack;
  qhmem.tempstack= NULL;
  oldqh= qh_qh;
  qh_qh= NULL;
  return oldqh;
} /* save_qhull */

#endif

qhull-2020.2/src/libqhull/index.htm0000644060175106010010000002603313716274032015423 0ustar  bbarber



Qhull functions, macros, and data structures




Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: Qhull files
To: GeomGlobalIoMemMergePolyQhullSetStatUser


Qhull functions, macros, and data structures

The following sections provide an overview and index to Qhull's functions, macros, and data structures. Each section starts with an introduction. See also Calling Qhull from C programs and Calling Qhull from C++ programs.

Qhull uses the following conventions:

  • in code, global variables start with "qh "
  • in documentation, global variables start with 'qh.'
  • constants start with an upper case word
  • important globals include an '_'
  • functions, macros, and constants start with "qh_"
  • data types end in "T"
  • macros with arguments end in "_"
  • iterators are macros that use local variables
  • iterators for sets start with "FOREACH"
  • iterators for lists start with "FORALL"
  • qhull options are in single quotes (e.g., 'Pdn')
  • lists are sorted alphabetically
  • preprocessor directives on left margin for older compilers

When reading the code, please note that the global data structure, 'qh', is a macro. It either expands to "qh_qh." or to "qh_qh->". The later is used for applications which run concurrent calls to qh_qhull().

When reading code with an editor, a search for '"function' will locate the header of qh_function. A search for '* function' will locate the tail of qh_function.

A useful starting point is libqhull.h. It defines most of Qhull data structures and top-level functions. Search for 'PFn' to determine the corresponding constant in Qhull. Search for 'Fp' to determine the corresponding qh_PRINT... constant. Search io.c to learn how the print function is implemented.

If your web browser is configured for .c and .h files, the function, macro, and data type links go to the corresponding source location.

  • Internet Explorer -- OK for web access but not for file access
  • Chrome -- OK for web access but not for file access
  • Firefox -- OK for web access but not for file access
    # .htaccess on web server with NL line endings
    AddType text/html .c .h
    
  • Opera 12.10
    1. In Tools > Preferences > Advanced > Downloads
    2. Uncheck 'Hide file types opened with Opera'
    3. Quick find 'html'
    4. Select 'text/html' > Edit
    5. Add File extensions 'c,h,'
    6. Click 'OK'

Please report documentation and link errors to qhull-bug@qhull.org.

Copyright © 1997-2020 C.B. Barber


»Qhull files

This sections lists the .c and .h files for Qhull. Please refer to these files for detailed information.

Makefile, CMakeLists.txt
Makefile is preconfigured for gcc. CMakeLists.txt supports multiple platforms with CMake. Qhull includes project files for Visual Studio and Qt.
 
libqhull.h
Include file for the Qhull library (libqhull.so, qhull.dll, libqhullstatic.a). Data structures are documented under Poly. Global variables are documented under Global. Other data structures and variables are documented under Qhull or Geom.
 
Geom, geom.h, geom.c, geom2.c, random.c, random.h
Geometric routines. These routines implement mathematical functions such as Gaussian elimination and geometric routines needed for Qhull. Frequently used routines are in geom.c while infrequent ones are in geom2.c.
 
Global, global.c, libqhull.h
Global routines. Qhull uses a global data structure, qh, to store globally defined constants, lists, sets, and variables. global.c initializes and frees these structures.
 
Io, io.h, io.c
Input and output routines. Qhull provides a wide range of input and output options.
 
Mem, mem.h, mem.c
Memory routines. Qhull provides memory allocation and deallocation. It uses quick-fit allocation.
 
Merge, merge.h, merge.c
Merge routines. Qhull handles precision problems by merged facets or joggled input. These routines merge simplicial facets, merge non-simplicial facets, merge cycles of facets, and rename redundant vertices.
 
Poly, poly.h, poly.c, poly2.c, libqhull.h
Polyhedral routines. Qhull produces a polyhedron as a list of facets with vertices, neighbors, ridges, and geometric information. libqhull.h defines the main data structures. Frequently used routines are in poly.c while infrequent ones are in poly2.c.
 
Qhull, libqhull.c, libqhull.h, qhull_a.h, unix.c , qconvex.c , qdelaun.c , qhalf.c , qvoronoi.c
Top-level routines. The Quickhull algorithm is implemented by libqhull.c. qhull_a.h includes all header files.
 
Set, qset.h, qset.c
Set routines. Qhull implements its data structures as sets. A set is an array of pointers that is expanded as needed. This is a separate package that may be used in other applications.
 
Stat, stat.h, stat.c
Statistical routines. Qhull maintains statistics about its implementation.
 
User, user.h, user.c, user_eg.c, user_eg2.c, user_eg3.cpp,
User-defined routines. Qhull allows the user to configure the code with defined constants and specialized routines.


Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: Qhull files
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

qhull-2020.2/src/libqhull/io.c0000644060175106010010000041416213666241740014365 0ustar bbarber/*
  ---------------------------------

   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-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull/io.c#11 $$Change: 2965 $
   $DateTime: 2020/06/04 15:37:41 $$Author: bbarber $
*/

#include "qhull_a.h"

/*========= -functions in alphabetical order after qh_produce_output()  =====*/

/*---------------------------------

  qh_produce_output( )
  qh_produce_output2( )
    prints out the result of qhull in desired format
    qh_produce_output2 does not call qh_prepare_output
      qh_checkpolygon is valid for qh_prepare_output
    if qh.GETarea
      computes and prints area and volume
    qh.PRINTout[] is an array of output formats

  notes:
    prints output in qh.PRINTout order
*/
void qh_produce_output(void) {
    int tempsize= qh_setsize(qhmem.tempstack);

    qh_prepare_output();
    qh_produce_output2();
    if (qh_setsize(qhmem.tempstack) != tempsize) {
        qh_fprintf(qh ferr, 6206, "qhull internal error (qh_produce_output): temporary sets not empty(%d)\n",
            qh_setsize(qhmem.tempstack));
        qh_errexit(qh_ERRqhull, NULL, NULL);
    }
} /* produce_output */


void qh_produce_output2(void) {
  int i, tempsize= qh_setsize(qhmem.tempstack), d_1;

  fflush(NULL);
  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);
  fflush(NULL);

  qh_allstatistics();
  if (qh PRINTprecision && !qh MERGING && (qh JOGGLEmax > REALmax/2 || qh RERUN))
    qh_printstats(qh ferr, qhstat precision, NULL);
  if (qh VERIFYoutput && (zzval_(Zridge) > 0 || zzval_(Zridgemid) > 0))
    qh_printstats(qh ferr, qhstat vridges, NULL);
  if (qh PRINTstatistics) {
    qh_printstatistics(qh ferr, "");
    qh_memstatistics(qh ferr);
    d_1= (int)sizeof(setT) + (qh hull_dim - 1) * SETelemsize;
    qh_fprintf(qh ferr, 8040, "\
    size in bytes: merge %d ridge %d vertex %d facet %d\n\
         normal %d ridge vertices %d facet vertices or neighbors %d\n",
            (int)sizeof(mergeT), (int)sizeof(ridgeT),
            (int)sizeof(vertexT), (int)sizeof(facetT),
            qh normal_size, d_1, d_1 + SETelemsize);
  }
  if (qh_setsize(qhmem.tempstack) != tempsize) {
    qh_fprintf(qh ferr, 6065, "qhull internal error (qh_produce_output2): temporary sets not empty(%d)\n",
             qh_setsize(qhmem.tempstack));
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
} /* produce_output2 */

/*---------------------------------

  qh_dfacet( id )
    print facet by id, for debugging

*/
void qh_dfacet(unsigned int id) {
  facetT *facet;

  FORALLfacets {
    if (facet->id == id) {
      qh_printfacet(qh fout, facet);
      break;
    }
  }
} /* dfacet */


/*---------------------------------

  qh_dvertex( id )
    print vertex by id, for debugging
*/
void qh_dvertex(unsigned int id) {
  vertexT *vertex;

  FORALLvertices {
    if (vertex->id == id) {
      qh_printvertex(qh fout, vertex);
      break;
    }
  }
} /* dvertex */


/*---------------------------------

  qh_compare_facetarea( p1, p2 )
    used by qsort() to order facets by area
*/
int qh_compare_facetarea(const void *p1, const void *p2) {
  const facetT *a= *((facetT *const*)p1), *b= *((facetT *const*)p2);

  if (!a->isarea)
    return -1;
  if (!b->isarea)
    return 1;
  if (a->f.area > b->f.area)
    return 1;
  else if (a->f.area == b->f.area)
    return 0;
  return -1;
} /* compare_facetarea */

/*---------------------------------

  qh_compare_facetvisit( p1, p2 )
    used by qsort() to order facets by visit id or id
*/
int qh_compare_facetvisit(const void *p1, const void *p2) {
  const facetT *a= *((facetT *const*)p1), *b= *((facetT *const*)p2);
  int i,j;

  if (!(i= (int)a->visitid))
    i= (int)(0 - a->id); /* sign distinguishes id from visitid */
  if (!(j= (int)b->visitid))
    j= (int)(0 - b->id);
  return(i - j);
} /* compare_facetvisit */

/*---------------------------------

  qh_compare_nummerge( p1, p2 )
    used by qsort() to order facets by number of merges

notes:
    called by qh_markkeep ('PMerge-keep')
*/
int qh_compare_nummerge(const void *p1, const void *p2) {
  const facetT *a= *((facetT *const*)p1), *b= *((facetT *const*)p2);

  return(a->nummerge - b->nummerge);
} /* compare_nummerge */

/*---------------------------------

  qh_copyfilename( dest, size, source, length )
    copy filename identified by qh_skipfilename()

  notes:
    see qh_skipfilename() for syntax
*/
void qh_copyfilename(char *filename, int size, const char* source, int length) {
  char c= *source;

  if (length > size + 1) {
      qh_fprintf(qh ferr, 6040, "qhull error: filename is more than %d characters, %s\n",  size-1, source);
      qh_errexit(qh_ERRinput, NULL, NULL);
  }
  strncpy(filename, source, (size_t)length);
  filename[length]= '\0';
  if (c == '\'' || c == '"') {
    char *s= filename + 1;
    char *t= filename;
    while (*s) {
      if (*s == c) {
          if (s[-1] == '\\')
              t[-1]= c;
      }else
          *t++= *s;
      s++;
    }
    *t= '\0';
  }
} /* copyfilename */

/*---------------------------------

  qh_countfacets(facetlist, facets, printall,
          numfacets, numsimplicial, totneighbors, numridges, numcoplanar, numtricoplanars  )
    count good facets for printing and set visitid
    if allfacets, ignores qh_skipfacet()

  notes:
    qh_printsummary and qh_countfacets must match counts

  returns:
    numfacets, numsimplicial, total neighbors, numridges, coplanars
    each facet with ->visitid indicating 1-relative position
      ->visitid==0 indicates not good

  notes
    numfacets >= numsimplicial
    if qh.NEWfacets,
      does not count visible facets (matches qh_printafacet)

  design:
    for all facets on facetlist and in facets set
      unless facet is skipped or visible (i.e., will be deleted)
        mark facet->visitid
        update counts
*/
void qh_countfacets(facetT *facetlist, setT *facets, boolT printall,
    int *numfacetsp, int *numsimplicialp, int *totneighborsp, int *numridgesp, int *numcoplanarsp, int *numtricoplanarsp) {
  facetT *facet, **facetp;
  int numfacets= 0, numsimplicial= 0, numridges= 0, totneighbors= 0, numcoplanars= 0, numtricoplanars= 0;

  FORALLfacet_(facetlist) {
    if ((facet->visible && qh NEWfacets)
    || (!printall && qh_skipfacet(facet)))
      facet->visitid= 0;
    else {
      facet->visitid= (unsigned int)(++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= (unsigned int)(++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 += (unsigned int)numfacets + 1;
  *numfacetsp= numfacets;
  *numsimplicialp= numsimplicial;
  *totneighborsp= totneighbors;
  *numridgesp= numridges;
  *numcoplanarsp= numcoplanars;
  *numtricoplanarsp= numtricoplanars;
} /* countfacets */

/*---------------------------------

  qh_detvnorm( vertex, vertexA, centers, offset )
    compute separating plane of the Voronoi diagram for a pair of input sites
    centers= set of facets (i.e., Voronoi vertices)
      facet->visitid= 0 iff vertex-at-infinity (i.e., unbounded)

  assumes:
    qh_ASvoronoi and qh_vertexneighbors() already set

  returns:
    norm
      a pointer into qh.gm_matrix to qh.hull_dim-1 reals
      copy the data before reusing qh.gm_matrix
    offset
      if 'QVn'
        sign adjusted so that qh.GOODvertexp is inside
      else
        sign adjusted so that vertex is inside

    qh.gm_matrix= simplex of points from centers relative to first center

  notes:
    in io.c so that code for 'v Tv' can be removed by removing io.c
    returns pointer into qh.gm_matrix to avoid tracking of temporary memory

  design:
    determine midpoint of input sites
    build points as the set of Voronoi vertices
    select a simplex from points (if necessary)
      include midpoint if the Voronoi region is unbounded
    relocate the first vertex of the simplex to the origin
    compute the normalized hyperplane through the simplex
    orient the hyperplane toward 'QVn' or 'vertex'
    if 'Tv' or 'Ts'
      if bounded
        test that hyperplane is the perpendicular bisector of the input sites
      test that Voronoi vertices not in the simplex are still on the hyperplane
    free up temporary memory
*/
pointT *qh_detvnorm(vertexT *vertex, vertexT *vertexA, setT *centers, realT *offsetp) {
  facetT *facet, **facetp;
  int  i, k, pointid, pointidA, point_i, point_n;
  setT *simplex= NULL;
  pointT *point, **pointp, *point0, *midpoint, *normal, *inpoint;
  coordT *coord, *gmcoord, *normalp;
  setT *points= qh_settemp(qh TEMPsize);
  boolT nearzero= False;
  boolT unbounded= False;
  int numcenters= 0;
  int dim= qh hull_dim - 1;
  realT dist, offset, angle, zero= 0.0;

  midpoint= qh gm_matrix + qh hull_dim * qh hull_dim;  /* last row */
  for (k=0; k < dim; k++)
    midpoint[k]= (vertex->point[k] + vertexA->point[k])/2;
  FOREACHfacet_(centers) {
    numcenters++;
    if (!facet->visitid)
      unbounded= True;
    else {
      if (!facet->center)
        facet->center= qh_facetcenter(facet->vertices);
      qh_setappend(&points, facet->center);
    }
  }
  if (numcenters > dim) {
    simplex= qh_settemp(qh TEMPsize);
    qh_setappend(&simplex, vertex->point);
    if (unbounded)
      qh_setappend(&simplex, midpoint);
    qh_maxsimplex(dim, points, NULL, 0, &simplex);
    qh_setdelnth(simplex, 0);
  }else if (numcenters == dim) {
    if (unbounded)
      qh_setappend(&points, midpoint);
    simplex= points;
  }else {
    qh_fprintf(qh ferr, 6216, "qhull internal error (qh_detvnorm): too few points(%d) to compute separating plane\n", numcenters);
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  i= 0;
  gmcoord= qh gm_matrix;
  point0= SETfirstt_(simplex, pointT);
  FOREACHpoint_(simplex) {
    if (qh IStracing >= 4)
      qh_printmatrix(qh ferr, "qh_detvnorm: Voronoi vertex or midpoint",
                              &point, 1, dim);
    if (point != point0) {
      qh gm_row[i++]= gmcoord;
      coord= point0;
      for (k=dim; k--; )
        *(gmcoord++)= *point++ - *coord++;
    }
  }
  qh gm_row[i]= gmcoord;  /* does not overlap midpoint, may be used later for qh_areasimplex */
  normal= gmcoord;
  qh_sethyperplane_gauss(dim, qh gm_row, point0, True,
                normal, &offset, &nearzero);
  /* nearzero is true for axis-parallel hyperplanes (e.g., a bounding box).  Should detect degenerate hyperplanes.  See 'Tv' check following */
  if (qh GOODvertexp == vertexA->point)
    inpoint= vertexA->point;
  else
    inpoint= vertex->point;
  zinc_(Zdistio);
  dist= qh_distnorm(dim, inpoint, normal, &offset);
  if (dist > 0) {
    offset= -offset;
    normalp= normal;
    for (k=dim; k--; ) {
      *normalp= -(*normalp);
      normalp++;
    }
  }
  if (qh VERIFYoutput || qh PRINTstatistics) {
    pointid= qh_pointid(vertex->point);
    pointidA= qh_pointid(vertexA->point);
    if (!unbounded) {
      zinc_(Zdiststat);
      dist= qh_distnorm(dim, midpoint, normal, &offset);
      if (dist < 0)
        dist= -dist;
      zzinc_(Zridgemid);
      wwmax_(Wridgemidmax, dist);
      wwadd_(Wridgemid, dist);
      trace4((qh ferr, 4014, "qh_detvnorm: points %d %d midpoint dist %2.2g\n",
                 pointid, pointidA, dist));
      for (k=0; k < dim; k++)
        midpoint[k]= vertexA->point[k] - vertex->point[k];  /* overwrites midpoint! */
      qh_normalize(midpoint, dim, False);
      angle= qh_distnorm(dim, midpoint, normal, &zero); /* qh_detangle uses dim+1 */
      if (angle < 0.0)
        angle= angle + 1.0;
      else
        angle= angle - 1.0;
      if (angle < 0.0)
        angle= -angle;
      trace4((qh ferr, 4015, "qh_detvnorm: points %d %d angle %2.2g nearzero %d\n",
                 pointid, pointidA, angle, nearzero));
      if (nearzero) {
        zzinc_(Zridge0);
        wwmax_(Wridge0max, angle);
        wwadd_(Wridge0, angle);
      }else {
        zzinc_(Zridgeok)
        wwmax_(Wridgeokmax, angle);
        wwadd_(Wridgeok, angle);
      }
    }
    if (simplex != points) {
      FOREACHpoint_i_(points) {
        if (!qh_setin(simplex, point)) {
          facet= SETelemt_(centers, point_i, facetT);
          zinc_(Zdiststat);
          dist= qh_distnorm(dim, point, normal, &offset);
          if (dist < 0)
            dist= -dist;
          zzinc_(Zridge);
          wwmax_(Wridgemax, dist);
          wwadd_(Wridge, dist);
          trace4((qh ferr, 4016, "qh_detvnorm: points %d %d Voronoi vertex %d dist %2.2g\n",
                             pointid, pointidA, facet->visitid, dist));
        }
      }
    }
  }
  *offsetp= offset;
  if (simplex != points)
    qh_settempfree(&simplex);
  qh_settempfree(&points);
  return normal;
} /* detvnorm */

/*---------------------------------

  qh_detvridge( vertexA )
    determine Voronoi ridge from 'seen' neighbors of vertexA
    include one vertex-at-infinite if an !neighbor->visitid

  returns:
    temporary set of centers (facets, i.e., Voronoi vertices)
    sorted by center id
*/
setT *qh_detvridge(vertexT *vertex) {
  setT *centers= qh_settemp(qh TEMPsize);
  setT *tricenters= qh_settemp(qh TEMPsize);
  facetT *neighbor, **neighborp;
  boolT firstinf= True;

  FOREACHneighbor_(vertex) {
    if (neighbor->seen) {
      if (neighbor->visitid) {
        if (!neighbor->tricoplanar || qh_setunique(&tricenters, neighbor->center))
          qh_setappend(¢ers, neighbor);
      }else if (firstinf) {
        firstinf= False;
        qh_setappend(¢ers, neighbor);
      }
    }
  }
  qsort(SETaddr_(centers, facetT), (size_t)qh_setsize(centers),
             sizeof(facetT *), qh_compare_facetvisit);
  qh_settempfree(&tricenters);
  return centers;
} /* detvridge */

/*---------------------------------

  qh_detvridge3( atvertex, vertex )
    determine 3-d Voronoi ridge from 'seen' neighbors of atvertex and vertex
    include one vertex-at-infinite for !neighbor->visitid
    assumes all facet->seen2= True

  returns:
    temporary set of centers (facets, i.e., Voronoi vertices)
    listed in adjacency order (!oriented)
    all facet->seen2= True

  design:
    mark all neighbors of atvertex
    for each adjacent neighbor of both atvertex and vertex
      if neighbor selected
        add neighbor to set of Voronoi vertices
*/
setT *qh_detvridge3(vertexT *atvertex, vertexT *vertex) {
  setT *centers= qh_settemp(qh TEMPsize);
  setT *tricenters= qh_settemp(qh TEMPsize);
  facetT *neighbor, **neighborp, *facet= NULL;
  boolT firstinf= True;

  FOREACHneighbor_(atvertex)
    neighbor->seen2= False;
  FOREACHneighbor_(vertex) {
    if (!neighbor->seen2) {
      facet= neighbor;
      break;
    }
  }
  while (facet) {
    facet->seen2= True;
    if (neighbor->seen) {
      if (facet->visitid) {
        if (!facet->tricoplanar || qh_setunique(&tricenters, facet->center))
          qh_setappend(¢ers, facet);
      }else if (firstinf) {
        firstinf= False;
        qh_setappend(¢ers, facet);
      }
    }
    FOREACHneighbor_(facet) {
      if (!neighbor->seen2) {
        if (qh_setin(vertex->neighbors, neighbor))
          break;
        else
          neighbor->seen2= True;
      }
    }
    facet= neighbor;
  }
  if (qh CHECKfrequently) {
    FOREACHneighbor_(vertex) {
      if (!neighbor->seen2) {
          qh_fprintf(qh ferr, 6217, "qhull internal error (qh_detvridge3): neighbors of vertex p%d are not connected at facet %d\n",
                 qh_pointid(vertex->point), neighbor->id);
        qh_errexit(qh_ERRqhull, neighbor, NULL);
      }
    }
  }
  FOREACHneighbor_(atvertex)
    neighbor->seen2= True;
  qh_settempfree(&tricenters);
  return centers;
} /* detvridge3 */

/*---------------------------------

  qh_eachvoronoi( fp, printvridge, vertex, visitall, innerouter, inorder )
    if visitall,
      visit all Voronoi ridges for vertex (i.e., an input site)
    else
      visit all unvisited Voronoi ridges for vertex
      all vertex->seen= False if unvisited
    assumes
      all facet->seen= False
      all facet->seen2= True (for qh_detvridge3)
      all facet->visitid == 0 if vertex_at_infinity
                         == index of Voronoi vertex
                         >= qh.num_facets if ignored
    innerouter:
      qh_RIDGEall--  both inner (bounded) and outer(unbounded) ridges
      qh_RIDGEinner- only inner
      qh_RIDGEouter- only outer

    if inorder
      orders vertices for 3-d Voronoi diagrams

  returns:
    number of visited ridges (does not include previously visited ridges)

    if printvridge,
      calls printvridge( fp, vertex, vertexA, centers)
        fp== any pointer (assumes FILE*)
             fp may be NULL for QhullQh::qh_fprintf which calls appendQhullMessage
        vertex,vertexA= pair of input sites that define a Voronoi ridge
        centers= set of facets (i.e., Voronoi vertices)
                 ->visitid == index or 0 if vertex_at_infinity
                 ordered for 3-d Voronoi diagram
  notes:
    uses qh.vertex_visit

  see:
    qh_eachvoronoi_all()

  design:
    mark selected neighbors of atvertex
    for each selected neighbor (either Voronoi vertex or vertex-at-infinity)
      for each unvisited vertex
        if atvertex and vertex share more than d-1 neighbors
          bump totalcount
          if printvridge defined
            build the set of shared neighbors (i.e., Voronoi vertices)
            call printvridge
*/
int qh_eachvoronoi(FILE *fp, printvridgeT printvridge, vertexT *atvertex, boolT visitall, qh_RIDGE innerouter, boolT inorder) {
  boolT unbounded;
  int count;
  facetT *neighbor, **neighborp, *neighborA, **neighborAp;
  setT *centers;
  setT *tricenters= qh_settemp(qh TEMPsize);

  vertexT *vertex, **vertexp;
  boolT firstinf;
  unsigned int numfacets= (unsigned int)qh num_facets;
  int totridges= 0;

  qh vertex_visit++;
  atvertex->seen= True;
  if (visitall) {
    FORALLvertices
      vertex->seen= False;
  }
  FOREACHneighbor_(atvertex) {
    if (neighbor->visitid < numfacets)
      neighbor->seen= True;
  }
  FOREACHneighbor_(atvertex) {
    if (neighbor->seen) {
      FOREACHvertex_(neighbor->vertices) {
        if (vertex->visitid != qh vertex_visit && !vertex->seen) {
          vertex->visitid= qh vertex_visit;
          count= 0;
          firstinf= True;
          qh_settruncate(tricenters, 0);
          FOREACHneighborA_(vertex) {
            if (neighborA->seen) {
              if (neighborA->visitid) {
                if (!neighborA->tricoplanar || qh_setunique(&tricenters, neighborA->center))
                  count++;
              }else if (firstinf) {
                count++;
                firstinf= False;
              }
            }
          }
          if (count >= qh hull_dim - 1) {  /* e.g., 3 for 3-d Voronoi */
            if (firstinf) {
              if (innerouter == qh_RIDGEouter)
                continue;
              unbounded= False;
            }else {
              if (innerouter == qh_RIDGEinner)
                continue;
              unbounded= True;
            }
            totridges++;
            trace4((qh ferr, 4017, "qh_eachvoronoi: Voronoi ridge of %d vertices between sites %d and %d\n",
                  count, qh_pointid(atvertex->point), qh_pointid(vertex->point)));
            if (printvridge) {
              if (inorder && qh hull_dim == 3+1) /* 3-d Voronoi diagram */
                centers= qh_detvridge3(atvertex, vertex);
              else
                centers= qh_detvridge(vertex);
              (*printvridge)(fp, atvertex, vertex, centers, unbounded);
              qh_settempfree(¢ers);
            }
          }
        }
      }
    }
  }
  FOREACHneighbor_(atvertex)
    neighbor->seen= False;
  qh_settempfree(&tricenters);
  return totridges;
} /* eachvoronoi */


/*---------------------------------

  qh_eachvoronoi_all( fp, printvridge, isUpper, innerouter, inorder )
    visit all Voronoi ridges

    innerouter:
      see qh_eachvoronoi()

    if inorder
      orders vertices for 3-d Voronoi diagrams

  returns
    total number of ridges

    if isUpper == facet->upperdelaunay  (i.e., a Vornoi vertex)
      facet->visitid= Voronoi vertex index(same as 'o' format)
    else
      facet->visitid= 0

    if printvridge,
      calls printvridge( fp, vertex, vertexA, centers)
      [see qh_eachvoronoi]

  notes:
    Not used for qhull.exe
    same effect as qh_printvdiagram but ridges not sorted by point id
*/
int qh_eachvoronoi_all(FILE *fp, printvridgeT printvridge, boolT isUpper, qh_RIDGE innerouter, boolT inorder) {
  facetT *facet;
  vertexT *vertex;
  int numcenters= 1;  /* vertex 0 is vertex-at-infinity */
  int totridges= 0;

  qh_clearcenters(qh_ASvoronoi);
  qh_vertexneighbors();
  maximize_(qh visit_id, (unsigned int)qh num_facets);
  FORALLfacets {
    facet->visitid= 0;
    facet->seen= False;
    facet->seen2= True;
  }
  FORALLfacets {
    if (facet->upperdelaunay == isUpper)
      facet->visitid= (unsigned int)(numcenters++);
  }
  FORALLvertices
    vertex->seen= False;
  FORALLvertices {
    if (qh GOODvertex > 0 && qh_pointid(vertex->point)+1 != qh GOODvertex)
      continue;
    totridges += qh_eachvoronoi(fp, printvridge, vertex,
                   !qh_ALL, innerouter, inorder);
  }
  return totridges;
} /* eachvoronoi_all */

/*---------------------------------

  qh_facet2point( facet, point0, point1, mindist )
    return two projected temporary vertices for a 2-d facet
    may be non-simplicial

  returns:
    point0 and point1 oriented and projected to the facet
    returns mindist (maximum distance below plane)
*/
void qh_facet2point(facetT *facet, pointT **point0, pointT **point1, realT *mindist) {
  vertexT *vertex0, *vertex1;
  realT dist;

  if (facet->toporient ^ qh_ORIENTclock) {
    vertex0= SETfirstt_(facet->vertices, vertexT);
    vertex1= SETsecondt_(facet->vertices, vertexT);
  }else {
    vertex1= SETfirstt_(facet->vertices, vertexT);
    vertex0= SETsecondt_(facet->vertices, vertexT);
  }
  zadd_(Zdistio, 2);
  qh_distplane(vertex0->point, facet, &dist);
  *mindist= dist;
  *point0= qh_projectpoint(vertex0->point, facet, dist);
  qh_distplane(vertex1->point, facet, &dist);
  minimize_(*mindist, dist);
  *point1= qh_projectpoint(vertex1->point, facet, dist);
} /* facet2point */


/*---------------------------------

  qh_facetvertices( facetlist, facets, allfacets )
    returns temporary set of vertices in a set and/or list of facets
    if allfacets, ignores qh_skipfacet()

  returns:
    vertices with qh.vertex_visit

  notes:
    optimized for allfacets of facet_list

  design:
    if allfacets of facet_list
      create vertex set from vertex_list
    else
      for each selected facet in facets or facetlist
        append unvisited vertices to vertex set
*/
setT *qh_facetvertices(facetT *facetlist, setT *facets, boolT allfacets) {
  setT *vertices;
  facetT *facet, **facetp;
  vertexT *vertex, **vertexp;

  qh vertex_visit++;
  if (facetlist == qh facet_list && allfacets && !facets) {
    vertices= qh_settemp(qh num_vertices);
    FORALLvertices {
      vertex->visitid= qh vertex_visit;
      qh_setappend(&vertices, vertex);
    }
  }else {
    vertices= qh_settemp(qh TEMPsize);
    FORALLfacet_(facetlist) {
      if (!allfacets && qh_skipfacet(facet))
        continue;
      FOREACHvertex_(facet->vertices) {
        if (vertex->visitid != qh vertex_visit) {
          vertex->visitid= qh vertex_visit;
          qh_setappend(&vertices, vertex);
        }
      }
    }
  }
  FOREACHfacet_(facets) {
    if (!allfacets && qh_skipfacet(facet))
      continue;
    FOREACHvertex_(facet->vertices) {
      if (vertex->visitid != qh vertex_visit) {
        vertex->visitid= qh vertex_visit;
        qh_setappend(&vertices, vertex);
      }
    }
  }
  return vertices;
} /* facetvertices */

/*---------------------------------

  qh_geomplanes( facet, outerplane, innerplane )
    return outer and inner planes for Geomview
    qh.PRINTradius is size of vertices and points (includes qh.JOGGLEmax)

  notes:
    assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
*/
void qh_geomplanes(facetT *facet, realT *outerplane, realT *innerplane) {
  realT radius;

  if (qh MERGING || qh JOGGLEmax < REALmax/2) {
    qh_outerinner(facet, outerplane, innerplane);
    radius= qh PRINTradius;
    if (qh JOGGLEmax < REALmax/2)
      radius -= qh JOGGLEmax * sqrt((realT)qh hull_dim);  /* already accounted for in qh_outerinner() */
    *outerplane += radius;
    *innerplane -= radius;
    if (qh PRINTcoplanar || qh PRINTspheres) {
      *outerplane += qh MAXabs_coord * qh_GEOMepsilon;
      *innerplane -= qh MAXabs_coord * qh_GEOMepsilon;
    }
  }else
    *innerplane= *outerplane= 0;
} /* geomplanes */


/*---------------------------------

  qh_markkeep( facetlist )
    restrict good facets for qh.KEEParea, qh.KEEPmerge, and qh.KEEPminArea
    ignores visible facets (!part of convex hull)

  returns:
    may clear facet->good
    recomputes qh.num_good

  notes:
    only called by qh_prepare_output after qh_findgood_all
    does not throw errors except memory/corruption of qset.c

  design:
    get set of good facets
    if qh.KEEParea
      sort facets by area
      clear facet->good for all but n largest facets
    if qh.KEEPmerge
      sort facets by merge count
      clear facet->good for all but n most merged facets
    if qh.KEEPminarea
      clear facet->good if area too small
    update qh.num_good
*/
void qh_markkeep(facetT *facetlist) {
  facetT *facet, **facetp;
  setT *facets= qh_settemp(qh num_facets);
  int size, count;

  trace2((qh ferr, 2006, "qh_markkeep: only keep %d largest and/or %d most merged facets and/or min area %.2g\n",
          qh KEEParea, qh KEEPmerge, qh KEEPminArea));
  FORALLfacet_(facetlist) {
    if (!facet->visible && facet->good)
      qh_setappend(&facets, facet);
  }
  size= qh_setsize(facets);
  if (qh KEEParea) {
    qsort(SETaddr_(facets, facetT), (size_t)size,
             sizeof(facetT *), qh_compare_facetarea);
    if ((count= size - qh KEEParea) > 0) {
      FOREACHfacet_(facets) {
        facet->good= False;
        if (--count == 0)
          break;
      }
    }
  }
  if (qh KEEPmerge) {
    qsort(SETaddr_(facets, facetT), (size_t)size,
             sizeof(facetT *), qh_compare_nummerge);
    if ((count= size - qh KEEPmerge) > 0) {
      FOREACHfacet_(facets) {
        facet->good= False;
        if (--count == 0)
          break;
      }
    }
  }
  if (qh KEEPminArea < REALmax/2) {
    FOREACHfacet_(facets) {
      if (!facet->isarea || facet->f.area < qh KEEPminArea)
        facet->good= False;
    }
  }
  qh_settempfree(&facets);
  count= 0;
  FORALLfacet_(facetlist) {
    if (facet->good)
      count++;
  }
  qh num_good= count;
} /* markkeep */


/*---------------------------------

  qh_markvoronoi( facetlist, facets, printall, isLower, numcenters )
    mark voronoi vertices for printing by site pairs

  returns:
    temporary set of vertices indexed by pointid
    isLower set if printing lower hull (i.e., at least one facet is lower hull)
    numcenters= total number of Voronoi vertices
    bumps qh.printoutnum for vertex-at-infinity
    clears all facet->seen and sets facet->seen2

    if selected
      facet->visitid= Voronoi vertex id
    else if upper hull (or 'Qu' and lower hull)
      facet->visitid= 0
    else
      facet->visitid >= qh num_facets

  notes:
    ignores qh.ATinfinity, if defined
*/
setT *qh_markvoronoi(facetT *facetlist, setT *facets, boolT printall, boolT *isLowerp, int *numcentersp) {
  int numcenters=0;
  facetT *facet, **facetp;
  setT *vertices;
  boolT isLower= False;

  qh printoutnum++;
  qh_clearcenters(qh_ASvoronoi);  /* in case, qh_printvdiagram2 called by user */
  qh_vertexneighbors();
  vertices= qh_pointvertex();
  if (qh ATinfinity)
    SETelem_(vertices, qh num_points-1)= NULL;
  qh visit_id++;
  maximize_(qh visit_id, (unsigned int)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= (unsigned int)(numcenters++);
  }
  FOREACHfacet_(facets) {
    if (printall || !qh_skipfacet(facet))
      facet->visitid= (unsigned int)(numcenters++);
  }
  *isLowerp= isLower;
  *numcentersp= numcenters;
  trace2((qh ferr, 2007, "qh_markvoronoi: isLower %d numcenters %d\n", isLower, numcenters));
  return vertices;
} /* markvoronoi */

/*---------------------------------

  qh_order_vertexneighbors( vertex )
    order facet neighbors of vertex by 2-d (orientation), 3-d (adjacency), or n-d (f.visitid,id)

  notes:
    error if qh_vertexneighbors not called beforehand
    only 2-d orients the neighbors
    for 4-d and higher
      set or clear f.visitid for qh_compare_facetvisit
      for example, use qh_markvoronoi (e.g., qh_printvornoi) or qh_countfacets (e.g., qh_printvneighbors)

  design (2-d):
    see qh_printextremes_2d
  design (3-d):
    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
  design (n-d):
    qsort by f.visitid, or f.facetid (qh_compare_facetvisit)
    facet_id is negated (sorted before visit_id facets)
*/
void qh_order_vertexneighbors(vertexT *vertex) {
  setT *newset;
  facetT *facet, *facetA, *facetB, *neighbor, **neighborp;
  vertexT *vertexA;
  int numneighbors;

  trace4((qh ferr, 4018, "qh_order_vertexneighbors: order facet neighbors of v%d by 2-d (orientation), 3-d (adjacency), or n-d (f.visitid,id)\n", vertex->id));
  if (!qh VERTEXneighbors) {
    qh_fprintf(qh ferr, 6428, "qhull internal error (qh_order_vertexneighbors): call qh_vertexneighbors before calling qh_order_vertexneighbors\n");
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  if (qh hull_dim == 2) {
    facetA= SETfirstt_(vertex->neighbors, facetT);
    if (facetA->toporient ^ qh_ORIENTclock)
      vertexA= SETfirstt_(facetA->vertices, vertexT);
    else
      vertexA= SETsecondt_(facetA->vertices, vertexT);
    if (vertexA!=vertex) {
      facetB= SETsecondt_(vertex->neighbors, facetT);
      SETfirst_(vertex->neighbors)= facetB;
      SETsecond_(vertex->neighbors)= facetA;
    }
  }else if (qh hull_dim == 3) {
    newset= qh_settemp(qh_setsize(vertex->neighbors));
    facet= (facetT *)qh_setdellast(vertex->neighbors);
    qh_setappend(&newset, facet);
    while (qh_setsize(vertex->neighbors)) {
      FOREACHneighbor_(vertex) {
        if (qh_setin(facet->neighbors, neighbor)) {
          qh_setdel(vertex->neighbors, neighbor);
          qh_setappend(&newset, neighbor);
          facet= neighbor;
          break;
        }
      }
      if (!neighbor) {
        qh_fprintf(qh ferr, 6066, "qhull internal error (qh_order_vertexneighbors): no neighbor of v%d for f%d\n",
          vertex->id, facet->id);
        qh_errexit(qh_ERRqhull, facet, NULL);
      }
    }
    qh_setfree(&vertex->neighbors);
    qh_settemppop();
    vertex->neighbors= newset;
  }else { /* qh.hull_dim >= 4 */
    numneighbors= qh_setsize(vertex->neighbors);
    qsort(SETaddr_(vertex->neighbors, facetT), (size_t)numneighbors,
        sizeof(facetT *), qh_compare_facetvisit);
  }
} /* order_vertexneighbors */

/*---------------------------------

  qh_prepare_output( )
    prepare for qh_produce_output2() according to
      qh.KEEPminArea, KEEParea, KEEPmerge, GOODvertex, GOODthreshold, GOODpoint, ONLYgood, SPLITthresholds
    does not reset facet->good

  notes
    called by qh_produce_output, qh_new_qhull, Qhull.outputQhull
    except for PRINTstatistics, no-op if previously called with same options
*/
void qh_prepare_output(void) {
  if (qh VORONOI) {
    qh_clearcenters(qh_ASvoronoi);  /* must be before qh_triangulate */
    qh_vertexneighbors();
  }
  if (qh TRIangulate && !qh hasTriangulation) {
    qh_triangulate();
    if (qh VERIFYoutput && !qh CHECKfrequently)
      qh_checkpolygon(qh facet_list);
  }
  qh_findgood_all(qh facet_list);
  if (qh GETarea)
    qh_getarea(qh facet_list);
  if (qh KEEParea || qh KEEPmerge || qh KEEPminArea < REALmax/2)
    qh_markkeep(qh facet_list);
  if (qh PRINTstatistics)
    qh_collectstatistics();
}

/*---------------------------------

  qh_printafacet( fp, format, facet, printall )
    print facet to fp in given output format (see qh.PRINTout)

  returns:
    nop if !printall and qh_skipfacet()
    nop if visible facet and NEWfacets and format != PRINTfacets
    must match qh_countfacets

  notes
    preserves qh.visit_id
    facet->normal may be null if PREmerge/MERGEexact and STOPcone before merge

  see
    qh_printbegin() and qh_printend()

  design:
    test for printing facet
    call appropriate routine for format
    or output results directly
*/
void qh_printafacet(FILE *fp, qh_PRINT format, facetT *facet, boolT printall) {
  realT color[4], offset, dist, outerplane, innerplane;
  boolT zerodiv;
  coordT *point, *normp, *coordp, **pointp, *feasiblep;
  int k;
  vertexT *vertex, **vertexp;
  facetT *neighbor, **neighborp;

  if (!printall && qh_skipfacet(facet))
    return;
  if (facet->visible && qh NEWfacets && format != qh_PRINTfacets)
    return;
  qh printoutnum++;
  switch (format) {
  case qh_PRINTarea:
    if (facet->isarea) {
      qh_fprintf(fp, 9009, qh_REAL_1, facet->f.area);
      qh_fprintf(fp, 9010, "\n");
    }else
      qh_fprintf(fp, 9011, "0\n");
    break;
  case qh_PRINTcoplanars:
    qh_fprintf(fp, 9012, "%d", qh_setsize(facet->coplanarset));
    FOREACHpoint_(facet->coplanarset)
      qh_fprintf(fp, 9013, " %d", qh_pointid(point));
    qh_fprintf(fp, 9014, "\n");
    break;
  case qh_PRINTcentrums:
    qh_printcenter(fp, format, NULL, facet);
    break;
  case qh_PRINTfacets:
    qh_printfacet(fp, facet);
    break;
  case qh_PRINTfacets_xridge:
    qh_printfacetheader(fp, facet);
    break;
  case qh_PRINTgeom:  /* either 2 , 3, or 4-d by qh_printbegin */
    if (!facet->normal)
      break;
    for (k=qh hull_dim; k--; ) {
      color[k]= (facet->normal[k]+1.0)/2.0;
      maximize_(color[k], -1.0);
      minimize_(color[k], +1.0);
    }
    qh_projectdim3(color, color);
    if (qh PRINTdim != qh hull_dim)
      qh_normalize2(color, 3, True, NULL, NULL);
    if (qh hull_dim <= 2)
      qh_printfacet2geom(fp, facet, color);
    else if (qh hull_dim == 3) {
      if (facet->simplicial)
        qh_printfacet3geom_simplicial(fp, facet, color);
      else
        qh_printfacet3geom_nonsimplicial(fp, facet, color);
    }else {
      if (facet->simplicial)
        qh_printfacet4geom_simplicial(fp, facet, color);
      else
        qh_printfacet4geom_nonsimplicial(fp, facet, color);
    }
    break;
  case qh_PRINTids:
    qh_fprintf(fp, 9015, "%d\n", facet->id);
    break;
  case qh_PRINTincidences:
  case qh_PRINToff:
  case qh_PRINTtriangles:
    if (qh hull_dim == 3 && format != qh_PRINTtriangles)
      qh_printfacet3vertex(fp, facet, format);
    else if (facet->simplicial || qh hull_dim == 2 || format == qh_PRINToff)
      qh_printfacetNvertex_simplicial(fp, facet, format);
    else
      qh_printfacetNvertex_nonsimplicial(fp, facet, qh printoutvar++, format);
    break;
  case qh_PRINTinner:
    qh_outerinner(facet, NULL, &innerplane);
    offset= facet->offset - innerplane;
    goto LABELprintnorm;
    break; /* prevent warning */
  case qh_PRINTmerges:
    qh_fprintf(fp, 9016, "%d\n", facet->nummerge);
    break;
  case qh_PRINTnormals:
    offset= facet->offset;
    goto LABELprintnorm;
    break; /* prevent warning */
  case qh_PRINTouter:
    qh_outerinner(facet, &outerplane, NULL);
    offset= facet->offset - outerplane;
  LABELprintnorm:
    if (!facet->normal) {
      qh_fprintf(fp, 9017, "no normal for facet f%d\n", facet->id);
      break;
    }
    if (qh CDDoutput) {
      qh_fprintf(fp, 9018, qh_REAL_1, -offset);
      for (k=0; k < qh hull_dim; k++)
        qh_fprintf(fp, 9019, qh_REAL_1, -facet->normal[k]);
    }else {
      for (k=0; k < qh hull_dim; k++)
        qh_fprintf(fp, 9020, qh_REAL_1, facet->normal[k]);
      qh_fprintf(fp, 9021, qh_REAL_1, offset);
    }
    qh_fprintf(fp, 9022, "\n");
    break;
  case qh_PRINTmathematica:  /* either 2 or 3-d by qh_printbegin */
  case qh_PRINTmaple:
    if (qh hull_dim == 2)
      qh_printfacet2math(fp, facet, format, qh printoutvar++);
    else
      qh_printfacet3math(fp, facet, format, qh printoutvar++);
    break;
  case qh_PRINTneighbors:
    qh_fprintf(fp, 9023, "%d", qh_setsize(facet->neighbors));
    FOREACHneighbor_(facet)
      qh_fprintf(fp, 9024, " %d",
               neighbor->visitid ? neighbor->visitid - 1: 0 - neighbor->id);
    qh_fprintf(fp, 9025, "\n");
    break;
  case qh_PRINTpointintersect:
    if (!qh feasible_point) {
      qh_fprintf(qh ferr, 6067, "qhull input error (qh_printafacet): option 'Fp' needs qh feasible_point\n");
      qh_errexit(qh_ERRinput, NULL, NULL);
    }
    if (facet->offset > 0)
      goto LABELprintinfinite;
    point= coordp= (coordT *)qh_memalloc(qh normal_size);
    normp= facet->normal;
    feasiblep= qh feasible_point;
    if (facet->offset < -qh MINdenom) {
      for (k=qh hull_dim; k--; )
        *(coordp++)= (*(normp++) / - facet->offset) + *(feasiblep++);
    }else {
      for (k=qh hull_dim; k--; ) {
        *(coordp++)= qh_divzero(*(normp++), facet->offset, qh MINdenom_1,
                                 &zerodiv) + *(feasiblep++);
        if (zerodiv) {
          qh_memfree(point, qh normal_size);
          goto LABELprintinfinite;
        }
      }
    }
    qh_printpoint(fp, NULL, point);
    qh_memfree(point, qh normal_size);
    break;
  LABELprintinfinite:
    for (k=qh hull_dim; k--; )
      qh_fprintf(fp, 9026, qh_REAL_1, qh_INFINITE);
    qh_fprintf(fp, 9027, "\n");
    break;
  case qh_PRINTpointnearest:
    FOREACHpoint_(facet->coplanarset) {
      int id, id2;
      vertex= qh_nearvertex(facet, point, &dist);
      id= qh_pointid(vertex->point);
      id2= qh_pointid(point);
      qh_fprintf(fp, 9028, "%d %d %d " qh_REAL_1 "\n", id, id2, facet->id, dist);
    }
    break;
  case qh_PRINTpoints:  /* VORONOI only by qh_printbegin */
    if (qh CDDoutput)
      qh_fprintf(fp, 9029, "1 ");
    qh_printcenter(fp, format, NULL, facet);
    break;
  case qh_PRINTvertices:
    qh_fprintf(fp, 9030, "%d", qh_setsize(facet->vertices));
    FOREACHvertex_(facet->vertices)
      qh_fprintf(fp, 9031, " %d", qh_pointid(vertex->point));
    qh_fprintf(fp, 9032, "\n");
    break;
  default:
    break;
  }
} /* printafacet */

/*---------------------------------

  qh_printbegin( )
    prints header for all output formats

  returns:
    checks for valid format

  notes:
    uses qh.visit_id for 3/4off
    changes qh.interior_point if printing centrums
    qh_countfacets clears facet->visitid for non-good facets

  see
    qh_printend() and qh_printafacet()

  design:
    count facets and related statistics
    print header for format
*/
void qh_printbegin(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {
  int numfacets, numsimplicial, numridges, totneighbors, numcoplanars, numtricoplanars;
  int i, num;
  facetT *facet, **facetp;
  vertexT *vertex, **vertexp;
  setT *vertices;
  pointT *point, **pointp, *pointtemp;

  qh printoutnum= 0;
  qh_countfacets(facetlist, facets, printall, &numfacets, &numsimplicial,
      &totneighbors, &numridges, &numcoplanars, &numtricoplanars);
  switch (format) {
  case qh_PRINTnone:
    break;
  case qh_PRINTarea:
    qh_fprintf(fp, 9033, "%d\n", numfacets);
    break;
  case qh_PRINTcoplanars:
    qh_fprintf(fp, 9034, "%d\n", numfacets);
    break;
  case qh_PRINTcentrums:
    if (qh CENTERtype == qh_ASnone)
      qh_clearcenters(qh_AScentrum);
    qh_fprintf(fp, 9035, "%d\n%d\n", qh hull_dim, numfacets);
    break;
  case qh_PRINTfacets:
  case qh_PRINTfacets_xridge:
    if (facetlist)
      qh_printvertexlist(fp, "Vertices and facets:\n", facetlist, facets, printall);
    break;
  case qh_PRINTgeom:
    if (qh hull_dim > 4)  /* qh_initqhull_globals also checks */
      goto LABELnoformat;
    if (qh VORONOI && qh hull_dim > 3)  /* PRINTdim == DROPdim == hull_dim-1 */
      goto LABELnoformat;
    if (qh hull_dim == 2 && (qh PRINTridges || qh DOintersections))
      qh_fprintf(qh ferr, 7049, "qhull warning: output for ridges and intersections not implemented in 2-d\n");
    if (qh hull_dim == 4 && (qh PRINTinner || qh PRINTouter ||
                             (qh PRINTdim == 4 && qh PRINTcentrums)))
      qh_fprintf(qh ferr, 7050, "qhull warning: output for outer/inner planes and centrums not implemented in 4-d\n");
    if (qh PRINTdim == 4 && (qh PRINTspheres))
      qh_fprintf(qh ferr, 7051, "qhull warning: output for vertices not implemented in 4-d\n");
    if (qh PRINTdim == 4 && qh DOintersections && qh PRINTnoplanes)
      qh_fprintf(qh ferr, 7052, "qhull warning: 'Gnh' generates no output in 4-d\n");
    if (qh PRINTdim == 2) {
      qh_fprintf(fp, 9036, "{appearance {linewidth 3} LIST # %s | %s\n",
              qh rbox_command, qh qhull_command);
    }else if (qh PRINTdim == 3) {
      qh_fprintf(fp, 9037, "{appearance {+edge -evert linewidth 2} LIST # %s | %s\n",
              qh rbox_command, qh qhull_command);
    }else if (qh PRINTdim == 4) {
      qh visit_id++;
      num= 0;
      FORALLfacet_(facetlist)    /* get number of ridges to be printed */
        qh_printend4geom(NULL, facet, &num, printall);
      FOREACHfacet_(facets)
        qh_printend4geom(NULL, facet, &num, printall);
      qh ridgeoutnum= num;
      qh printoutvar= 0;  /* counts number of ridges in output */
      qh_fprintf(fp, 9038, "LIST # %s | %s\n", qh rbox_command, qh qhull_command);
    }

    if (qh PRINTdots) {
      qh printoutnum++;
      num= qh num_points + qh_setsize(qh other_points);
      if (qh DELAUNAY && qh ATinfinity)
        num--;
      if (qh PRINTdim == 4)
        qh_fprintf(fp, 9039, "4VECT %d %d 1\n", num, num);
      else
        qh_fprintf(fp, 9040, "VECT %d %d 1\n", num, num);

      for (i=num; i--; ) {
        if (i % 20 == 0)
          qh_fprintf(fp, 9041, "\n");
        qh_fprintf(fp, 9042, "1 ");
      }
      qh_fprintf(fp, 9043, "# 1 point per line\n1 ");
      for (i=num-1; i--; ) { /* num at least 3 for D2 */
        if (i % 20 == 0)
          qh_fprintf(fp, 9044, "\n");
        qh_fprintf(fp, 9045, "0 ");
      }
      qh_fprintf(fp, 9046, "# 1 color for all\n");
      FORALLpoints {
        if (!qh DELAUNAY || !qh ATinfinity || qh_pointid(point) != qh num_points-1) {
          if (qh PRINTdim == 4)
            qh_printpoint(fp, NULL, point);
            else
              qh_printpoint3(fp, point);
        }
      }
      FOREACHpoint_(qh other_points) {
        if (qh PRINTdim == 4)
          qh_printpoint(fp, NULL, point);
        else
          qh_printpoint3(fp, point);
      }
      qh_fprintf(fp, 9047, "0 1 1 1  # color of points\n");
    }

    if (qh PRINTdim == 4  && !qh PRINTnoplanes)
      /* 4dview loads up multiple 4OFF objects slowly */
      qh_fprintf(fp, 9048, "4OFF %d %d 1\n", 3*qh ridgeoutnum, qh ridgeoutnum);
    qh PRINTcradius= 2 * qh DISTround;  /* include test DISTround */
    if (qh PREmerge) {
      maximize_(qh PRINTcradius, qh premerge_centrum + qh DISTround);
    }else if (qh POSTmerge)
      maximize_(qh PRINTcradius, qh postmerge_centrum + qh DISTround);
    qh PRINTradius= qh PRINTcradius;
    if (qh PRINTspheres + qh PRINTcoplanar)
      maximize_(qh PRINTradius, qh MAXabs_coord * qh_MINradius);
    if (qh premerge_cos < REALmax/2) {
      maximize_(qh PRINTradius, (1- qh premerge_cos) * qh MAXabs_coord);
    }else if (!qh PREmerge && qh POSTmerge && qh postmerge_cos < REALmax/2) {
      maximize_(qh PRINTradius, (1- qh postmerge_cos) * qh MAXabs_coord);
    }
    maximize_(qh PRINTradius, qh MINvisible);
    if (qh JOGGLEmax < REALmax/2)
      qh PRINTradius += qh JOGGLEmax * sqrt((realT)qh hull_dim);
    if (qh PRINTdim != 4 &&
        (qh PRINTcoplanar || qh PRINTspheres || qh PRINTcentrums)) {
      vertices= qh_facetvertices(facetlist, facets, printall);
      if (qh PRINTspheres && qh PRINTdim <= 3)
        qh_printspheres(fp, vertices, qh PRINTradius);
      if (qh PRINTcoplanar || qh PRINTcentrums) {
        qh firstcentrum= True;
        if (qh PRINTcoplanar&& !qh PRINTspheres) {
          FOREACHvertex_(vertices)
            qh_printpointvect2(fp, vertex->point, NULL, qh interior_point, qh PRINTradius);
        }
        FORALLfacet_(facetlist) {
          if (!printall && qh_skipfacet(facet))
            continue;
          if (!facet->normal)
            continue;
          if (qh PRINTcentrums && qh PRINTdim <= 3)
            qh_printcentrum(fp, facet, qh PRINTcradius);
          if (!qh PRINTcoplanar)
            continue;
          FOREACHpoint_(facet->coplanarset)
            qh_printpointvect2(fp, point, facet->normal, NULL, qh PRINTradius);
          FOREACHpoint_(facet->outsideset)
            qh_printpointvect2(fp, point, facet->normal, NULL, qh PRINTradius);
        }
        FOREACHfacet_(facets) {
          if (!printall && qh_skipfacet(facet))
            continue;
          if (!facet->normal)
            continue;
          if (qh PRINTcentrums && qh PRINTdim <= 3)
            qh_printcentrum(fp, facet, qh PRINTcradius);
          if (!qh PRINTcoplanar)
            continue;
          FOREACHpoint_(facet->coplanarset)
            qh_printpointvect2(fp, point, facet->normal, NULL, qh PRINTradius);
          FOREACHpoint_(facet->outsideset)
            qh_printpointvect2(fp, point, facet->normal, NULL, qh PRINTradius);
        }
      }
      qh_settempfree(&vertices);
    }
    qh visit_id++; /* for printing hyperplane intersections */
    break;
  case qh_PRINTids:
    qh_fprintf(fp, 9049, "%d\n", numfacets);
    break;
  case qh_PRINTincidences:
    if (qh VORONOI && qh PRINTprecision)
      qh_fprintf(qh ferr, 7053, "qhull warning: input sites of Delaunay regions (option 'i').  Use option 'p' or 'o' for Voronoi centers.  Disable warning with option 'Pp'\n");
    qh printoutvar= (int)qh vertex_id;  /* centrum id for 4-d+, non-simplicial facets */
    if (qh hull_dim <= 3)
      qh_fprintf(fp, 9050, "%d\n", numfacets);
    else
      qh_fprintf(fp, 9051, "%d\n", numsimplicial+numridges);
    break;
  case qh_PRINTinner:
  case qh_PRINTnormals:
  case qh_PRINTouter:
    if (qh CDDoutput)
      qh_fprintf(fp, 9052, "%s | %s\nbegin\n    %d %d real\n", qh rbox_command,
            qh qhull_command, numfacets, qh hull_dim+1);
    else
      qh_fprintf(fp, 9053, "%d\n%d\n", qh hull_dim+1, numfacets);
    break;
  case qh_PRINTmathematica:
  case qh_PRINTmaple:
    if (qh hull_dim > 3)  /* qh_initbuffers also checks */
      goto LABELnoformat;
    if (qh VORONOI)
      qh_fprintf(qh ferr, 7054, "qhull warning: output is the Delaunay triangulation\n");
    if (format == qh_PRINTmaple) {
      if (qh hull_dim == 2)
        qh_fprintf(fp, 9054, "PLOT(CURVES(\n");
      else
        qh_fprintf(fp, 9055, "PLOT3D(POLYGONS(\n");
    }else
      qh_fprintf(fp, 9056, "{\n");
    qh printoutvar= 0;   /* counts number of facets for notfirst */
    break;
  case qh_PRINTmerges:
    qh_fprintf(fp, 9057, "%d\n", numfacets);
    break;
  case qh_PRINTpointintersect:
    qh_fprintf(fp, 9058, "%d\n%d\n", qh hull_dim, numfacets);
    break;
  case qh_PRINTneighbors:
    qh_fprintf(fp, 9059, "%d\n", numfacets);
    break;
  case qh_PRINToff:
  case qh_PRINTtriangles:
    if (qh VORONOI)
      goto LABELnoformat;
    num= qh hull_dim;
    if (format == qh_PRINToff || qh hull_dim == 2)
      qh_fprintf(fp, 9060, "%d\n%d %d %d\n", num,
        qh num_points+qh_setsize(qh other_points), numfacets, totneighbors/2);
    else { /* qh_PRINTtriangles */
      qh printoutvar= qh num_points+qh_setsize(qh other_points); /* first centrum */
      if (qh DELAUNAY)
        num--;  /* drop last dimension */
      qh_fprintf(fp, 9061, "%d\n%d %d %d\n", num, qh printoutvar
        + numfacets - numsimplicial, numsimplicial + numridges, totneighbors/2);
    }
    FORALLpoints
      qh_printpointid(qh fout, NULL, num, point, qh_IDunknown);
    FOREACHpoint_(qh other_points)
      qh_printpointid(qh fout, NULL, num, point, qh_IDunknown);
    if (format == qh_PRINTtriangles && qh hull_dim > 2) {
      FORALLfacets {
        if (!facet->simplicial && facet->visitid)
          qh_printcenter(qh fout, format, NULL, facet);
      }
    }
    break;
  case qh_PRINTpointnearest:
    qh_fprintf(fp, 9062, "%d\n", numcoplanars);
    break;
  case qh_PRINTpoints:
    if (!qh VORONOI)
      goto LABELnoformat;
    if (qh CDDoutput)
      qh_fprintf(fp, 9063, "%s | %s\nbegin\n%d %d real\n", qh rbox_command,
           qh qhull_command, numfacets, qh hull_dim);
    else
      qh_fprintf(fp, 9064, "%d\n%d\n", qh hull_dim-1, numfacets);
    break;
  case qh_PRINTvertices:
    qh_fprintf(fp, 9065, "%d\n", numfacets);
    break;
  case qh_PRINTsummary:
  default:
  LABELnoformat:
    qh_fprintf(qh ferr, 6068, "qhull internal error (qh_printbegin): can not use this format for dimension %d\n",
         qh hull_dim);
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
} /* printbegin */

/*---------------------------------

  qh_printcenter( fp, string, facet )
    print facet->center as centrum or Voronoi center
    string may be NULL.  Don't include '%' codes.
    nop if qh CENTERtype neither CENTERvoronoi nor CENTERcentrum
    if upper envelope of Delaunay triangulation and point at-infinity
      prints qh_INFINITE instead;

  notes:
    defines facet->center if needed
    if format=PRINTgeom, adds a 0 if would otherwise be 2-d
    Same as QhullFacet::printCenter
*/
void qh_printcenter(FILE *fp, qh_PRINT format, const char *string, facetT *facet) {
  int k, num;

  if (qh CENTERtype != qh_ASvoronoi && qh CENTERtype != qh_AScentrum)
    return;
  if (string)
    qh_fprintf(fp, 9066, string);
  if (qh CENTERtype == qh_ASvoronoi) {
    num= qh hull_dim-1;
    if (!facet->normal || !facet->upperdelaunay || !qh ATinfinity) {
      if (!facet->center)
        facet->center= qh_facetcenter(facet->vertices);
      for (k=0; k < num; k++)
        qh_fprintf(fp, 9067, qh_REAL_1, facet->center[k]);
    }else {
      for (k=0; k < num; k++)
        qh_fprintf(fp, 9068, qh_REAL_1, qh_INFINITE);
    }
  }else /* qh.CENTERtype == qh_AScentrum */ {
    num= qh hull_dim;
    if (format == qh_PRINTtriangles && qh DELAUNAY)
      num--;
    if (!facet->center)
      facet->center= qh_getcentrum(facet);
    for (k=0; k < num; k++)
      qh_fprintf(fp, 9069, qh_REAL_1, facet->center[k]);
  }
  if (format == qh_PRINTgeom && num == 2)
    qh_fprintf(fp, 9070, " 0\n");
  else
    qh_fprintf(fp, 9071, "\n");
} /* printcenter */

/*---------------------------------

  qh_printcentrum( fp, facet, radius )
    print centrum for a facet in OOGL format
    radius defines size of centrum
    2-d or 3-d only

  returns:
    defines facet->center if needed
*/
void qh_printcentrum(FILE *fp, facetT *facet, realT radius) {
  pointT *centrum, *projpt;
  boolT tempcentrum= False;
  realT xaxis[4], yaxis[4], normal[4], dist;
  realT green[3]={0, 1, 0};
  vertexT *apex;
  int k;

  if (qh CENTERtype == qh_AScentrum) {
    if (!facet->center)
      facet->center= qh_getcentrum(facet);
    centrum= facet->center;
  }else {
    centrum= qh_getcentrum(facet);
    tempcentrum= True;
  }
  qh_fprintf(fp, 9072, "{appearance {-normal -edge normscale 0} ");
  if (qh firstcentrum) {
    qh firstcentrum= False;
    qh_fprintf(fp, 9073, "{INST geom { define centrum CQUAD  # f%d\n\
-0.3 -0.3 0.0001     0 0 1 1\n\
 0.3 -0.3 0.0001     0 0 1 1\n\
 0.3  0.3 0.0001     0 0 1 1\n\
-0.3  0.3 0.0001     0 0 1 1 } transform { \n", facet->id);
  }else
    qh_fprintf(fp, 9074, "{INST geom { : centrum } transform { # f%d\n", facet->id);
  apex= SETfirstt_(facet->vertices, vertexT);
  qh_distplane(apex->point, facet, &dist);
  projpt= qh_projectpoint(apex->point, facet, dist);
  for (k=qh hull_dim; k--; ) {
    xaxis[k]= projpt[k] - centrum[k];
    normal[k]= facet->normal[k];
  }
  if (qh hull_dim == 2) {
    xaxis[2]= 0;
    normal[2]= 0;
  }else if (qh hull_dim == 4) {
    qh_projectdim3(xaxis, xaxis);
    qh_projectdim3(normal, normal);
    qh_normalize2(normal, qh PRINTdim, True, NULL, NULL);
  }
  qh_crossproduct(3, xaxis, normal, yaxis);
  qh_fprintf(fp, 9075, "%8.4g %8.4g %8.4g 0\n", xaxis[0], xaxis[1], xaxis[2]);
  qh_fprintf(fp, 9076, "%8.4g %8.4g %8.4g 0\n", yaxis[0], yaxis[1], yaxis[2]);
  qh_fprintf(fp, 9077, "%8.4g %8.4g %8.4g 0\n", normal[0], normal[1], normal[2]);
  qh_printpoint3(fp, centrum);
  qh_fprintf(fp, 9078, "1 }}}\n");
  qh_memfree(projpt, qh normal_size);
  qh_printpointvect(fp, centrum, facet->normal, NULL, radius, green);
  if (tempcentrum)
    qh_memfree(centrum, qh normal_size);
} /* printcentrum */

/*---------------------------------

  qh_printend( fp, format )
    prints trailer for all output formats

  see:
    qh_printbegin() and qh_printafacet()

*/
void qh_printend(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {
  int num;
  facetT *facet, **facetp;

  if (!qh printoutnum)
    qh_fprintf(qh ferr, 7055, "qhull warning: no facets printed\n");
  switch (format) {
  case qh_PRINTgeom:
    if (qh hull_dim == 4 && qh DROPdim < 0  && !qh PRINTnoplanes) {
      qh visit_id++;
      num= 0;
      FORALLfacet_(facetlist)
        qh_printend4geom(fp, facet,&num, printall);
      FOREACHfacet_(facets)
        qh_printend4geom(fp, facet, &num, printall);
      if (num != qh ridgeoutnum || qh printoutvar != qh ridgeoutnum) {
        qh_fprintf(qh ferr, 6069, "qhull internal error (qh_printend): number of ridges %d != number printed %d and at end %d\n", qh ridgeoutnum, qh printoutvar, num);
        qh_errexit(qh_ERRqhull, NULL, NULL);
      }
    }else
      qh_fprintf(fp, 9079, "}\n");
    break;
  case qh_PRINTinner:
  case qh_PRINTnormals:
  case qh_PRINTouter:
    if (qh CDDoutput)
      qh_fprintf(fp, 9080, "end\n");
    break;
  case qh_PRINTmaple:
    qh_fprintf(fp, 9081, "));\n");
    break;
  case qh_PRINTmathematica:
    qh_fprintf(fp, 9082, "}\n");
    break;
  case qh_PRINTpoints:
    if (qh CDDoutput)
      qh_fprintf(fp, 9083, "end\n");
    break;
  default:
    break;
  }
} /* printend */

/*---------------------------------

  qh_printend4geom( fp, facet, numridges, printall )
    helper function for qh_printbegin/printend

  returns:
    number of printed ridges

  notes:
    just counts printed ridges if fp=NULL
    uses facet->visitid
    must agree with qh_printfacet4geom...

  design:
    computes color for facet from its normal
    prints each ridge of facet
*/
void qh_printend4geom(FILE *fp, facetT *facet, int *nump, boolT printall) {
  realT color[3];
  int i, num= *nump;
  facetT *neighbor, **neighborp;
  ridgeT *ridge, **ridgep;

  if (!printall && qh_skipfacet(facet))
    return;
  if (qh PRINTnoplanes || (facet->visible && qh NEWfacets))
    return;
  if (!facet->normal)
    return;
  if (fp) {
    for (i=0; i < 3; i++) {
      color[i]= (facet->normal[i]+1.0)/2.0;
      maximize_(color[i], -1.0);
      minimize_(color[i], +1.0);
    }
  }
  facet->visitid= qh visit_id;
  if (facet->simplicial) {
    FOREACHneighbor_(facet) {
      if (neighbor->visitid != qh visit_id) {
        if (fp)
          qh_fprintf(fp, 9084, "3 %d %d %d %8.4g %8.4g %8.4g 1 # f%d f%d\n",
                 3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],
                 facet->id, neighbor->id);
        num++;
      }
    }
  }else {
    FOREACHridge_(facet->ridges) {
      neighbor= otherfacet_(ridge, facet);
      if (neighbor->visitid != qh visit_id) {
        if (fp)
          qh_fprintf(fp, 9085, "3 %d %d %d %8.4g %8.4g %8.4g 1 #r%d f%d f%d\n",
                 3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],
                 ridge->id, facet->id, neighbor->id);
        num++;
      }
    }
  }
  *nump= num;
} /* printend4geom */

/*---------------------------------

  qh_printextremes( fp, facetlist, facets, printall )
    print extreme points for convex hulls or halfspace intersections

  notes:
    #points, followed by ids, one per line

    sorted by id
    same order as qh_printpoints_out if no coplanar/interior points
*/
void qh_printextremes(FILE *fp, facetT *facetlist, setT *facets, boolT printall) {
  setT *vertices, *points;
  pointT *point;
  vertexT *vertex, **vertexp;
  int id;
  int numpoints=0, point_i, point_n;
  int allpoints= qh num_points + qh_setsize(qh other_points);

  points= qh_settemp(allpoints);
  qh_setzero(points, 0, allpoints);
  vertices= qh_facetvertices(facetlist, facets, printall);
  FOREACHvertex_(vertices) {
    id= qh_pointid(vertex->point);
    if (id >= 0) {
      SETelem_(points, id)= vertex->point;
      numpoints++;
    }
  }
  qh_settempfree(&vertices);
  qh_fprintf(fp, 9086, "%d\n", numpoints);
  FOREACHpoint_i_(points) {
    if (point)
      qh_fprintf(fp, 9087, "%d\n", point_i);
  }
  qh_settempfree(&points);
} /* printextremes */

/*---------------------------------

  qh_printextremes_2d( fp, facetlist, facets, printall )
    prints point ids for facets in qh_ORIENTclock order

  notes:
    #points, followed by ids, one per line
    if facetlist/facets are disjoint than the output includes skips
    errors if facets form a loop
    does not print coplanar points
*/
void qh_printextremes_2d(FILE *fp, facetT *facetlist, setT *facets, boolT printall) {
  int numfacets, numridges, totneighbors, numcoplanars, numsimplicial, numtricoplanars;
  setT *vertices;
  facetT *facet, *startfacet, *nextfacet;
  vertexT *vertexA, *vertexB;

  qh_countfacets(facetlist, facets, printall, &numfacets, &numsimplicial,
      &totneighbors, &numridges, &numcoplanars, &numtricoplanars); /* marks qh visit_id */
  vertices= qh_facetvertices(facetlist, facets, printall);
  qh_fprintf(fp, 9088, "%d\n", qh_setsize(vertices));
  qh_settempfree(&vertices);
  if (!numfacets)
    return;
  facet= startfacet= facetlist ? facetlist : SETfirstt_(facets, facetT);
  qh vertex_visit++;
  qh visit_id++;
  do {
    if (facet->toporient ^ qh_ORIENTclock) {
      vertexA= SETfirstt_(facet->vertices, vertexT);
      vertexB= SETsecondt_(facet->vertices, vertexT);
      nextfacet= SETfirstt_(facet->neighbors, facetT);
    }else {
      vertexA= SETsecondt_(facet->vertices, vertexT);
      vertexB= SETfirstt_(facet->vertices, vertexT);
      nextfacet= SETsecondt_(facet->neighbors, facetT);
    }
    if (facet->visitid == qh visit_id) {
      qh_fprintf(qh ferr, 6218, "qhull internal error (qh_printextremes_2d): loop in facet list.  facet %d nextfacet %d\n",
                 facet->id, nextfacet->id);
      qh_errexit2(qh_ERRqhull, facet, nextfacet);
    }
    if (facet->visitid) {
      if (vertexA->visitid != qh vertex_visit) {
        vertexA->visitid= qh vertex_visit;
        qh_fprintf(fp, 9089, "%d\n", qh_pointid(vertexA->point));
      }
      if (vertexB->visitid != qh vertex_visit) {
        vertexB->visitid= qh vertex_visit;
        qh_fprintf(fp, 9090, "%d\n", qh_pointid(vertexB->point));
      }
    }
    facet->visitid= qh visit_id;
    facet= nextfacet;
  }while (facet && facet != startfacet);
} /* printextremes_2d */

/*---------------------------------

  qh_printextremes_d( fp, facetlist, facets, printall )
    print extreme points of input sites for Delaunay triangulations

  notes:
    #points, followed by ids, one per line

    unordered
*/
void qh_printextremes_d(FILE *fp, facetT *facetlist, setT *facets, boolT printall) {
  setT *vertices;
  vertexT *vertex, **vertexp;
  boolT upperseen, lowerseen;
  facetT *neighbor, **neighborp;
  int numpoints=0;

  vertices= qh_facetvertices(facetlist, facets, printall);
  qh_vertexneighbors();
  FOREACHvertex_(vertices) {
    upperseen= lowerseen= False;
    FOREACHneighbor_(vertex) {
      if (neighbor->upperdelaunay)
        upperseen= True;
      else
        lowerseen= True;
    }
    if (upperseen && lowerseen) {
      vertex->seen= True;
      numpoints++;
    }else
      vertex->seen= False;
  }
  qh_fprintf(fp, 9091, "%d\n", numpoints);
  FOREACHvertex_(vertices) {
    if (vertex->seen)
      qh_fprintf(fp, 9092, "%d\n", qh_pointid(vertex->point));
  }
  qh_settempfree(&vertices);
} /* printextremes_d */

/*---------------------------------

  qh_printfacet( fp, facet )
    prints all fields of a facet to fp

  notes:
    ridges printed in neighbor order
*/
void qh_printfacet(FILE *fp, facetT *facet) {

  qh_printfacetheader(fp, facet);
  if (facet->ridges)
    qh_printfacetridges(fp, facet);
} /* printfacet */


/*---------------------------------

  qh_printfacet2geom( fp, facet, color )
    print facet as part of a 2-d VECT for Geomview

    notes:
      assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
      mindist is calculated within io.c.  maxoutside is calculated elsewhere
      so a DISTround error may have occurred.
*/
void qh_printfacet2geom(FILE *fp, facetT *facet, realT color[3]) {
  pointT *point0, *point1;
  realT mindist, innerplane, outerplane;
  int k;

  qh_facet2point(facet, &point0, &point1, &mindist);
  qh_geomplanes(facet, &outerplane, &innerplane);
  if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner))
    qh_printfacet2geom_points(fp, point0, point1, facet, outerplane, color);
  if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter &&
                outerplane - innerplane > 2 * qh MAXabs_coord * qh_GEOMepsilon)) {
    for (k=3; k--; )
      color[k]= 1.0 - color[k];
    qh_printfacet2geom_points(fp, point0, point1, facet, innerplane, color);
  }
  qh_memfree(point1, qh normal_size);
  qh_memfree(point0, qh normal_size);
} /* printfacet2geom */

/*---------------------------------

  qh_printfacet2geom_points( fp, point1, point2, facet, offset, color )
    prints a 2-d facet as a VECT with 2 points at some offset.
    The points are on the facet's plane.
*/
void qh_printfacet2geom_points(FILE *fp, pointT *point1, pointT *point2,
                               facetT *facet, realT offset, realT color[3]) {
  pointT *p1= point1, *p2= point2;

  qh_fprintf(fp, 9093, "VECT 1 2 1 2 1 # f%d\n", facet->id);
  if (offset != 0.0) {
    p1= qh_projectpoint(p1, facet, -offset);
    p2= qh_projectpoint(p2, facet, -offset);
  }
  qh_fprintf(fp, 9094, "%8.4g %8.4g %8.4g\n%8.4g %8.4g %8.4g\n",
           p1[0], p1[1], 0.0, p2[0], p2[1], 0.0);
  if (offset != 0.0) {
    qh_memfree(p1, qh normal_size);
    qh_memfree(p2, qh normal_size);
  }
  qh_fprintf(fp, 9095, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
} /* printfacet2geom_points */


/*---------------------------------

  qh_printfacet2math( fp, facet, format, notfirst )
    print 2-d Maple or Mathematica output for a facet
    may be non-simplicial

  notes:
    use %16.8f since Mathematica 2.2 does not handle exponential format
    see qh_printfacet3math
*/
void qh_printfacet2math(FILE *fp, facetT *facet, qh_PRINT format, int notfirst) {
  pointT *point0, *point1;
  realT mindist;
  const char *pointfmt;

  qh_facet2point(facet, &point0, &point1, &mindist);
  if (notfirst)
    qh_fprintf(fp, 9096, ",");
  if (format == qh_PRINTmaple)
    pointfmt= "[[%16.8f, %16.8f], [%16.8f, %16.8f]]\n";
  else
    pointfmt= "Line[{{%16.8f, %16.8f}, {%16.8f, %16.8f}}]\n";
  qh_fprintf(fp, 9097, pointfmt, point0[0], point0[1], point1[0], point1[1]);
  qh_memfree(point1, qh normal_size);
  qh_memfree(point0, qh normal_size);
} /* printfacet2math */


/*---------------------------------

  qh_printfacet3geom_nonsimplicial( fp, facet, color )
    print Geomview OFF for a 3-d nonsimplicial facet.
    if DOintersections, prints ridges to unvisited neighbors(qh visit_id)

  notes
    uses facet->visitid for intersections and ridges
*/
void qh_printfacet3geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]) {
  ridgeT *ridge, **ridgep;
  setT *projectedpoints, *vertices;
  vertexT *vertex, **vertexp, *vertexA, *vertexB;
  pointT *projpt, *point, **pointp;
  facetT *neighbor;
  realT dist, outerplane, innerplane;
  int cntvertices, k;
  realT black[3]={0, 0, 0}, green[3]={0, 1, 0};

  qh_geomplanes(facet, &outerplane, &innerplane);
  vertices= qh_facet3vertex(facet); /* oriented */
  cntvertices= qh_setsize(vertices);
  projectedpoints= qh_settemp(cntvertices);
  FOREACHvertex_(vertices) {
    zinc_(Zdistio);
    qh_distplane(vertex->point, facet, &dist);
    projpt= qh_projectpoint(vertex->point, facet, dist);
    qh_setappend(&projectedpoints, projpt);
  }
  if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner))
    qh_printfacet3geom_points(fp, projectedpoints, facet, outerplane, color);
  if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter &&
                outerplane - innerplane > 2 * qh MAXabs_coord * qh_GEOMepsilon)) {
    for (k=3; k--; )
      color[k]= 1.0 - color[k];
    qh_printfacet3geom_points(fp, projectedpoints, facet, innerplane, color);
  }
  FOREACHpoint_(projectedpoints)
    qh_memfree(point, qh normal_size);
  qh_settempfree(&projectedpoints);
  qh_settempfree(&vertices);
  if ((qh DOintersections || qh PRINTridges)
  && (!facet->visible || !qh NEWfacets)) {
    facet->visitid= qh visit_id;
    FOREACHridge_(facet->ridges) {
      neighbor= otherfacet_(ridge, facet);
      if (neighbor->visitid != qh visit_id) {
        if (qh DOintersections)
          qh_printhyperplaneintersection(fp, facet, neighbor, ridge->vertices, black);
        if (qh PRINTridges) {
          vertexA= SETfirstt_(ridge->vertices, vertexT);
          vertexB= SETsecondt_(ridge->vertices, vertexT);
          qh_printline3geom(fp, vertexA->point, vertexB->point, green);
        }
      }
    }
  }
} /* printfacet3geom_nonsimplicial */

/*---------------------------------

  qh_printfacet3geom_points( fp, points, facet, offset )
    prints a 3-d facet as OFF Geomview object.
    offset is relative to the facet's hyperplane
    Facet is determined as a list of points
*/
void qh_printfacet3geom_points(FILE *fp, setT *points, facetT *facet, realT offset, realT color[3]) {
  int k, n= qh_setsize(points), i;
  pointT *point, **pointp;
  setT *printpoints;

  qh_fprintf(fp, 9098, "{ OFF %d 1 1 # f%d\n", n, facet->id);
  if (offset != 0.0) {
    printpoints= qh_settemp(n);
    FOREACHpoint_(points)
      qh_setappend(&printpoints, qh_projectpoint(point, facet, -offset));
  }else
    printpoints= points;
  FOREACHpoint_(printpoints) {
    for (k=0; k < qh hull_dim; k++) {
      if (k == qh DROPdim)
        qh_fprintf(fp, 9099, "0 ");
      else
        qh_fprintf(fp, 9100, "%8.4g ", point[k]);
    }
    if (printpoints != points)
      qh_memfree(point, qh normal_size);
    qh_fprintf(fp, 9101, "\n");
  }
  if (printpoints != points)
    qh_settempfree(&printpoints);
  qh_fprintf(fp, 9102, "%d ", n);
  for (i=0; i < n; i++)
    qh_fprintf(fp, 9103, "%d ", i);
  qh_fprintf(fp, 9104, "%8.4g %8.4g %8.4g 1.0 }\n", color[0], color[1], color[2]);
} /* printfacet3geom_points */


/*---------------------------------

  qh_printfacet3geom_simplicial( )
    print Geomview OFF for a 3-d simplicial facet.

  notes:
    may flip color
    uses facet->visitid for intersections and ridges

    assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
    innerplane may be off by qh DISTround.  Maxoutside is calculated elsewhere
    so a DISTround error may have occurred.
*/
void qh_printfacet3geom_simplicial(FILE *fp, facetT *facet, realT color[3]) {
  setT *points, *vertices;
  vertexT *vertex, **vertexp, *vertexA, *vertexB;
  facetT *neighbor, **neighborp;
  realT outerplane, innerplane;
  realT black[3]={0, 0, 0}, green[3]={0, 1, 0};
  int k;

  qh_geomplanes(facet, &outerplane, &innerplane);
  vertices= qh_facet3vertex(facet);
  points= qh_settemp(qh TEMPsize);
  FOREACHvertex_(vertices)
    qh_setappend(&points, vertex->point);
  if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner))
    qh_printfacet3geom_points(fp, points, facet, outerplane, color);
  if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter &&
              outerplane - innerplane > 2 * qh MAXabs_coord * qh_GEOMepsilon)) {
    for (k=3; k--; )
      color[k]= 1.0 - color[k];
    qh_printfacet3geom_points(fp, points, facet, innerplane, color);
  }
  qh_settempfree(&points);
  qh_settempfree(&vertices);
  if ((qh DOintersections || qh PRINTridges)
  && (!facet->visible || !qh NEWfacets)) {
    facet->visitid= qh visit_id;
    FOREACHneighbor_(facet) {
      if (neighbor->visitid != qh visit_id) {
        vertices= qh_setnew_delnthsorted(facet->vertices, qh hull_dim,
                          SETindex_(facet->neighbors, neighbor), 0);
        if (qh DOintersections)
           qh_printhyperplaneintersection(fp, facet, neighbor, vertices, black);
        if (qh PRINTridges) {
          vertexA= SETfirstt_(vertices, vertexT);
          vertexB= SETsecondt_(vertices, vertexT);
          qh_printline3geom(fp, vertexA->point, vertexB->point, green);
        }
        qh_setfree(&vertices);
      }
    }
  }
} /* printfacet3geom_simplicial */

/*---------------------------------

  qh_printfacet3math( fp, facet, notfirst )
    print 3-d Maple or Mathematica output for a facet

  notes:
    may be non-simplicial
    use %16.8f since Mathematica 2.2 does not handle exponential format
    see qh_printfacet2math
*/
void qh_printfacet3math(FILE *fp, facetT *facet, qh_PRINT format, int notfirst) {
  vertexT *vertex, **vertexp;
  setT *points, *vertices;
  pointT *point, **pointp;
  boolT firstpoint= True;
  realT dist;
  const char *pointfmt, *endfmt;

  if (notfirst)
    qh_fprintf(fp, 9105, ",\n");
  vertices= qh_facet3vertex(facet);
  points= qh_settemp(qh_setsize(vertices));
  FOREACHvertex_(vertices) {
    zinc_(Zdistio);
    qh_distplane(vertex->point, facet, &dist);
    point= qh_projectpoint(vertex->point, facet, dist);
    qh_setappend(&points, point);
  }
  if (format == qh_PRINTmaple) {
    qh_fprintf(fp, 9106, "[");
    pointfmt= "[%16.8f, %16.8f, %16.8f]";
    endfmt= "]";
  }else {
    qh_fprintf(fp, 9107, "Polygon[{");
    pointfmt= "{%16.8f, %16.8f, %16.8f}";
    endfmt= "}]";
  }
  FOREACHpoint_(points) {
    if (firstpoint)
      firstpoint= False;
    else
      qh_fprintf(fp, 9108, ",\n");
    qh_fprintf(fp, 9109, pointfmt, point[0], point[1], point[2]);
  }
  FOREACHpoint_(points)
    qh_memfree(point, qh normal_size);
  qh_settempfree(&points);
  qh_settempfree(&vertices);
  qh_fprintf(fp, 9110, "%s", endfmt);
} /* printfacet3math */


/*---------------------------------

  qh_printfacet3vertex( fp, facet, format )
    print vertices in a 3-d facet as point ids

  notes:
    prints number of vertices first if format == qh_PRINToff
    the facet may be non-simplicial
*/
void qh_printfacet3vertex(FILE *fp, facetT *facet, qh_PRINT format) {
  vertexT *vertex, **vertexp;
  setT *vertices;

  vertices= qh_facet3vertex(facet);
  if (format == qh_PRINToff)
    qh_fprintf(fp, 9111, "%d ", qh_setsize(vertices));
  FOREACHvertex_(vertices)
    qh_fprintf(fp, 9112, "%d ", qh_pointid(vertex->point));
  qh_fprintf(fp, 9113, "\n");
  qh_settempfree(&vertices);
} /* printfacet3vertex */


/*---------------------------------

  qh_printfacet4geom_nonsimplicial( )
    print Geomview 4OFF file for a 4d nonsimplicial facet
    prints all ridges to unvisited neighbors (qh.visit_id)
    if qh.DROPdim
      prints in OFF format

  notes:
    must agree with printend4geom()
*/
void qh_printfacet4geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]) {
  facetT *neighbor;
  ridgeT *ridge, **ridgep;
  vertexT *vertex, **vertexp;
  pointT *point;
  int k;
  realT dist;

  facet->visitid= qh visit_id;
  if (qh PRINTnoplanes || (facet->visible && qh NEWfacets))
    return;
  FOREACHridge_(facet->ridges) {
    neighbor= otherfacet_(ridge, facet);
    if (neighbor->visitid == qh visit_id)
      continue;
    if (qh PRINTtransparent && !neighbor->good)
      continue;
    if (qh DOintersections)
      qh_printhyperplaneintersection(fp, facet, neighbor, ridge->vertices, color);
    else {
      if (qh DROPdim >= 0)
        qh_fprintf(fp, 9114, "OFF 3 1 1 # f%d\n", facet->id);
      else {
        qh printoutvar++;
        qh_fprintf(fp, 9115, "# r%d between f%d f%d\n", ridge->id, facet->id, neighbor->id);
      }
      FOREACHvertex_(ridge->vertices) {
        zinc_(Zdistio);
        qh_distplane(vertex->point,facet, &dist);
        point=qh_projectpoint(vertex->point,facet, dist);
        for (k=0; k < qh hull_dim; k++) {
          if (k != qh DROPdim)
            qh_fprintf(fp, 9116, "%8.4g ", point[k]);
        }
        qh_fprintf(fp, 9117, "\n");
        qh_memfree(point, qh normal_size);
      }
      if (qh DROPdim >= 0)
        qh_fprintf(fp, 9118, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);
    }
  }
} /* printfacet4geom_nonsimplicial */


/*---------------------------------

  qh_printfacet4geom_simplicial( fp, facet, color )
    print Geomview 4OFF file for a 4d simplicial facet
    prints triangles for unvisited neighbors (qh.visit_id)

  notes:
    must agree with printend4geom()
*/
void qh_printfacet4geom_simplicial(FILE *fp, facetT *facet, realT color[3]) {
  setT *vertices;
  facetT *neighbor, **neighborp;
  vertexT *vertex, **vertexp;
  int k;

  facet->visitid= qh visit_id;
  if (qh PRINTnoplanes || (facet->visible && qh NEWfacets))
    return;
  FOREACHneighbor_(facet) {
    if (neighbor->visitid == qh visit_id)
      continue;
    if (qh PRINTtransparent && !neighbor->good)
      continue;
    vertices= qh_setnew_delnthsorted(facet->vertices, qh hull_dim,
                          SETindex_(facet->neighbors, neighbor), 0);
    if (qh DOintersections)
      qh_printhyperplaneintersection(fp, facet, neighbor, vertices, color);
    else {
      if (qh DROPdim >= 0)
        qh_fprintf(fp, 9119, "OFF 3 1 1 # ridge between f%d f%d\n",
                facet->id, neighbor->id);
      else {
        qh printoutvar++;
        qh_fprintf(fp, 9120, "# ridge between f%d f%d\n", facet->id, neighbor->id);
      }
      FOREACHvertex_(vertices) {
        for (k=0; k < qh hull_dim; k++) {
          if (k != qh DROPdim)
            qh_fprintf(fp, 9121, "%8.4g ", vertex->point[k]);
        }
        qh_fprintf(fp, 9122, "\n");
      }
      if (qh DROPdim >= 0)
        qh_fprintf(fp, 9123, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);
    }
    qh_setfree(&vertices);
  }
} /* printfacet4geom_simplicial */


/*---------------------------------

  qh_printfacetNvertex_nonsimplicial( fp, facet, id, format )
    print vertices for an N-d non-simplicial facet
    triangulates each ridge to the id
*/
void qh_printfacetNvertex_nonsimplicial(FILE *fp, facetT *facet, int id, qh_PRINT format) {
  vertexT *vertex, **vertexp;
  ridgeT *ridge, **ridgep;

  if (facet->visible && qh NEWfacets)
    return;
  FOREACHridge_(facet->ridges) {
    if (format == qh_PRINTtriangles)
      qh_fprintf(fp, 9124, "%d ", qh hull_dim);
    qh_fprintf(fp, 9125, "%d ", id);
    if ((ridge->top == facet) ^ qh_ORIENTclock) {
      FOREACHvertex_(ridge->vertices)
        qh_fprintf(fp, 9126, "%d ", qh_pointid(vertex->point));
    }else {
      FOREACHvertexreverse12_(ridge->vertices)
        qh_fprintf(fp, 9127, "%d ", qh_pointid(vertex->point));
    }
    qh_fprintf(fp, 9128, "\n");
  }
} /* printfacetNvertex_nonsimplicial */


/*---------------------------------

  qh_printfacetNvertex_simplicial( fp, facet, format )
    print vertices for an N-d simplicial facet
    prints vertices for non-simplicial facets
      2-d facets (orientation preserved by qh_mergefacet2d)
      PRINToff ('o') for 4-d and higher
*/
void qh_printfacetNvertex_simplicial(FILE *fp, facetT *facet, qh_PRINT format) {
  vertexT *vertex, **vertexp;

  if (format == qh_PRINToff || format == qh_PRINTtriangles)
    qh_fprintf(fp, 9129, "%d ", qh_setsize(facet->vertices));
  if ((facet->toporient ^ qh_ORIENTclock)
  || (qh hull_dim > 2 && !facet->simplicial)) {
    FOREACHvertex_(facet->vertices)
      qh_fprintf(fp, 9130, "%d ", qh_pointid(vertex->point));
  }else {
    FOREACHvertexreverse12_(facet->vertices)
      qh_fprintf(fp, 9131, "%d ", qh_pointid(vertex->point));
  }
  qh_fprintf(fp, 9132, "\n");
} /* printfacetNvertex_simplicial */


/*---------------------------------

  qh_printfacetheader( fp, facet )
    prints header fields of a facet to fp

  notes:
    for 'f' output and debugging
    Same as QhullFacet::printHeader()
*/
void qh_printfacetheader(FILE *fp, facetT *facet) {
  pointT *point, **pointp, *furthest;
  facetT *neighbor, **neighborp;
  realT dist;

  if (facet == qh_MERGEridge) {
    qh_fprintf(fp, 9133, " MERGEridge\n");
    return;
  }else if (facet == qh_DUPLICATEridge) {
    qh_fprintf(fp, 9134, " DUPLICATEridge\n");
    return;
  }else if (!facet) {
    qh_fprintf(fp, 9135, " NULLfacet\n");
    return;
  }
  qh old_randomdist= qh RANDOMdist;
  qh RANDOMdist= False;
  qh_fprintf(fp, 9136, "- f%d\n", facet->id);
  qh_fprintf(fp, 9137, "    - flags:");
  if (facet->toporient)
    qh_fprintf(fp, 9138, " top");
  else
    qh_fprintf(fp, 9139, " bottom");
  if (facet->simplicial)
    qh_fprintf(fp, 9140, " simplicial");
  if (facet->tricoplanar)
    qh_fprintf(fp, 9141, " tricoplanar");
  if (facet->upperdelaunay)
    qh_fprintf(fp, 9142, " upperDelaunay");
  if (facet->visible)
    qh_fprintf(fp, 9143, " visible");
  if (facet->newfacet)
    qh_fprintf(fp, 9144, " newfacet");
  if (facet->tested)
    qh_fprintf(fp, 9145, " tested");
  if (!facet->good)
    qh_fprintf(fp, 9146, " notG");
  if (facet->seen && qh IStracing)
    qh_fprintf(fp, 9147, " seen");
  if (facet->seen2 && qh IStracing)
    qh_fprintf(fp, 9418, " seen2");
  if (facet->isarea)
    qh_fprintf(fp, 9419, " isarea");
  if (facet->coplanarhorizon)
    qh_fprintf(fp, 9148, " coplanarhorizon");
  if (facet->mergehorizon)
    qh_fprintf(fp, 9149, " mergehorizon");
  if (facet->cycledone)
    qh_fprintf(fp, 9420, " cycledone");
  if (facet->keepcentrum)
    qh_fprintf(fp, 9150, " keepcentrum");
  if (facet->dupridge)
    qh_fprintf(fp, 9151, " dupridge");
  if (facet->mergeridge && !facet->mergeridge2)
    qh_fprintf(fp, 9152, " mergeridge1");
  if (facet->mergeridge2)
    qh_fprintf(fp, 9153, " mergeridge2");
  if (facet->newmerge)
    qh_fprintf(fp, 9154, " newmerge");
  if (facet->flipped)
    qh_fprintf(fp, 9155, " flipped");
  if (facet->notfurthest)
    qh_fprintf(fp, 9156, " notfurthest");
  if (facet->degenerate)
    qh_fprintf(fp, 9157, " degenerate");
  if (facet->redundant)
    qh_fprintf(fp, 9158, " redundant");
  qh_fprintf(fp, 9159, "\n");
  if (facet->isarea)
    qh_fprintf(fp, 9160, "    - area: %2.2g\n", facet->f.area);
  else if (qh NEWfacets && facet->visible && facet->f.replace)
    qh_fprintf(fp, 9161, "    - replacement: f%d\n", facet->f.replace->id);
  else if (facet->newfacet) {
    if (facet->f.samecycle && facet->f.samecycle != facet)
      qh_fprintf(fp, 9162, "    - shares same visible/horizon as f%d\n", facet->f.samecycle->id);
  }else if (facet->tricoplanar /* !isarea */) {
    if (facet->f.triowner)
      qh_fprintf(fp, 9163, "    - owner of normal & centrum is facet f%d\n", facet->f.triowner->id);
  }else if (facet->f.newcycle)
    qh_fprintf(fp, 9164, "    - was horizon to f%d\n", facet->f.newcycle->id);
  if (facet->nummerge == qh_MAXnummerge)
    qh_fprintf(fp, 9427, "    - merges: %dmax\n", qh_MAXnummerge);
  else if (facet->nummerge)
    qh_fprintf(fp, 9165, "    - merges: %d\n", facet->nummerge);
  qh_printpointid(fp, "    - normal: ", qh hull_dim, facet->normal, qh_IDunknown);
  qh_fprintf(fp, 9166, "    - offset: %10.7g\n", facet->offset);
  if (qh CENTERtype == qh_ASvoronoi || facet->center)
    qh_printcenter(fp, qh_PRINTfacets, "    - center: ", facet);
#if qh_MAXoutside
  if (facet->maxoutside > qh DISTround) /* initial value */
    qh_fprintf(fp, 9167, "    - maxoutside: %10.7g\n", facet->maxoutside);
#endif
  if (!SETempty_(facet->outsideset)) {
    furthest= (pointT *)qh_setlast(facet->outsideset);
    if (qh_setsize(facet->outsideset) < 6) {
      qh_fprintf(fp, 9168, "    - outside set(furthest p%d):\n", qh_pointid(furthest));
      FOREACHpoint_(facet->outsideset)
        qh_printpoint(fp, "     ", point);
    }else if (qh_setsize(facet->outsideset) < 21) {
      qh_printpoints(fp, "    - outside set:", facet->outsideset);
    }else {
      qh_fprintf(fp, 9169, "    - outside set:  %d points.", qh_setsize(facet->outsideset));
      qh_printpoint(fp, "  Furthest", furthest);
    }
#if !qh_COMPUTEfurthest
    qh_fprintf(fp, 9170, "    - furthest distance= %2.2g\n", facet->furthestdist);
#endif
  }
  if (!SETempty_(facet->coplanarset)) {
    furthest= (pointT *)qh_setlast(facet->coplanarset);
    if (qh_setsize(facet->coplanarset) < 6) {
      qh_fprintf(fp, 9171, "    - coplanar set(furthest p%d):\n", qh_pointid(furthest));
      FOREACHpoint_(facet->coplanarset)
        qh_printpoint(fp, "     ", point);
    }else if (qh_setsize(facet->coplanarset) < 21) {
      qh_printpoints(fp, "    - coplanar set:", facet->coplanarset);
    }else {
      qh_fprintf(fp, 9172, "    - coplanar set:  %d points.", qh_setsize(facet->coplanarset));
      qh_printpoint(fp, "  Furthest", furthest);
    }
    zinc_(Zdistio);
    qh_distplane(furthest, facet, &dist);
    qh_fprintf(fp, 9173, "      furthest distance= %2.2g\n", dist);
  }
  qh_printvertices(fp, "    - vertices:", facet->vertices);
  qh_fprintf(fp, 9174, "    - neighboring facets:");
  FOREACHneighbor_(facet) {
    if (neighbor == qh_MERGEridge)
      qh_fprintf(fp, 9175, " MERGEridge");
    else if (neighbor == qh_DUPLICATEridge)
      qh_fprintf(fp, 9176, " DUPLICATEridge");
    else
      qh_fprintf(fp, 9177, " f%d", neighbor->id);
  }
  qh_fprintf(fp, 9178, "\n");
  qh RANDOMdist= qh old_randomdist;
} /* printfacetheader */


/*---------------------------------

  qh_printfacetridges( fp, facet )
    prints ridges of a facet to fp

  notes:
    ridges printed in neighbor order
    assumes the ridges exist
    for 'f' output
    same as QhullFacet::printRidges
*/
void qh_printfacetridges(FILE *fp, facetT *facet) {
  facetT *neighbor, **neighborp;
  ridgeT *ridge, **ridgep;
  int numridges= 0;
  int n;

  if (facet->visible && qh NEWfacets) {
    qh_fprintf(fp, 9179, "    - ridges (tentative ids):");
    FOREACHridge_(facet->ridges)
      qh_fprintf(fp, 9180, " r%d", ridge->id);
    qh_fprintf(fp, 9181, "\n");
  }else {
    qh_fprintf(fp, 9182, "    - ridges:\n");
    FOREACHridge_(facet->ridges)
      ridge->seen= False;
    if (qh hull_dim == 3) {
      ridge= SETfirstt_(facet->ridges, ridgeT);
      while (ridge && !ridge->seen) {
        ridge->seen= True;
        qh_printridge(fp, ridge);
        numridges++;
        ridge= qh_nextridge3d(ridge, facet, NULL);
        }
    }else {
      FOREACHneighbor_(facet) {
        FOREACHridge_(facet->ridges) {
          if (otherfacet_(ridge, facet) == neighbor && !ridge->seen) {
            ridge->seen= True;
            qh_printridge(fp, ridge);
            numridges++;
          }
        }
      }
    }
    n= qh_setsize(facet->ridges);
    if (n == 1 && facet->newfacet && qh NEWtentative) {
      qh_fprintf(fp, 9411, "     - horizon ridge to visible facet\n");
    }
    if (numridges != n) {
      qh_fprintf(fp, 9183, "     - all ridges:");
      FOREACHridge_(facet->ridges)
        qh_fprintf(fp, 9184, " r%d", ridge->id);
      qh_fprintf(fp, 9185, "\n");
    }
    /* non-3d ridges w/o non-simplicial neighbors */
    FOREACHridge_(facet->ridges) {
      if (!ridge->seen)
        qh_printridge(fp, ridge);
    }
  }
} /* printfacetridges */

/*---------------------------------

  qh_printfacets( fp, format, facetlist, facets, printall )
    prints facetlist and/or facet set in output format

  notes:
    also used for specialized formats ('FO' and summary)
    turns off 'Rn' option since want actual numbers
*/
void qh_printfacets(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {
  int numfacets, numsimplicial, numridges, totneighbors, numcoplanars, numtricoplanars;
  facetT *facet, **facetp;
  setT *vertices;
  coordT *center;
  realT outerplane, innerplane;

  qh old_randomdist= qh RANDOMdist;
  qh RANDOMdist= False;
  if (qh CDDoutput && (format == qh_PRINTcentrums || format == qh_PRINTpointintersect || format == qh_PRINToff))
    qh_fprintf(qh ferr, 7056, "qhull warning: CDD format is not available for centrums, halfspace\nintersections, and OFF file format.\n");
  if (format == qh_PRINTnone)
    ; /* print nothing */
  else if (format == qh_PRINTaverage) {
    vertices= qh_facetvertices(facetlist, facets, printall);
    center= qh_getcenter(vertices);
    qh_fprintf(fp, 9186, "%d 1\n", qh hull_dim);
    qh_printpointid(fp, NULL, qh hull_dim, center, qh_IDunknown);
    qh_memfree(center, qh normal_size);
    qh_settempfree(&vertices);
  }else if (format == qh_PRINTextremes) {
    if (qh DELAUNAY)
      qh_printextremes_d(fp, facetlist, facets, printall);
    else if (qh hull_dim == 2)
      qh_printextremes_2d(fp, facetlist, facets, printall);
    else
      qh_printextremes(fp, facetlist, facets, printall);
  }else if (format == qh_PRINToptions)
    qh_fprintf(fp, 9187, "Options selected for Qhull %s:\n%s\n", qh_version, qh qhull_options);
  else if (format == qh_PRINTpoints && !qh VORONOI)
    qh_printpoints_out(fp, facetlist, facets, printall);
  else if (format == qh_PRINTqhull)
    qh_fprintf(fp, 9188, "%s | %s\n", qh rbox_command, qh qhull_command);
  else if (format == qh_PRINTsize) {
    qh_fprintf(fp, 9189, "0\n2 ");
    qh_fprintf(fp, 9190, qh_REAL_1, qh totarea);
    qh_fprintf(fp, 9191, qh_REAL_1, qh totvol);
    qh_fprintf(fp, 9192, "\n");
  }else if (format == qh_PRINTsummary) {
    qh_countfacets(facetlist, facets, printall, &numfacets, &numsimplicial,
      &totneighbors, &numridges, &numcoplanars, &numtricoplanars);
    vertices= qh_facetvertices(facetlist, facets, printall);
    qh_fprintf(fp, 9193, "10 %d %d %d %d %d %d %d %d %d %d\n2 ", qh hull_dim,
                qh num_points + qh_setsize(qh other_points),
                qh num_vertices, qh num_facets - qh num_visible,
                qh_setsize(vertices), numfacets, numcoplanars,
                numfacets - numsimplicial, zzval_(Zdelvertextot),
                numtricoplanars);
    qh_settempfree(&vertices);
    qh_outerinner(NULL, &outerplane, &innerplane);
    qh_fprintf(fp, 9194, qh_REAL_2n, outerplane, innerplane);
  }else if (format == qh_PRINTvneighbors)
    qh_printvneighbors(fp, facetlist, facets, printall);
  else if (qh VORONOI && format == qh_PRINToff)
    qh_printvoronoi(fp, format, facetlist, facets, printall);
  else if (qh VORONOI && format == qh_PRINTgeom) {
    qh_printbegin(fp, format, facetlist, facets, printall);
    qh_printvoronoi(fp, format, facetlist, facets, printall);
    qh_printend(fp, format, facetlist, facets, printall);
  }else if (qh VORONOI
  && (format == qh_PRINTvertices || format == qh_PRINTinner || format == qh_PRINTouter))
    qh_printvdiagram(fp, format, facetlist, facets, printall);
  else {
    qh_printbegin(fp, format, facetlist, facets, printall);
    FORALLfacet_(facetlist)
      qh_printafacet(fp, format, facet, printall);
    FOREACHfacet_(facets)
      qh_printafacet(fp, format, facet, printall);
    qh_printend(fp, format, facetlist, facets, printall);
  }
  qh RANDOMdist= qh old_randomdist;
} /* printfacets */


/*---------------------------------

  qh_printhyperplaneintersection( fp, facet1, facet2, vertices, color )
    print Geomview OFF or 4OFF for the intersection of two hyperplanes in 3-d or 4-d
*/
void qh_printhyperplaneintersection(FILE *fp, facetT *facet1, facetT *facet2,
                   setT *vertices, realT color[3]) {
  realT costheta, denominator, dist1, dist2, s, t, mindenom, p[4];
  vertexT *vertex, **vertexp;
  int i, k;
  boolT nearzero1, nearzero2;

  costheta= qh_getangle(facet1->normal, facet2->normal);
  denominator= 1 - costheta * costheta;
  i= qh_setsize(vertices);
  if (qh hull_dim == 3)
    qh_fprintf(fp, 9195, "VECT 1 %d 1 %d 1 ", i, i);
  else if (qh hull_dim == 4 && qh DROPdim >= 0)
    qh_fprintf(fp, 9196, "OFF 3 1 1 ");
  else
    qh printoutvar++;
  qh_fprintf(fp, 9197, "# intersect f%d f%d\n", facet1->id, facet2->id);
  mindenom= 1 / (10.0 * qh MAXabs_coord);
  FOREACHvertex_(vertices) {
    zadd_(Zdistio, 2);
    qh_distplane(vertex->point, facet1, &dist1);
    qh_distplane(vertex->point, facet2, &dist2);
    s= qh_divzero(-dist1 + costheta * dist2, denominator,mindenom,&nearzero1);
    t= qh_divzero(-dist2 + costheta * dist1, denominator,mindenom,&nearzero2);
    if (nearzero1 || nearzero2)
      s= t= 0.0;
    for (k=qh hull_dim; k--; )
      p[k]= vertex->point[k] + facet1->normal[k] * s + facet2->normal[k] * t;
    if (qh PRINTdim <= 3) {
      qh_projectdim3(p, p);
      qh_fprintf(fp, 9198, "%8.4g %8.4g %8.4g # ", p[0], p[1], p[2]);
    }else
      qh_fprintf(fp, 9199, "%8.4g %8.4g %8.4g %8.4g # ", p[0], p[1], p[2], p[3]);
    if (nearzero1+nearzero2)
      qh_fprintf(fp, 9200, "p%d(coplanar facets)\n", qh_pointid(vertex->point));
    else
      qh_fprintf(fp, 9201, "projected p%d\n", qh_pointid(vertex->point));
  }
  if (qh hull_dim == 3)
    qh_fprintf(fp, 9202, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
  else if (qh hull_dim == 4 && qh DROPdim >= 0)
    qh_fprintf(fp, 9203, "3 0 1 2 %8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
} /* printhyperplaneintersection */

/*---------------------------------

  qh_printline3geom( fp, pointA, pointB, color )
    prints a line as a VECT
    prints 0's for qh.DROPdim

  notes:
    if pointA == pointB,
      it's a 1 point VECT
*/
void qh_printline3geom(FILE *fp, pointT *pointA, pointT *pointB, realT color[3]) {
  int k;
  realT pA[4], pB[4];

  qh_projectdim3(pointA, pA);
  qh_projectdim3(pointB, pB);
  if ((fabs(pA[0] - pB[0]) > 1e-3) ||
      (fabs(pA[1] - pB[1]) > 1e-3) ||
      (fabs(pA[2] - pB[2]) > 1e-3)) {
    qh_fprintf(fp, 9204, "VECT 1 2 1 2 1\n");
    for (k=0; k < 3; k++)
       qh_fprintf(fp, 9205, "%8.4g ", pB[k]);
    qh_fprintf(fp, 9206, " # p%d\n", qh_pointid(pointB));
  }else
    qh_fprintf(fp, 9207, "VECT 1 1 1 1 1\n");
  for (k=0; k < 3; k++)
    qh_fprintf(fp, 9208, "%8.4g ", pA[k]);
  qh_fprintf(fp, 9209, " # p%d\n", qh_pointid(pointA));
  qh_fprintf(fp, 9210, "%8.4g %8.4g %8.4g 1\n", color[0], color[1], color[2]);
}

/*---------------------------------

  qh_printneighborhood( fp, format, facetA, facetB, printall )
    print neighborhood of one or two facets

  notes:
    calls qh_findgood_all()
    bumps qh.visit_id
*/
void qh_printneighborhood(FILE *fp, qh_PRINT format, facetT *facetA, facetT *facetB, boolT printall) {
  facetT *neighbor, **neighborp, *facet;
  setT *facets;

  if (format == qh_PRINTnone)
    return;
  qh_findgood_all(qh facet_list);
  if (facetA == facetB)
    facetB= NULL;
  facets= qh_settemp(2*(qh_setsize(facetA->neighbors)+1));
  qh visit_id++;
  for (facet=facetA; facet; facet= ((facet == facetA) ? facetB : NULL)) {
    if (facet->visitid != qh visit_id) {
      facet->visitid= qh visit_id;
      qh_setappend(&facets, facet);
    }
    FOREACHneighbor_(facet) {
      if (neighbor->visitid == qh visit_id)
        continue;
      neighbor->visitid= qh visit_id;
      if (printall || !qh_skipfacet(neighbor))
        qh_setappend(&facets, neighbor);
    }
  }
  qh_printfacets(fp, format, NULL, facets, printall);
  qh_settempfree(&facets);
} /* printneighborhood */

/*---------------------------------

  qh_printpoint( fp, string, point )
  qh_printpointid( fp, string, dim, point, id )
    prints the coordinates of a point

  returns:
    if string is defined
      prints 'string p%d'.  Skips p%d if id=qh_IDunknown(-1) or qh_IDnone(-3)

  notes:
    nop if point is NULL
    Same as QhullPoint's printPoint
*/
void qh_printpoint(FILE *fp, const char *string, pointT *point) {
  int id= qh_pointid(point);

  qh_printpointid(fp, string, qh hull_dim, point, id);
} /* printpoint */

void qh_printpointid(FILE *fp, const char *string, int dim, pointT *point, int id) {
  int k;
  realT r; /*bug fix*/

  if (!point)
    return;
  if (string) {
    qh_fprintf(fp, 9211, "%s", string);
    if (id != qh_IDunknown && id != qh_IDnone)
      qh_fprintf(fp, 9212, " p%d: ", id);
  }
  for (k=dim; k--; ) {
    r= *point++;
    if (string)
      qh_fprintf(fp, 9213, " %8.4g", r);
    else
      qh_fprintf(fp, 9214, qh_REAL_1, r);
  }
  qh_fprintf(fp, 9215, "\n");
} /* printpointid */

/*---------------------------------

  qh_printpoint3( fp, point )
    prints 2-d, 3-d, or 4-d point as Geomview 3-d coordinates
*/
void qh_printpoint3(FILE *fp, pointT *point) {
  int k;
  realT p[4];

  qh_projectdim3(point, p);
  for (k=0; k < 3; k++)
    qh_fprintf(fp, 9216, "%8.4g ", p[k]);
  qh_fprintf(fp, 9217, " # p%d\n", qh_pointid(point));
} /* printpoint3 */

/*----------------------------------------
-printpoints- print pointids for a set of points starting at index
   see geom.c
*/

/*---------------------------------

  qh_printpoints_out( fp, facetlist, facets, printall )
    prints vertices, coplanar/inside points, for facets by their point coordinates
    allows qh.CDDoutput

  notes:
    same format as qhull input
    if no coplanar/interior points,
      same order as qh_printextremes
*/
void qh_printpoints_out(FILE *fp, facetT *facetlist, setT *facets, boolT printall) {
  int allpoints= qh num_points + qh_setsize(qh other_points);
  int numpoints=0, point_i, point_n;
  setT *vertices, *points;
  facetT *facet, **facetp;
  pointT *point, **pointp;
  vertexT *vertex, **vertexp;
  int id;

  points= qh_settemp(allpoints);
  qh_setzero(points, 0, allpoints);
  vertices= qh_facetvertices(facetlist, facets, printall);
  FOREACHvertex_(vertices) {
    id= qh_pointid(vertex->point);
    if (id >= 0)
      SETelem_(points, id)= vertex->point;
  }
  if (qh KEEPinside || qh KEEPcoplanar || qh KEEPnearinside) {
    FORALLfacet_(facetlist) {
      if (!printall && qh_skipfacet(facet))
        continue;
      FOREACHpoint_(facet->coplanarset) {
        id= qh_pointid(point);
        if (id >= 0)
          SETelem_(points, id)= point;
      }
    }
    FOREACHfacet_(facets) {
      if (!printall && qh_skipfacet(facet))
        continue;
      FOREACHpoint_(facet->coplanarset) {
        id= qh_pointid(point);
        if (id >= 0)
          SETelem_(points, id)= point;
      }
    }
  }
  qh_settempfree(&vertices);
  FOREACHpoint_i_(points) {
    if (point)
      numpoints++;
  }
  if (qh CDDoutput)
    qh_fprintf(fp, 9218, "%s | %s\nbegin\n%d %d real\n", qh rbox_command,
             qh qhull_command, numpoints, qh hull_dim + 1);
  else
    qh_fprintf(fp, 9219, "%d\n%d\n", qh hull_dim, numpoints);
  FOREACHpoint_i_(points) {
    if (point) {
      if (qh CDDoutput)
        qh_fprintf(fp, 9220, "1 ");
      qh_printpoint(fp, NULL, point);
    }
  }
  if (qh CDDoutput)
    qh_fprintf(fp, 9221, "end\n");
  qh_settempfree(&points);
} /* printpoints_out */


/*---------------------------------

  qh_printpointvect( fp, point, normal, center, radius, color )
    prints a 2-d, 3-d, or 4-d point as 3-d VECT's relative to normal or to center point
*/
void qh_printpointvect(FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius, realT color[3]) {
  realT diff[4], pointA[4];
  int k;

  for (k=qh hull_dim; k--; ) {
    if (center)
      diff[k]= point[k]-center[k];
    else if (normal)
      diff[k]= normal[k];
    else
      diff[k]= 0;
  }
  if (center)
    qh_normalize2(diff, qh hull_dim, True, NULL, NULL);
  for (k=qh hull_dim; k--; )
    pointA[k]= point[k]+diff[k] * radius;
  qh_printline3geom(fp, point, pointA, color);
} /* printpointvect */

/*---------------------------------

  qh_printpointvect2( fp, point, normal, center, radius )
    prints a 2-d, 3-d, or 4-d point as 2 3-d VECT's for an imprecise point
*/
void qh_printpointvect2(FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius) {
  realT red[3]={1, 0, 0}, yellow[3]={1, 1, 0};

  qh_printpointvect(fp, point, normal, center, radius, red);
  qh_printpointvect(fp, point, normal, center, -radius, yellow);
} /* printpointvect2 */

/*---------------------------------

  qh_printridge( fp, ridge )
    prints the information in a ridge

  notes:
    for qh_printfacetridges()
    same as operator<< [QhullRidge.cpp]
*/
void qh_printridge(FILE *fp, ridgeT *ridge) {

  qh_fprintf(fp, 9222, "     - r%d", ridge->id);
  if (ridge->tested)
    qh_fprintf(fp, 9223, " tested");
  if (ridge->nonconvex)
    qh_fprintf(fp, 9224, " nonconvex");
  if (ridge->mergevertex)
    qh_fprintf(fp, 9421, " mergevertex");
  if (ridge->mergevertex2)
    qh_fprintf(fp, 9422, " mergevertex2");
  if (ridge->simplicialtop)
    qh_fprintf(fp, 9425, " simplicialtop");
  if (ridge->simplicialbot)
    qh_fprintf(fp, 9423, " simplicialbot");
  qh_fprintf(fp, 9225, "\n");
  qh_printvertices(fp, "           vertices:", ridge->vertices);
  if (ridge->top && ridge->bottom)
    qh_fprintf(fp, 9226, "           between f%d and f%d\n",
            ridge->top->id, ridge->bottom->id);
} /* printridge */

/*---------------------------------

  qh_printspheres( fp, vertices, radius )
    prints 3-d vertices as OFF spheres

  notes:
    inflated octahedron from Stuart Levy earth/mksphere2
*/
void qh_printspheres(FILE *fp, setT *vertices, realT radius) {
  vertexT *vertex, **vertexp;

  qh printoutnum++;
  qh_fprintf(fp, 9227, "{appearance {-edge -normal normscale 0} {\n\
INST geom {define vsphere OFF\n\
18 32 48\n\
\n\
0 0 1\n\
1 0 0\n\
0 1 0\n\
-1 0 0\n\
0 -1 0\n\
0 0 -1\n\
0.707107 0 0.707107\n\
0 -0.707107 0.707107\n\
0.707107 -0.707107 0\n\
-0.707107 0 0.707107\n\
-0.707107 -0.707107 0\n\
0 0.707107 0.707107\n\
-0.707107 0.707107 0\n\
0.707107 0.707107 0\n\
0.707107 0 -0.707107\n\
0 0.707107 -0.707107\n\
-0.707107 0 -0.707107\n\
0 -0.707107 -0.707107\n\
\n\
3 0 6 11\n\
3 0 7 6 \n\
3 0 9 7 \n\
3 0 11 9\n\
3 1 6 8 \n\
3 1 8 14\n\
3 1 13 6\n\
3 1 14 13\n\
3 2 11 13\n\
3 2 12 11\n\
3 2 13 15\n\
3 2 15 12\n\
3 3 9 12\n\
3 3 10 9\n\
3 3 12 16\n\
3 3 16 10\n\
3 4 7 10\n\
3 4 8 7\n\
3 4 10 17\n\
3 4 17 8\n\
3 5 14 17\n\
3 5 15 14\n\
3 5 16 15\n\
3 5 17 16\n\
3 6 13 11\n\
3 7 8 6\n\
3 9 10 7\n\
3 11 12 9\n\
3 14 8 17\n\
3 15 13 14\n\
3 16 12 15\n\
3 17 10 16\n} transforms { TLIST\n");
  FOREACHvertex_(vertices) {
    qh_fprintf(fp, 9228, "%8.4g 0 0 0 # v%d\n 0 %8.4g 0 0\n0 0 %8.4g 0\n",
      radius, vertex->id, radius, radius);
    qh_printpoint3(fp, vertex->point);
    qh_fprintf(fp, 9229, "1\n");
  }
  qh_fprintf(fp, 9230, "}}}\n");
} /* printspheres */


/*----------------------------------------------
-printsummary-
                see libqhull.c
*/

/*---------------------------------

  qh_printvdiagram( fp, format, facetlist, facets, printall )
    print voronoi diagram
      # of pairs of input sites
      #indices site1 site2 vertex1 ...

    sites indexed by input point id
      point 0 is the first input point
    vertices indexed by 'o' and 'p' order
      vertex 0 is the 'vertex-at-infinity'
      vertex 1 is the first Voronoi vertex

  see:
    qh_printvoronoi()
    qh_eachvoronoi_all()

  notes:
    if all facets are upperdelaunay,
      prints upper hull (furthest-site Voronoi diagram)
*/
void qh_printvdiagram(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {
  setT *vertices;
  int totcount, numcenters;
  boolT isLower;
  qh_RIDGE innerouter= qh_RIDGEall;
  printvridgeT printvridge= NULL;

  if (format == qh_PRINTvertices) {
    innerouter= qh_RIDGEall;
    printvridge= qh_printvridge;
  }else if (format == qh_PRINTinner) {
    innerouter= qh_RIDGEinner;
    printvridge= qh_printvnorm;
  }else if (format == qh_PRINTouter) {
    innerouter= qh_RIDGEouter;
    printvridge= qh_printvnorm;
  }else {
    qh_fprintf(qh ferr, 6219, "qhull internal error (qh_printvdiagram): unknown print format %d.\n", format);
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  vertices= qh_markvoronoi(facetlist, facets, printall, &isLower, &numcenters);
  totcount= qh_printvdiagram2(NULL, NULL, vertices, innerouter, False);
  qh_fprintf(fp, 9231, "%d\n", totcount);
  totcount= qh_printvdiagram2(fp, printvridge, vertices, innerouter, True /* inorder*/);
  qh_settempfree(&vertices);
#if 0  /* for testing qh_eachvoronoi_all */
  qh_fprintf(fp, 9232, "\n");
  totcount= qh_eachvoronoi_all(fp, printvridge, qh UPPERdelaunay, innerouter, True /* inorder*/);
  qh_fprintf(fp, 9233, "%d\n", totcount);
#endif
} /* printvdiagram */

/*---------------------------------

  qh_printvdiagram2( fp, printvridge, vertices, innerouter, inorder )
    visit all pairs of input sites (vertices) for selected Voronoi vertices
    vertices may include NULLs

  innerouter:
    qh_RIDGEall   print inner ridges(bounded) and outer ridges(unbounded)
    qh_RIDGEinner print only inner ridges
    qh_RIDGEouter print only outer ridges

  inorder:
    print 3-d Voronoi vertices in order

  assumes:
    qh_markvoronoi marked facet->visitid for Voronoi vertices
    all facet->seen= False
    all facet->seen2= True

  returns:
    total number of Voronoi ridges
    if printvridge,
      calls printvridge( fp, vertex, vertexA, centers) for each ridge
      [see qh_eachvoronoi()]

  see:
    qh_eachvoronoi_all()
*/
int qh_printvdiagram2(FILE *fp, printvridgeT printvridge, setT *vertices, qh_RIDGE innerouter, boolT inorder) {
  int totcount= 0;
  int vertex_i, vertex_n;
  vertexT *vertex;

  FORALLvertices
    vertex->seen= False;
  FOREACHvertex_i_(vertices) {
    if (vertex) {
      if (qh GOODvertex > 0 && qh_pointid(vertex->point)+1 != qh GOODvertex)
        continue;
      totcount += qh_eachvoronoi(fp, printvridge, vertex, !qh_ALL, innerouter, inorder);
    }
  }
  return totcount;
} /* printvdiagram2 */

/*---------------------------------

  qh_printvertex( fp, vertex )
    prints the information in a vertex
    Duplicated as operator<< [QhullVertex.cpp]
*/
void qh_printvertex(FILE *fp, vertexT *vertex) {
  pointT *point;
  int k, count= 0;
  facetT *neighbor, **neighborp;
  realT r; /*bug fix*/

  if (!vertex) {
    qh_fprintf(fp, 9234, "  NULLvertex\n");
    return;
  }
  qh_fprintf(fp, 9235, "- p%d(v%d):", qh_pointid(vertex->point), vertex->id);
  point= vertex->point;
  if (point) {
    for (k=qh hull_dim; k--; ) {
      r= *point++;
      qh_fprintf(fp, 9236, " %5.2g", r);
    }
  }
  if (vertex->deleted)
    qh_fprintf(fp, 9237, " deleted");
  if (vertex->delridge)
    qh_fprintf(fp, 9238, " delridge");
  if (vertex->newfacet)
    qh_fprintf(fp, 9415, " newfacet");
  if (vertex->seen && qh IStracing)
    qh_fprintf(fp, 9416, " seen");
  if (vertex->seen2 && qh IStracing)
    qh_fprintf(fp, 9417, " seen2");
  qh_fprintf(fp, 9239, "\n");
  if (vertex->neighbors) {
    qh_fprintf(fp, 9240, "  neighbors:");
    FOREACHneighbor_(vertex) {
      if (++count % 100 == 0)
        qh_fprintf(fp, 9241, "\n     ");
      qh_fprintf(fp, 9242, " f%d", neighbor->id);
    }
    qh_fprintf(fp, 9243, "\n");
  }
} /* printvertex */


/*---------------------------------

  qh_printvertexlist( fp, string, facetlist, facets, printall )
    prints vertices used by a facetlist or facet set
    tests qh_skipfacet() if !printall
*/
void qh_printvertexlist(FILE *fp, const char* string, facetT *facetlist,
                         setT *facets, boolT printall) {
  vertexT *vertex, **vertexp;
  setT *vertices;

  vertices= qh_facetvertices(facetlist, facets, printall);
  qh_fprintf(fp, 9244, "%s", string);
  FOREACHvertex_(vertices)
    qh_printvertex(fp, vertex);
  qh_settempfree(&vertices);
} /* printvertexlist */


/*---------------------------------

  qh_printvertices( fp, string, vertices )
    prints vertices in a set
    duplicated as printVertexSet [QhullVertex.cpp]
*/
void qh_printvertices(FILE *fp, const char* string, setT *vertices) {
  vertexT *vertex, **vertexp;

  qh_fprintf(fp, 9245, "%s", string);
  FOREACHvertex_(vertices)
    qh_fprintf(fp, 9246, " p%d(v%d)", qh_pointid(vertex->point), vertex->id);
  qh_fprintf(fp, 9247, "\n");
} /* printvertices */

/*---------------------------------

  qh_printvneighbors( fp, facetlist, facets, printall )
    print vertex neighbors of vertices in facetlist and facets ('FN')

  notes:
    qh_countfacets clears facet->visitid for non-printed facets

  design:
    collect facet count and related statistics
    if necessary, build neighbor sets for each vertex
    collect vertices in facetlist and facets
    build a point array for point->vertex and point->coplanar facet
    for each point
      list vertex neighbors or coplanar facet
*/
void qh_printvneighbors(FILE *fp, facetT* facetlist, setT *facets, boolT printall) {
  int numfacets, numsimplicial, numridges, totneighbors, numneighbors, numcoplanars, numtricoplanars;
  setT *vertices, *vertex_points, *coplanar_points;
  int numpoints= qh num_points + qh_setsize(qh other_points);
  vertexT *vertex, **vertexp;
  int vertex_i, vertex_n;
  facetT *facet, **facetp, *neighbor, **neighborp;
  pointT *point, **pointp;

  qh_countfacets(facetlist, facets, printall, &numfacets, &numsimplicial,
      &totneighbors, &numridges, &numcoplanars, &numtricoplanars);  /* sets facet->visitid */
  qh_fprintf(fp, 9248, "%d\n", numpoints);
  qh_vertexneighbors();
  vertices= qh_facetvertices(facetlist, facets, printall);
  vertex_points= qh_settemp(numpoints);
  coplanar_points= qh_settemp(numpoints);
  qh_setzero(vertex_points, 0, numpoints);
  qh_setzero(coplanar_points, 0, numpoints);
  FOREACHvertex_(vertices)
    qh_point_add(vertex_points, vertex->point, vertex);
  FORALLfacet_(facetlist) {
    FOREACHpoint_(facet->coplanarset)
      qh_point_add(coplanar_points, point, facet);
  }
  FOREACHfacet_(facets) {
    FOREACHpoint_(facet->coplanarset)
      qh_point_add(coplanar_points, point, facet);
  }
  FOREACHvertex_i_(vertex_points) {
    if (vertex) {
      numneighbors= qh_setsize(vertex->neighbors);
      qh_fprintf(fp, 9249, "%d", numneighbors);
      qh_order_vertexneighbors(vertex);
      FOREACHneighbor_(vertex)
        qh_fprintf(fp, 9250, " %d",
                 neighbor->visitid ? neighbor->visitid - 1 : 0 - neighbor->id);
      qh_fprintf(fp, 9251, "\n");
    }else if ((facet= SETelemt_(coplanar_points, vertex_i, facetT)))
      qh_fprintf(fp, 9252, "1 %d\n",
                  facet->visitid ? facet->visitid - 1 : 0 - facet->id);
    else
      qh_fprintf(fp, 9253, "0\n");
  }
  qh_settempfree(&coplanar_points);
  qh_settempfree(&vertex_points);
  qh_settempfree(&vertices);
} /* printvneighbors */

/*---------------------------------

  qh_printvoronoi( fp, format, facetlist, facets, printall )
    print voronoi diagram in 'o' or 'G' format
    for 'o' format
      prints voronoi centers for each facet and for infinity
      for each vertex, lists ids of printed facets or infinity
      assumes facetlist and facets are disjoint
    for 'G' format
      prints an OFF object
      adds a 0 coordinate to center
      prints infinity but does not list in vertices

  see:
    qh_printvdiagram()

  notes:
    if 'o',
      prints a line for each point except "at-infinity"
    if all facets are upperdelaunay,
      reverses lower and upper hull
*/
void qh_printvoronoi(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {
  int k, numcenters, numvertices= 0, numneighbors, numinf, vid=1, vertex_i, vertex_n;
  facetT *facet, **facetp, *neighbor, **neighborp;
  setT *vertices;
  vertexT *vertex;
  boolT isLower;
  unsigned int numfacets= (unsigned int)qh num_facets;

  vertices= qh_markvoronoi(facetlist, facets, printall, &isLower, &numcenters);
  FOREACHvertex_i_(vertices) {
    if (vertex) {
      numvertices++;
      numneighbors= numinf= 0;
      FOREACHneighbor_(vertex) {
        if (neighbor->visitid == 0)
          numinf= 1;
        else if (neighbor->visitid < numfacets)
          numneighbors++;
      }
      if (numinf && !numneighbors) {
        SETelem_(vertices, vertex_i)= NULL;
        numvertices--;
      }
    }
  }
  if (format == qh_PRINTgeom)
    qh_fprintf(fp, 9254, "{appearance {+edge -face} OFF %d %d 1 # Voronoi centers and cells\n",
                numcenters, numvertices);
  else
    qh_fprintf(fp, 9255, "%d\n%d %d 1\n", qh hull_dim-1, numcenters, qh_setsize(vertices));
  if (format == qh_PRINTgeom) {
    for (k=qh hull_dim-1; k--; )
      qh_fprintf(fp, 9256, qh_REAL_1, 0.0);
    qh_fprintf(fp, 9257, " 0 # infinity not used\n");
  }else {
    for (k=qh hull_dim-1; k--; )
      qh_fprintf(fp, 9258, qh_REAL_1, qh_INFINITE);
    qh_fprintf(fp, 9259, "\n");
  }
  FORALLfacet_(facetlist) {
    if (facet->visitid && facet->visitid < numfacets) {
      if (format == qh_PRINTgeom)
        qh_fprintf(fp, 9260, "# %d f%d\n", vid++, facet->id);
      qh_printcenter(fp, format, NULL, facet);
    }
  }
  FOREACHfacet_(facets) {
    if (facet->visitid && facet->visitid < numfacets) {
      if (format == qh_PRINTgeom)
        qh_fprintf(fp, 9261, "# %d f%d\n", vid++, facet->id);
      qh_printcenter(fp, format, NULL, facet);
    }
  }
  FOREACHvertex_i_(vertices) {
    numneighbors= 0;
    numinf=0;
    if (vertex) {
      qh_order_vertexneighbors(vertex);
      FOREACHneighbor_(vertex) {
        if (neighbor->visitid == 0)
          numinf= 1;
        else if (neighbor->visitid < numfacets)
          numneighbors++;
      }
    }
    if (format == qh_PRINTgeom) {
      if (vertex) {
        qh_fprintf(fp, 9262, "%d", numneighbors);
        FOREACHneighbor_(vertex) {
          if (neighbor->visitid && neighbor->visitid < numfacets)
            qh_fprintf(fp, 9263, " %d", neighbor->visitid);
        }
        qh_fprintf(fp, 9264, " # p%d(v%d)\n", vertex_i, vertex->id);
      }else
        qh_fprintf(fp, 9265, " # p%d is coplanar or isolated\n", vertex_i);
    }else {
      if (numinf)
        numneighbors++;
      qh_fprintf(fp, 9266, "%d", numneighbors);
      if (vertex) {
        FOREACHneighbor_(vertex) {
          if (neighbor->visitid == 0) {
            if (numinf) {
              numinf= 0;
              qh_fprintf(fp, 9267, " %d", neighbor->visitid);
            }
          }else if (neighbor->visitid < numfacets)
            qh_fprintf(fp, 9268, " %d", neighbor->visitid);
        }
      }
      qh_fprintf(fp, 9269, "\n");
    }
  }
  if (format == qh_PRINTgeom)
    qh_fprintf(fp, 9270, "}\n");
  qh_settempfree(&vertices);
} /* printvoronoi */

/*---------------------------------

  qh_printvnorm( fp, vertex, vertexA, centers, unbounded )
    print one separating plane of the Voronoi diagram for a pair of input sites
    unbounded==True if centers includes vertex-at-infinity

  assumes:
    qh_ASvoronoi and qh_vertexneighbors() already set

  note:
    parameter unbounded is UNUSED by this callback

  see:
    qh_printvdiagram()
    qh_eachvoronoi()
*/
void qh_printvnorm(FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {
  pointT *normal;
  realT offset;
  int k;
  QHULL_UNUSED(unbounded);

  normal= qh_detvnorm(vertex, vertexA, centers, &offset);
  qh_fprintf(fp, 9271, "%d %d %d ",
      2+qh hull_dim, qh_pointid(vertex->point), qh_pointid(vertexA->point));
  for (k=0; k< qh hull_dim-1; k++)
    qh_fprintf(fp, 9272, qh_REAL_1, normal[k]);
  qh_fprintf(fp, 9273, qh_REAL_1, offset);
  qh_fprintf(fp, 9274, "\n");
} /* printvnorm */

/*---------------------------------

  qh_printvridge( fp, vertex, vertexA, centers, unbounded )
    print one ridge of the Voronoi diagram for a pair of input sites
    unbounded==True if centers includes vertex-at-infinity

  see:
    qh_printvdiagram()

  notes:
    the user may use a different function
    parameter unbounded is UNUSED
*/
void qh_printvridge(FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {
  facetT *facet, **facetp;
  QHULL_UNUSED(unbounded);

  qh_fprintf(fp, 9275, "%d %d %d", qh_setsize(centers)+2,
       qh_pointid(vertex->point), qh_pointid(vertexA->point));
  FOREACHfacet_(centers)
    qh_fprintf(fp, 9276, " %d", facet->visitid);
  qh_fprintf(fp, 9277, "\n");
} /* printvridge */

/*---------------------------------

  qh_projectdim3( source, destination )
    project 2-d 3-d or 4-d point to a 3-d point
    uses qh.DROPdim and qh.hull_dim
    source and destination may be the same

  notes:
    allocate 4 elements to destination just in case
*/
void qh_projectdim3(pointT *source, pointT *destination) {
  int i,k;

  for (k=0, i=0; k < qh hull_dim; k++) {
    if (qh hull_dim == 4) {
      if (k != qh DROPdim)
        destination[i++]= source[k];
    }else if (k == qh DROPdim)
      destination[i++]= 0;
    else
      destination[i++]= source[k];
  }
  while (i < 3)
    destination[i++]= 0.0;
} /* projectdim3 */

/*---------------------------------

  qh_readfeasible( dim, curline )
    read feasible point from current line and qh.fin

  returns:
    number of lines read from qh.fin
    sets qh.feasible_point with malloc'd coordinates

  notes:
    checks for qh.HALFspace
    assumes dim > 1

  see:
    qh_setfeasible
*/
int qh_readfeasible(int dim, const char *curline) {
  boolT isfirst= True;
  int linecount= 0, tokcount= 0;
  const char *s;
  char *t, firstline[qh_MAXfirst+1];
  coordT *coords, value;

  if (!qh HALFspace) {
    qh_fprintf(qh ferr, 6070, "qhull input error: feasible point(dim 1 coords) is only valid for halfspace intersection\n");
    qh_errexit(qh_ERRinput, NULL, NULL);
  }
  if (qh feasible_string)
    qh_fprintf(qh ferr, 7057, "qhull input warning: feasible point(dim 1 coords) overrides 'Hn,n,n' feasible point for halfspace intersection\n");
  if (!(qh feasible_point= (coordT *)qh_malloc((size_t)dim * sizeof(coordT)))) {
    qh_fprintf(qh ferr, 6071, "qhull error: insufficient memory for feasible point\n");
    qh_errexit(qh_ERRmem, NULL, NULL);
  }
  coords= qh feasible_point;
  while ((s= (isfirst ?  curline : fgets(firstline, qh_MAXfirst, qh fin)))) {
    if (isfirst)
      isfirst= False;
    else
      linecount++;
    while (*s) {
      while (isspace(*s))
        s++;
      value= qh_strtod(s, &t);
      if (s == t)
        break;
      s= t;
      *(coords++)= value;
      if (++tokcount == dim) {
        while (isspace(*s))
          s++;
        qh_strtod(s, &t);
        if (s != t) {
          qh_fprintf(qh ferr, 6072, "qhull input error: coordinates for feasible point do not finish out the line: %s\n",
               s);
          qh_errexit(qh_ERRinput, NULL, NULL);
        }
        return linecount;
      }
    }
  }
  qh_fprintf(qh ferr, 6073, "qhull input error: only %d coordinates.  Could not read %d-d feasible point.\n",
           tokcount, dim);
  qh_errexit(qh_ERRinput, NULL, NULL);
  return 0;
} /* readfeasible */

/*---------------------------------

  qh_readpoints( numpoints, dimension, ismalloc )
    read points from qh.fin into qh.first_point, qh.num_points
    qh.fin is lines of coordinates, one per vertex, first line number of points
    if 'rbox D4',
      gives message
    if qh.ATinfinity,
      adds point-at-infinity for Delaunay triangulations

  returns:
    number of points, array of point coordinates, dimension, ismalloc True
    if qh.DELAUNAY & !qh.PROJECTinput, projects points to paraboloid
        and clears qh.PROJECTdelaunay
    if qh.HALFspace, reads optional feasible point, reads halfspaces,
        converts to dual.

  for feasible point in "cdd format" in 3-d:
    3 1
    coordinates
    comments
    begin
    n 4 real/integer
    ...
    end

  notes:
    dimension will change in qh_initqhull_globals if qh.PROJECTinput
    uses malloc() since qh_mem not initialized
    QH11012 FIX: qh_readpoints needs rewriting, too long
*/
coordT *qh_readpoints(int *numpoints, int *dimension, boolT *ismalloc) {
  coordT *points, *coords, *infinity= NULL;
  realT paraboloid, maxboloid= -REALmax, value;
  realT *coordp= NULL, *offsetp= NULL, *normalp= NULL;
  char *s= 0, *t, firstline[qh_MAXfirst+1];
  int diminput=0, numinput=0, dimfeasible= 0, newnum, k, tempi;
  int firsttext=0, firstshort=0, firstlong=0, firstpoint=0;
  int tokcount= 0, linecount=0, maxcount, coordcount=0;
  boolT islong, isfirst= True, wasbegin= False;
  boolT isdelaunay= qh DELAUNAY && !qh PROJECTinput;

  if (qh CDDinput) {
    while ((s= fgets(firstline, qh_MAXfirst, qh fin))) {
      linecount++;
      if (qh HALFspace && linecount == 1 && isdigit(*s)) {
        dimfeasible= qh_strtol(s, &s);
        while (isspace(*s))
          s++;
        if (qh_strtol(s, &s) == 1)
          linecount += qh_readfeasible(dimfeasible, s);
        else
          dimfeasible= 0;
      }else if (!memcmp(firstline, "begin", (size_t)5) || !memcmp(firstline, "BEGIN", (size_t)5))
        break;
      else if (!*qh rbox_command)
        strncat(qh rbox_command, s, sizeof(qh rbox_command)-1);
    }
    if (!s) {
      qh_fprintf(qh ferr, 6074, "qhull input error: missing \"begin\" for cdd-formated input\n");
      qh_errexit(qh_ERRinput, NULL, NULL);
    }
  }
  while (!numinput && (s= fgets(firstline, qh_MAXfirst, qh fin))) {
    linecount++;
    if (!memcmp(s, "begin", (size_t)5) || !memcmp(s, "BEGIN", (size_t)5))
      wasbegin= True;
    while (*s) {
      while (isspace(*s))
        s++;
      if (!*s)
        break;
      if (!isdigit(*s)) {
        if (!*qh rbox_command) {
          strncat(qh rbox_command, s, sizeof(qh rbox_command)-1);
          firsttext= linecount;
        }
        break;
      }
      if (!diminput)
        diminput= qh_strtol(s, &s);
      else {
        numinput= qh_strtol(s, &s);
        if (numinput == 1 && diminput >= 2 && qh HALFspace && !qh CDDinput) {
          linecount += qh_readfeasible(diminput, s); /* checks if ok */
          dimfeasible= diminput;
          diminput= numinput= 0;
        }else
          break;
      }
    }
  }
  if (!s) {
    qh_fprintf(qh ferr, 6075, "qhull input error: short input file.  Did not find dimension and number of points\n");
    qh_errexit(qh_ERRinput, NULL, NULL);
  }
  if (diminput > numinput) {
    tempi= diminput;    /* exchange dim and n, e.g., for cdd input format */
    diminput= numinput;
    numinput= tempi;
  }
  if (diminput < 2) {
    qh_fprintf(qh ferr, 6220, "qhull input error: dimension %d (first or smaller number) should be at least 2\n",
            diminput);
    qh_errexit(qh_ERRinput, NULL, NULL);
  }
  if (numinput < 1 || numinput > qh_POINTSmax) {
    qh_fprintf(qh ferr, 6411, "qhull input error: expecting between 1 and %d points.  Got %d %d-d points\n",
      qh_POINTSmax, numinput, diminput);
    qh_errexit(qh_ERRinput, NULL, NULL);
    /* same error message in qh_initqhull_globals */
  }

  if (isdelaunay && qh HALFspace) {
    qh_fprintf(qh ferr, 6037, "qhull option error (qh_readpoints): can not use Delaunay('d') or Voronoi('v') with halfspace intersection('H')\n");
    qh_errexit(qh_ERRinput, NULL, NULL);
    /* otherwise corrupted memory allocations, same error message as in qh_initqhull_globals */
  }else if (isdelaunay) {
    qh PROJECTdelaunay= False;
    if (qh CDDinput)
      *dimension= diminput;
    else
      *dimension= diminput+1;
    *numpoints= numinput;
    if (qh ATinfinity)
      (*numpoints)++;
  }else if (qh HALFspace) {
    *dimension= diminput - 1;
    *numpoints= numinput;
    if (diminput < 3) {
      qh_fprintf(qh ferr, 6221, "qhull input error: dimension %d (first number, includes offset) should be at least 3 for halfspaces\n",
            diminput);
      qh_errexit(qh_ERRinput, NULL, NULL);
    }
    if (dimfeasible) {
      if (dimfeasible != *dimension) {
        qh_fprintf(qh ferr, 6222, "qhull input error: dimension %d of feasible point is not one less than dimension %d for halfspaces\n",
          dimfeasible, diminput);
        qh_errexit(qh_ERRinput, NULL, NULL);
      }
    }else
      qh_setfeasible(*dimension);
  }else {
    if (qh CDDinput)
      *dimension= diminput-1;
    else
      *dimension= diminput;
    *numpoints= numinput;
  }
  qh normal_size= *dimension * (int)sizeof(coordT); /* for tracing with qh_printpoint */
  if (qh HALFspace) {
    qh half_space= coordp= (coordT *)qh_malloc((size_t)qh normal_size + sizeof(coordT));
    if (qh CDDinput) {
      offsetp= qh half_space;
      normalp= offsetp + 1;
    }else {
      normalp= qh half_space;
      offsetp= normalp + *dimension;
    }
  }
  qh maxline= diminput * (qh_REALdigits + 5);
  maximize_(qh maxline, 500);
  qh line= (char *)qh_malloc((size_t)(qh maxline+1) * sizeof(char));
  *ismalloc= True;  /* use malloc since memory not setup */
  coords= points= qh temp_malloc=  /* numinput and diminput >=2 by QH6220 */
        (coordT *)qh_malloc((size_t)((*numpoints)*(*dimension))*sizeof(coordT));
  if (!coords || !qh line || (qh HALFspace && !qh half_space)) {
    qh_fprintf(qh ferr, 6076, "qhull error: insufficient memory to read %d points\n",
            numinput);
    qh_errexit(qh_ERRmem, NULL, NULL);
  }
  if (isdelaunay && qh ATinfinity) {
    infinity= points + numinput * (*dimension);
    for (k= (*dimension) - 1; k--; )
      infinity[k]= 0.0;
  }
  maxcount= numinput * diminput;
  paraboloid= 0.0;
  while ((s= (isfirst ?  s : fgets(qh line, qh maxline, qh fin)))) {
    if (!isfirst) {
      linecount++;
      if (*s == 'e' || *s == 'E') {
        if (!memcmp(s, "end", (size_t)3) || !memcmp(s, "END", (size_t)3)) {
          if (qh CDDinput )
            break;
          else if (wasbegin)
            qh_fprintf(qh ferr, 7058, "qhull input warning: the input appears to be in cdd format.  If so, use 'Fd'\n");
        }
      }
    }
    islong= False;
    while (*s) {
      while (isspace(*s))
        s++;
      value= qh_strtod(s, &t);
      if (s == t) {
        if (!*qh rbox_command)
         strncat(qh rbox_command, s, sizeof(qh rbox_command)-1);
        if (*s && !firsttext)
          firsttext= linecount;
        if (!islong && !firstshort && coordcount)
          firstshort= linecount;
        break;
      }
      if (!firstpoint)
        firstpoint= linecount;
      s= t;
      if (++tokcount > maxcount)
        continue;
      if (qh HALFspace) {
        if (qh CDDinput)
          *(coordp++)= -value; /* both coefficients and offset */
        else
          *(coordp++)= value;
      }else {
        *(coords++)= value;
        if (qh CDDinput && !coordcount) {
          if (value != 1.0) {
            qh_fprintf(qh ferr, 6077, "qhull input error: for cdd format, point at line %d does not start with '1'\n",
                   linecount);
            qh_errexit(qh_ERRinput, NULL, NULL);
          }
          coords--;
        }else if (isdelaunay) {
          paraboloid += value * value;
          if (qh ATinfinity) {
            if (qh CDDinput)
              infinity[coordcount-1] += value;
            else
              infinity[coordcount] += value;
          }
        }
      }
      if (++coordcount == diminput) {
        coordcount= 0;
        if (isdelaunay) {
          *(coords++)= paraboloid;
          maximize_(maxboloid, paraboloid);
          paraboloid= 0.0;
        }else if (qh HALFspace) {
          if (!qh_sethalfspace(*dimension, coords, &coords, normalp, offsetp, qh feasible_point)) {
            qh_fprintf(qh ferr, 8048, "The halfspace was on line %d\n", linecount);
            if (wasbegin)
              qh_fprintf(qh ferr, 8049, "The input appears to be in cdd format.  If so, you should use option 'Fd'\n");
            qh_errexit(qh_ERRinput, NULL, NULL);
          }
          coordp= qh half_space;
        }
        while (isspace(*s))
          s++;
        if (*s) {
          islong= True;
          if (!firstlong)
            firstlong= linecount;
        }
      }
    }
    if (!islong && !firstshort && coordcount)
      firstshort= linecount;
    if (!isfirst && s - qh line >= qh maxline) {
      qh_fprintf(qh ferr, 6078, "qhull input error: line %d contained more than %d characters\n",
              linecount, (int) (s - qh line));   /* WARN64 */
      qh_errexit(qh_ERRinput, NULL, NULL);
    }
    isfirst= False;
  }
  if (qh rbox_command[0])
    qh rbox_command[strlen(qh rbox_command)-1]= '\0'; /* remove \n, previous qh_errexit's display command as two lines */
  if (tokcount != maxcount) {
    newnum= fmin_(numinput, tokcount/diminput);
    if (qh ALLOWshort)
      qh_fprintf(qh ferr, 7073, "qhull warning: instead of %d points in %d-d, input contains %d points and %d extra coordinates.\n",
          numinput, diminput, tokcount/diminput, tokcount % diminput);
    else
      qh_fprintf(qh ferr, 6410, "qhull error: instead of %d points in %d-d, input contains %d points and %d extra coordinates.\n",
          numinput, diminput, tokcount/diminput, tokcount % diminput);
    if (firsttext)
      qh_fprintf(qh ferr, 8051, "    Line %d is the first comment.\n", firsttext);
    qh_fprintf(qh ferr, 8033,   "    Line %d is the first point.\n", firstpoint);
    if (firstshort)
      qh_fprintf(qh ferr, 8052, "    Line %d is the first short line.\n", firstshort);
    if (firstlong)
      qh_fprintf(qh ferr, 8053, "    Line %d is the first long line.\n", firstlong);
    if (qh ALLOWshort)
      qh_fprintf(qh ferr, 8054, "    Continuing with %d points.\n", newnum);
    else {
      qh_fprintf(qh ferr, 8077, "    Override with option 'Qa' (allow-short)\n");
      qh_errexit(qh_ERRinput, NULL, NULL);
    }
    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 (!strcmp(qh rbox_command, "./rbox D4"))
    qh_fprintf(qh ferr, 8055, "\n\
This is the qhull test case.  If any errors or core dumps occur,\n\
recompile qhull with 'make new'.  If errors still occur, there is\n\
an incompatibility.  You should try a different compiler.  You can also\n\
change the choices in user.h.  If you discover the source of the problem,\n\
please send mail to qhull_bug@qhull.org.\n\
\n\
Type 'qhull' for a short list of options.\n");
  qh_free(qh line);
  qh line= NULL;
  if (qh half_space) {
    qh_free(qh half_space);
    qh half_space= NULL;
  }
  qh temp_malloc= NULL;
  trace1((qh ferr, 1008,"qh_readpoints: read in %d %d-dimensional points\n",
          numinput, diminput));
  return(points);
} /* readpoints */


/*---------------------------------

  qh_setfeasible( dim )
    set qh.feasible_point 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()
    called only once from qh_new_qhull, otherwise leaks memory
*/
void qh_setfeasible(int dim) {
  int tokcount= 0;
  char *s;
  coordT *coords, value;

  if (!(s= qh feasible_string)) {
    qh_fprintf(qh ferr, 6223, "qhull input error: halfspace intersection needs a feasible point.  Either prepend the input with 1 point or use 'Hn,n,n'.  See manual.\n");
    qh_errexit(qh_ERRinput, NULL, NULL);
  }
  if (!(qh feasible_point= (pointT *)qh_malloc((size_t)dim * sizeof(coordT)))) {
    qh_fprintf(qh ferr, 6079, "qhull error: insufficient memory for 'Hn,n,n'\n");
    qh_errexit(qh_ERRmem, NULL, NULL);
  }
  coords= qh feasible_point;
  while (*s) {
    value= qh_strtod(s, &s);
    if (++tokcount > dim) {
      qh_fprintf(qh ferr, 7059, "qhull input warning: more coordinates for 'H%s' than dimension %d\n",
          qh feasible_string, dim);
      break;
    }
    *(coords++)= value;
    if (*s)
      s++;
  }
  while (++tokcount <= dim)
    *(coords++)= 0.0;
} /* setfeasible */

/*---------------------------------

  qh_skipfacet( facet )
    returns 'True' if this facet is not to be printed

  notes:
    based on the user provided slice thresholds and 'good' specifications
*/
boolT qh_skipfacet(facetT *facet) {
  facetT *neighbor, **neighborp;

  if (qh PRINTneighbors) {
    if (facet->good)
      return !qh PRINTgood;
    FOREACHneighbor_(facet) {
      if (neighbor->good)
        return False;
    }
    return True;
  }else if (qh PRINTgood)
    return !facet->good;
  else if (!facet->normal)
    return True;
  return(!qh_inthresholds(facet->normal, NULL));
} /* skipfacet */

/*---------------------------------

  qh_skipfilename( string )
    returns pointer to character after filename

  notes:
    skips leading spaces
    ends with spacing or eol
    if starts with ' or " ends with the same, skipping \' or \"
    For qhull, qh_argv_to_command() only uses double quotes
*/
char *qh_skipfilename(char *filename) {
  char *s= filename;  /* non-const due to return */
  char c;

  while (*s && isspace(*s))
    s++;
  c= *s++;
  if (c == '\0') {
    qh_fprintf(qh ferr, 6204, "qhull input error: filename expected, none found.\n");
    qh_errexit(qh_ERRinput, NULL, NULL);
  }
  if (c == '\'' || c == '"') {
    while (*s !=c || s[-1] == '\\') {
      if (!*s) {
        qh_fprintf(qh ferr, 6203, "qhull input error: missing quote after filename -- %s\n", filename);
        qh_errexit(qh_ERRinput, NULL, NULL);
      }
      s++;
    }
    s++;
  }
  else while (*s && !isspace(*s))
      s++;
  return s;
} /* skipfilename */

qhull-2020.2/src/libqhull/io.h0000644060175106010010000001725513661631132014365 0ustar  bbarber/*
  ---------------------------------

   io.h
   declarations of Input/Output functions

   see README, libqhull.h and io.c

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull/io.h#3 $$Change: 2953 $
   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
*/

#ifndef qhDEFio
#define qhDEFio 1

#include "libqhull.h"

/*============ constants and flags ==================*/

/*----------------------------------

  qh_MAXfirst
    maximum length of first two lines of stdin
*/
#define qh_MAXfirst  200

/*----------------------------------

  qh_MINradius
    min radius for Gp and Gv, fraction of maxcoord
*/
#define qh_MINradius 0.02

/*----------------------------------

  qh_GEOMepsilon
    adjust outer planes for 'lines closer' and geomview roundoff.
    This prevents bleed through.
*/
#define qh_GEOMepsilon 2e-3

/*----------------------------------

  qh_WHITESPACE
    possible values of white space
*/
#define qh_WHITESPACE " \n\t\v\r\f"


/*----------------------------------

  qh_RIDGE
    to select which ridges to print in qh_eachvoronoi
*/
typedef enum
{
    qh_RIDGEall= 0, qh_RIDGEinner, qh_RIDGEouter
}
qh_RIDGE;

/*----------------------------------

  printvridgeT
    prints results of qh_printvdiagram

  see:
    qh_printvridge for an example
*/
typedef void (*printvridgeT)(FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);

/*============== -prototypes in alphabetical order =========*/

void    qh_dfacet(unsigned int id);
void    qh_dvertex(unsigned int id);
int     qh_compare_facetarea(const void *p1, const void *p2);
int     qh_compare_facetvisit(const void *p1, const void *p2);
int     qh_compare_nummerge(const void *p1, const void *p2);
void    qh_copyfilename(char *filename, int size, const char* source, int length);
void    qh_countfacets(facetT *facetlist, setT *facets, boolT printall,
              int *numfacetsp, int *numsimplicialp, int *totneighborsp,
              int *numridgesp, int *numcoplanarsp, int *numnumtricoplanarsp);
pointT *qh_detvnorm(vertexT *vertex, vertexT *vertexA, setT *centers, realT *offsetp);
setT   *qh_detvridge(vertexT *vertex);
setT   *qh_detvridge3(vertexT *atvertex, vertexT *vertex);
int     qh_eachvoronoi(FILE *fp, printvridgeT printvridge, vertexT *atvertex, boolT visitall, qh_RIDGE innerouter, boolT inorder);
int     qh_eachvoronoi_all(FILE *fp, printvridgeT printvridge, boolT isUpper, qh_RIDGE innerouter, boolT inorder);
void    qh_facet2point(facetT *facet, pointT **point0, pointT **point1, realT *mindist);
setT   *qh_facetvertices(facetT *facetlist, setT *facets, boolT allfacets);
void    qh_geomplanes(facetT *facet, realT *outerplane, realT *innerplane);
void    qh_markkeep(facetT *facetlist);
setT   *qh_markvoronoi(facetT *facetlist, setT *facets, boolT printall, boolT *isLowerp, int *numcentersp);
void    qh_order_vertexneighbors(vertexT *vertex);
void    qh_prepare_output(void);
void    qh_printafacet(FILE *fp, qh_PRINT format, facetT *facet, boolT printall);
void    qh_printbegin(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
void    qh_printcenter(FILE *fp, qh_PRINT format, const char *string, facetT *facet);
void    qh_printcentrum(FILE *fp, facetT *facet, realT radius);
void    qh_printend(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
void    qh_printend4geom(FILE *fp, facetT *facet, int *num, boolT printall);
void    qh_printextremes(FILE *fp, facetT *facetlist, setT *facets, boolT printall);
void    qh_printextremes_2d(FILE *fp, facetT *facetlist, setT *facets, boolT printall);
void    qh_printextremes_d(FILE *fp, facetT *facetlist, setT *facets, boolT printall);
void    qh_printfacet(FILE *fp, facetT *facet);
void    qh_printfacet2math(FILE *fp, facetT *facet, qh_PRINT format, int notfirst);
void    qh_printfacet2geom(FILE *fp, facetT *facet, realT color[3]);
void    qh_printfacet2geom_points(FILE *fp, pointT *point1, pointT *point2,
                               facetT *facet, realT offset, realT color[3]);
void    qh_printfacet3math(FILE *fp, facetT *facet, qh_PRINT format, int notfirst);
void    qh_printfacet3geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]);
void    qh_printfacet3geom_points(FILE *fp, setT *points, facetT *facet, realT offset, realT color[3]);
void    qh_printfacet3geom_simplicial(FILE *fp, facetT *facet, realT color[3]);
void    qh_printfacet3vertex(FILE *fp, facetT *facet, qh_PRINT format);
void    qh_printfacet4geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]);
void    qh_printfacet4geom_simplicial(FILE *fp, facetT *facet, realT color[3]);
void    qh_printfacetNvertex_nonsimplicial(FILE *fp, facetT *facet, int id, qh_PRINT format);
void    qh_printfacetNvertex_simplicial(FILE *fp, facetT *facet, qh_PRINT format);
void    qh_printfacetheader(FILE *fp, facetT *facet);
void    qh_printfacetridges(FILE *fp, facetT *facet);
void    qh_printfacets(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
void    qh_printhyperplaneintersection(FILE *fp, facetT *facet1, facetT *facet2,
                   setT *vertices, realT color[3]);
void    qh_printline3geom(FILE *fp, pointT *pointA, pointT *pointB, realT color[3]);
void    qh_printneighborhood(FILE *fp, qh_PRINT format, facetT *facetA, facetT *facetB, boolT printall);
void    qh_printpoint(FILE *fp, const char *string, pointT *point);
void    qh_printpointid(FILE *fp, const char *string, int dim, pointT *point, int id);
void    qh_printpoint3(FILE *fp, pointT *point);
void    qh_printpoints_out(FILE *fp, facetT *facetlist, setT *facets, boolT printall);
void    qh_printpointvect(FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius, realT color[3]);
void    qh_printpointvect2(FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius);
void    qh_printridge(FILE *fp, ridgeT *ridge);
void    qh_printspheres(FILE *fp, setT *vertices, realT radius);
void    qh_printvdiagram(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
int     qh_printvdiagram2(FILE *fp, printvridgeT printvridge, setT *vertices, qh_RIDGE innerouter, boolT inorder);
void    qh_printvertex(FILE *fp, vertexT *vertex);
void    qh_printvertexlist(FILE *fp, const char* string, facetT *facetlist,
                         setT *facets, boolT printall);
void    qh_printvertices(FILE *fp, const char* string, setT *vertices);
void    qh_printvneighbors(FILE *fp, facetT* facetlist, setT *facets, boolT printall);
void    qh_printvoronoi(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
void    qh_printvnorm(FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
void    qh_printvridge(FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
void    qh_produce_output(void);
void    qh_produce_output2(void);
void    qh_projectdim3(pointT *source, pointT *destination);
int     qh_readfeasible(int dim, const char *curline);
coordT *qh_readpoints(int *numpoints, int *dimension, boolT *ismalloc);
void    qh_setfeasible(int dim);
boolT   qh_skipfacet(facetT *facet);
char   *qh_skipfilename(char *filename);

#endif /* qhDEFio */
qhull-2020.2/src/libqhull/libqhull.c0000644060175106010010000021114013661631132015552 0ustar  bbarber/*
  ---------------------------------

   libqhull.c
   Quickhull algorithm for convex hulls

   qhull() and top-level routines

   see qh-qhull.htm, libqhull.h, unix.c

   see qhull_a.h for internal functions

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull/libqhull.c#13 $$Change: 2953 $
   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
*/

#include "qhull_a.h"

/*============= functions in alphabetic order after qhull() =======*/

/*---------------------------------

  qh_qhull( )
    compute DIM3 convex hull of qh.num_points starting at qh.first_point
    qh contains all global options and variables

  returns:
    returns polyhedron
      qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices,

    returns global variables
      qh.hulltime, qh.max_outside, qh.interior_point, qh.max_vertex, qh.min_vertex

    returns precision constants
      qh.ANGLEround, centrum_radius, cos_max, DISTround, MAXabs_coord, ONEmerge

  notes:
    unless needed for output
      qh.max_vertex and qh.min_vertex are max/min due to merges

  see:
    to add individual points to either qh.num_points
      use qh_addpoint()

    if qh.GETarea
      qh_produceoutput() returns qh.totarea and qh.totvol via qh_getarea()

  design:
    record starting time
    initialize hull and partition points
    build convex hull
    unless early termination
      update facet->maxoutside for vertices, coplanar, and near-inside points
    error if temporary sets exist
    record end time
*/

void qh_qhull(void) {
  int numoutside;

  qh hulltime= qh_CPUclock;
  if (qh RERUN || qh JOGGLEmax < REALmax/2)
    qh_build_withrestart();
  else {
    qh_initbuild();
    qh_buildhull();
  }
  if (!qh STOPadd && !qh STOPcone && !qh STOPpoint) {
    if (qh ZEROall_ok && !qh TESTvneighbors && qh MERGEexact)
      qh_checkzero(qh_ALL);
    if (qh ZEROall_ok && !qh TESTvneighbors && !qh WAScoplanar) {
      trace2((qh ferr, 2055, "qh_qhull: all facets are clearly convex and no coplanar points.  Post-merging and check of maxout not needed.\n"));
      qh DOcheckmax= False;
    }else {
      qh_initmergesets(/* qh.facet_mergeset,degen_mergeset,vertex_mergeset */);
      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)); /* calls qh_reducevertices */
      else if (!qh POSTmerge && qh TESTvneighbors)
        qh_postmerge("For testing vertex neighbors", qh premerge_centrum,
             qh premerge_cos, True);                       /* calls qh_test_vneighbors */
      if (qh POSTmerge)
        qh_postmerge("For post-merging", qh postmerge_centrum,
             qh postmerge_cos, qh TESTvneighbors);
      if (qh visible_list == qh facet_list) {            /* qh_postmerge was called */
        qh findbestnew= True;
        qh_partitionvisible(!qh_ALL, &numoutside /* qh.visible_list */);
        qh findbestnew= False;
        qh_deletevisible(/* qh.visible_list */);        /* stops at first !f.visible */
        qh_resetlists(False, qh_RESETvisible /* qh.visible_list newvertex_list qh.newfacet_list */);
      }
      qh_all_vertexmerges(-1, NULL, NULL);
      qh_freemergesets();
    }
    if (qh TRACEpoint == qh_IDunknown && qh TRACElevel > qh IStracing) {
      qh IStracing= qh TRACElevel;
      qh_fprintf(qh ferr, 2112, "qh_qhull: finished qh_buildhull and qh_postmerge, start tracing (TP-1)\n");
    }
    if (qh DOcheckmax){
      if (qh REPORTfreq) {
        qh_buildtracing(NULL, NULL);
        qh_fprintf(qh ferr, 8115, "\nTesting all coplanar points.\n");
      }
      qh_check_maxout();
    }
    if (qh KEEPnearinside && !qh maxoutdone)
      qh_nearcoplanar();
  }
  if (qh_setsize(qhmem.tempstack) != 0) {
    qh_fprintf(qh ferr, 6164, "qhull internal error (qh_qhull): temporary sets not empty(%d) at end of Qhull\n",
             qh_setsize(qhmem.tempstack));
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  qh hulltime= qh_CPUclock - qh hulltime;
  qh QHULLfinished= True;
  trace1((qh ferr, 1036, "Qhull: algorithm completed\n"));
} /* qhull */

/*---------------------------------

  qh_addpoint( furthest, facet, checkdist )
    add point (usually furthest point) above facet to hull
    if checkdist,
      check that point is above facet.
      if point is not outside of the hull, uses qh_partitioncoplanar()
      assumes that facet is defined by qh_findbestfacet()
    else if facet specified,
      assumes that point is above facet (major damage if below)
    for Delaunay triangulations,
      Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed
      Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates.

  returns:
    returns False if user requested an early termination
      qh.visible_list, newfacet_list, delvertex_list, NEWfacets may be defined
    updates qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices
    clear qh.maxoutdone (will need to call qh_check_maxout() for facet->maxoutside)
    if unknown point, adds a pointer to qh.other_points
      do not deallocate the point's coordinates

  notes:
    called from qh_initbuild, qh_buildhull, and qh_addpoint
    tail recursive call if merged a pinchedvertex due to a duplicated ridge
      no more than qh.num_vertices calls (QH6296)
    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
    if called from a user application after qh_qhull and 'QJ' (joggle),
      facet merging for precision problems is disabled by default

  design:
    exit if qh.STOPadd vertices 'TAn'
    add point to other_points if needed
    if checkdist
      if point not above facet
        partition coplanar point
        exit
    exit if pre STOPpoint requested
    find horizon and visible facets for point
    build cone of new facets to the horizon
    exit if build cone fails due to qh.ONLYgood
    tail recursive call if build cone fails due to pinched 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) {
  realT dist, pbalance;
  facetT *replacefacet, *newfacet;
  vertexT *apex;
  boolT isoutside= False;
  int numpart, numpoints, goodvisible, goodhorizon, apexpointid;

  qh maxoutdone= False;
  if (qh_pointid(furthest) == qh_IDunknown)
    qh_setappend(&qh other_points, furthest);
  if (!facet) {
    qh_fprintf(qh ferr, 6213, "qhull internal error (qh_addpoint): NULL facet.  Need to call qh_findbestfacet first\n");
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  qh_detmaxoutside();
  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, qh findbestnew);
      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 && !qh GOODclosest && !(goodvisible+goodhorizon)) {
    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 qh.newfacet_list */);
    return True;
  }
  apex= qh_buildcone(furthest, facet, goodhorizon, &replacefacet);
  /* qh.newfacet_list, visible_list, newvertex_list */
  if (!apex) {
    if (qh ONLYgood)
      return True; /* ignore this furthest point, a good new facet was not found */
    if (replacefacet) {
      if (qh retry_addpoint++ >= qh num_vertices) {
        qh_fprintf(qh ferr, 6296, "qhull internal error (qh_addpoint): infinite loop (%d retries) of merging pinched vertices due to dupridge for point p%d, facet f%d, and %d vertices\n",
          qh retry_addpoint, qh_pointid(furthest), facet->id, qh num_vertices);
        qh_errexit(qh_ERRqhull, facet, NULL);
      }
      /* retry qh_addpoint after resolving a dupridge via qh_merge_pinchedvertices */
      return qh_addpoint(furthest, replacefacet, True /* checkdisk */);
    }
    qh retry_addpoint= 0;
    return True; /* ignore this furthest point, resolved a dupridge by making furthest a coplanar point */
  }
  if (qh retry_addpoint) {
    zinc_(Zretryadd);
    zadd_(Zretryaddtot, qh retry_addpoint);
    zmax_(Zretryaddmax, qh retry_addpoint);
    qh retry_addpoint= 0;
  }
  apexpointid= qh_pointid(apex->point);
  zzinc_(Zprocessed);
  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_initmergesets(/* qh.facet_mergeset,degen_mergeset,vertex_mergeset */);
    qh_premerge(apexpointid, qh premerge_centrum, qh premerge_cos /* qh.newfacet_list */);
    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;
  if (qh IStracing >= 4)
    qh_checkpolygon(qh visible_list);
  qh_partitionvisible(!qh_ALL, &numpoints /* qh.visible_list */);
  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 < 200)
      qh_printlists();
    qh_printfacetlist(qh newfacet_list, NULL, True);
    qh_checkpolygon(qh facet_list);
  }else if (qh CHECKfrequently) {
    if (qh num_facets < 1000)
      qh_checkpolygon(qh facet_list);
    else
      qh_checkpolygon(qh newfacet_list);
  }
  if (qh STOPpoint > 0 && qh furthest_id == qh STOPpoint-1 && qh_setsize(qh vertex_mergeset) > 0)
    return False;
  qh_resetlists(True, qh_RESETvisible /* qh.visible_list newvertex_list qh.newfacet_list */);
  if (qh facet_mergeset) {
    /* vertex merges occur after facet merges (qh_premerge) and qh_resetlists */
    qh_all_vertexmerges(apexpointid, NULL, NULL);
    qh_freemergesets();
  }
  /* qh_triangulate(); to test qh.TRInormals */
  if (qh STOPpoint > 0 && qh furthest_id == qh STOPpoint-1)
    return False;
  trace2((qh ferr, 2056, "qh_addpoint: added p%d to convex hull with point balance %2.2g\n",
    qh_pointid(furthest), pbalance));
  return True;
} /* addpoint */

/*---------------------------------

  qh_build_withrestart( )
    allow restarts due to qh.JOGGLEmax while calling qh_buildhull()
       qh_errexit always undoes qh_build_withrestart()
    qh.FIRSTpoint/qh.NUMpoints is point array
       it may be moved by qh_joggleinput
*/
void qh_build_withrestart(void) {
  int restart;
  vertexT *vertex, **vertexp;

  qh ALLOWrestart= True;
  while (True) {
    restart= setjmp(qh restartexit); /* simple statement for CRAY J916 */
    if (restart) {       /* only from qh_joggle_restart() */
      qh last_errcode= qh_ERRnone;
      zzinc_(Zretry);
      wmax_(Wretrymax, qh JOGGLEmax);
      /* QH7078 warns about using 'TCn' with 'QJn' */
      qh STOPcone= qh_IDunknown; /* if break from joggle, prevents normal output */
      FOREACHvertex_(qh del_vertices) {
        if (vertex->point && !vertex->partitioned)
          vertex->partitioned= True; /* avoid error in qh_freebuild -> qh_delvertex */
      }
    }
    if (!qh RERUN && qh JOGGLEmax < REALmax/2) {
      if (qh build_cnt > qh_JOGGLEmaxretry) {
        qh_fprintf(qh ferr, 6229, "qhull input error: %d attempts to construct a convex hull with joggled input.  Increase joggle above 'QJ%2.2g' or modify qh_JOGGLE... parameters in user.h\n",
           qh build_cnt, qh JOGGLEmax);
        qh_errexit(qh_ERRinput, NULL, NULL);
      }
      if (qh build_cnt && !restart)
        break;
    }else if (qh build_cnt && qh build_cnt >= qh RERUN)
      break;
    qh STOPcone= 0;
    qh_freebuild(True);  /* first call is a nop */
    qh build_cnt++;
    if (!qh qhull_optionsiz)
      qh qhull_optionsiz= (int)strlen(qh qhull_options);   /* WARN64 */
    else {
      qh qhull_options[qh qhull_optionsiz]= '\0';
      qh qhull_optionlen= qh_OPTIONline;  /* starts a new line */
    }
    qh_option("_run", &qh build_cnt, NULL);
    if (qh build_cnt == qh RERUN) {
      qh IStracing= qh TRACElastrun;  /* duplicated from qh_initqhull_globals */
      if (qh TRACEpoint != qh_IDnone || qh TRACEdist < REALmax/2 || qh TRACEmerge) {
        qh TRACElevel= (qh IStracing? qh IStracing : 3);
        qh IStracing= 0;
      }
      qhmem.IStracing= qh IStracing;
    }
    if (qh JOGGLEmax < REALmax/2)
      qh_joggleinput();
    qh_initbuild();
    qh_buildhull();
    if (qh JOGGLEmax < REALmax/2 && !qh MERGING)
      qh_checkconvex(qh facet_list, qh_ALGORITHMfault);
  }
  qh ALLOWrestart= False;
} /* qh_build_withrestart */

/*---------------------------------

  qh_buildcone( furthest, facet, goodhorizon, &replacefacet )
    build cone of new facets from furthest to the horizon
    goodhorizon is count of good, horizon facets from qh_find_horizon

  returns:
    returns apex of cone with qh.newfacet_list and qh.first_newfacet (f.id)
    returns NULL if qh.ONLYgood and no good facets
    returns NULL and retryfacet if merging pinched vertices will resolve a dupridge
      a horizon vertex was nearly adjacent to another vertex
      will retry qh_addpoint
    returns NULL if resolve a dupridge by making furthest a coplanar point
      furthest was nearly adjacent to an existing vertex
    updates qh.degen_mergeset (MRGridge) if resolve a dupridge by merging facets
    updates qh.newfacet_list, visible_list, newvertex_list
    updates qh.facet_list, vertex_list, num_facets, num_vertices

  notes:
    called by qh_addpoint
    see qh_triangulate, it triangulates non-simplicial facets in post-processing

  design:
    make new facets for point to horizon
    compute balance statistics
    make hyperplanes for point
    exit if qh.ONLYgood and not good (qh_buildcone_onlygood)
    match neighboring new facets
    if dupridges
      exit if !qh.IGNOREpinched and dupridge resolved by coplanar furthest
      retry qh_buildcone if !qh.IGNOREpinched and dupridge resolved by qh_buildcone_mergepinched
      otherwise dupridges resolved by merging facets
    update vertex neighbors and delete interior vertices
*/
vertexT *qh_buildcone(pointT *furthest, facetT *facet, int goodhorizon, facetT **retryfacet) {
  vertexT *apex;
  realT newbalance;
  int numnew;

  *retryfacet= NULL;
  qh first_newfacet= qh facet_id;
  qh NEWtentative= (qh MERGEpinched || qh ONLYgood); /* cleared by qh_attachnewfacets or qh_resetlists */
  apex= qh_makenewfacets(furthest /* qh.newfacet_list visible_list, attaches new facets if !qh.NEWtentative */);
  numnew= (int)(qh facet_id - qh first_newfacet);
  newbalance= numnew - (realT)(qh num_facets - qh num_visible) * qh hull_dim / qh num_vertices;
  /* newbalance statistics updated below if the new facets are accepted */
  if (qh ONLYgood) { /* qh.MERGEpinched is false by QH6362 */
    if (!qh_buildcone_onlygood(apex, goodhorizon /* qh.newfacet_list */)) {
      facet->notfurthest= True;
      return NULL;
    }
  }else if(qh MERGEpinched) {
#ifndef qh_NOmerge
    if (qh_buildcone_mergepinched(apex, facet, retryfacet /* qh.newfacet_list */))
      return NULL;
#else
    qh_fprintf(qh ferr, 6375, "qhull option error (qh_buildcone): option 'Q14' (qh.MERGEpinched) is not available due to qh_NOmerge\n");
    qh_errexit(qh_ERRinput, NULL, NULL);
#endif
  }else {
    /* qh_makenewfacets attached new facets to the horizon */
    qh_matchnewfacets(); /* ignore returned value.  qh_forcedmerges will merge dupridges if any */
    qh_makenewplanes(/* qh.newfacet_list */);
    qh_update_vertexneighbors_cone();
  }
  wadd_(Wnewbalance, newbalance);
  wadd_(Wnewbalance2, newbalance * newbalance);
  trace2((qh ferr, 2067, "qh_buildcone: created %d newfacets for p%d(v%d) new facet balance %2.2g\n",
    numnew, qh_pointid(furthest), apex->id, newbalance));
  return apex;
} /* buildcone */

#ifndef qh_NOmerge
/*---------------------------------

  qh_buildcone_mergepinched( apex, facet, maxdupdist, &retryfacet )
    build cone of new facets from furthest to the horizon
    maxdupdist>0.0 for merging dupridges (qh_matchdupridge)

  returns:
    returns True if merged a pinched vertex and deleted the cone of new facets
      if retryfacet is set
        a dupridge was resolved by qh_merge_pinchedvertices
        retry qh_addpoint
      otherwise
        apex/furthest was partitioned as a coplanar point
        ignore this furthest point
    returns False if no dupridges or if dupridges will be resolved by MRGridge
    updates qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices

  notes:
    only called from qh_buildcone with qh.MERGEpinched

  design:
    match neighboring new facets
    if matching detected dupridges with a wide merge (qh_RATIOtrypinched)
      if pinched vertices (i.e., nearly adjacent)
        delete the cone of new facets
        delete the apex and reset the facet lists
        if coplanar, pinched apex
          partition the apex as a coplanar point
        else
           repeatedly merge the nearest pair of pinched vertices and subsequent facet merges
        return True
      otherwise
        MRGridge are better than vertex merge, but may report an error
    attach new facets
    make hyperplanes for point
    update vertex neighbors and delete interior vertices
*/
boolT qh_buildcone_mergepinched(vertexT *apex, facetT *facet, facetT **retryfacet) {
  facetT *newfacet, *nextfacet;
  pointT *apexpoint;
  coordT maxdupdist;
  int apexpointid;
  boolT iscoplanar;

  *retryfacet= NULL;
  maxdupdist= qh_matchnewfacets();
  if (maxdupdist > qh_RATIOtrypinched * qh ONEmerge) { /* one or more dupridges with a wide merge */
    if (qh IStracing >= 4 && qh num_facets < 1000)
      qh_printlists();
    qh_initmergesets(/* qh.facet_mergeset,degen_mergeset,vertex_mergeset */);
    if (qh_getpinchedmerges(apex, maxdupdist, &iscoplanar /* qh.newfacet_list, qh.vertex_mergeset */)) {
      for (newfacet=qh newfacet_list; newfacet && newfacet->next; newfacet= nextfacet) {
        nextfacet= newfacet->next;
        qh_delfacet(newfacet);
      }
      apexpoint= apex->point;
      apexpointid= qh_pointid(apexpoint);
      qh_delvertex(apex);
      qh_resetlists(False, qh_RESETvisible /* qh.visible_list newvertex_list qh.newfacet_list */);
      if (iscoplanar) {
        zinc_(Zpinchedapex);
        facet->notfurthest= True;
        qh_partitioncoplanar(apexpoint, facet, NULL, qh findbestnew);
      }else {
        qh_all_vertexmerges(apexpointid, facet, retryfacet);
      }
      qh_freemergesets(); /* errors if not empty */
      return True;
    }
    /* MRGridge are better than vertex merge, but may report an error */
    qh_freemergesets();
  }
  qh_attachnewfacets(/* qh.visible_list */);
  qh_makenewplanes(/* qh.newfacet_list */);
  qh_update_vertexneighbors_cone();
  return False;
} /* buildcone_mergepinched */
#endif /* !qh_NOmerge */

/*---------------------------------

  qh_buildcone_onlygood( apex, goodhorizon )
    build cone of good, new facets from apex and its qh.newfacet_list to the horizon
    goodhorizon is count of good, horizon facets from qh_find_horizon

  returns:
    False if a f.good facet or a qh.GOODclosest facet is not found
    updates qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices

  notes:
    called from qh_buildcone
    QH11030 FIX: Review effect of qh.GOODclosest on qh_buildcone_onlygood ('Qg').  qh_findgood preserves old value if didn't find a good facet.  See qh_findgood_all for disabling

  design:
    make hyperplanes for point
    if qh_findgood fails to find a f.good facet or a qh.GOODclosest facet
      delete cone of new facets
      return NULL (ignores apex)
    else
      attach cone to horizon
      match neighboring new facets
*/
boolT qh_buildcone_onlygood(vertexT *apex, int goodhorizon) {
  facetT *newfacet, *nextfacet;

  qh_makenewplanes(/* qh.newfacet_list */);
  if(qh_findgood(qh newfacet_list, goodhorizon) == 0) {
    if (!qh GOODclosest) {
      for (newfacet=qh newfacet_list; newfacet && newfacet->next; newfacet= nextfacet) {
        nextfacet= newfacet->next;
        qh_delfacet(newfacet);
      }
      qh_delvertex(apex);
      qh_resetlists(False /*no stats*/, qh_RESETvisible /* qh.visible_list newvertex_list qh.newfacet_list */);
      zinc_(Znotgoodnew);
      /* !good outside points dropped from hull */
      return False;
    }
  }
  qh_attachnewfacets(/* qh.visible_list */);
  qh_matchnewfacets(); /* ignore returned value.  qh_forcedmerges will merge dupridges if any */
  qh_update_vertexneighbors_cone();
  return True;
} /* buildcone_onlygood */

/*---------------------------------

  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 newfacet vertex flags and qh.STOPcone/STOPpoint
    for each facet with a furthest outside point
      add point to facet
      exit if qh.STOPcone or qh.STOPpoint requested
    if qh.NARROWhull for initial simplex
      partition remaining outside points to coplanar sets
*/
void qh_buildhull(void) {
  facetT *facet;
  pointT *furthest;
  vertexT *vertex;
  int id;

  trace1((qh ferr, 1037, "qh_buildhull: start build hull\n"));
  FORALLfacets {
    if (facet->visible || facet->newfacet) {
      qh_fprintf(qh ferr, 6165, "qhull internal error (qh_buildhull): visible or new facet f%d in facet list\n",
                   facet->id);
      qh_errexit(qh_ERRqhull, facet, NULL);
    }
  }
  FORALLvertices {
    if (vertex->newfacet) {
      qh_fprintf(qh ferr, 6166, "qhull internal error (qh_buildhull): new vertex f%d in vertex list\n",
                   vertex->id);
      qh_errprint("ERRONEOUS", NULL, NULL, NULL, vertex);
      qh_errexit(qh_ERRqhull, NULL, NULL);
    }
    id= qh_pointid(vertex->point);
    if ((qh STOPpoint>0 && id == qh STOPpoint-1) ||
        (qh STOPpoint<0 && id == -qh STOPpoint-1) ||
        (qh STOPcone>0 && id == qh STOPcone-1)) {
      trace1((qh ferr, 1038,"qh_buildhull: stop point or cone P%d in initial hull\n", id));
      return;
    }
  }
  qh facet_next= qh facet_list;      /* advance facet when processed */
  while ((furthest= qh_nextfurthest(&facet))) {
    qh num_outside--;  /* if ONLYmax, furthest may not be outside */
    if (qh STOPadd>0 && (qh num_vertices - qh hull_dim - 1 >= qh STOPadd - 1)) {
      trace1((qh ferr, 1059, "qh_buildhull: stop after adding %d vertices\n", qh STOPadd-1));
      return;
    }
    if (!qh_addpoint(furthest, facet, qh ONLYmax))
      break;
  }
  if (qh NARROWhull) /* move points from outsideset to coplanarset */
    qh_outcoplanar(/* facet_list */ );
  if (qh num_outside && !furthest) {
    qh_fprintf(qh ferr, 6167, "qhull internal error (qh_buildhull): %d outside points were never processed.\n", qh num_outside);
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  trace1((qh ferr, 1039, "qh_buildhull: completed the hull construction\n"));
} /* buildhull */


/*---------------------------------

  qh_buildtracing( furthest, facet )
    trace an iteration of qh_buildhull() for furthest point and facet
    if !furthest, prints progress message

  returns:
    tracks progress with qh.lastreport, lastcpu, lastfacets, lastmerges, lastplanes, lastdist
    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;
  double 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= (double)qh_CPUclock - (double)qh hulltime;
    cpu /= (double)qh_SECticks;
    total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
    qh_fprintf(qh ferr, 8118, "\n\
At %02d:%02d:%02d & %2.5g CPU secs, qhull has created %d facets and merged %d.\n\
 The current hull contains %d facets and %d vertices.  Last point was p%d\n",
      tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, qh facet_id -1,
      total, qh num_facets, qh num_vertices, qh furthest_id);
    return;
  }
  furthestid= qh_pointid(furthest);
#ifndef qh_NOtrace
  if (qh TRACEpoint == furthestid) {
    trace1((qh ferr, 1053, "qh_buildtracing: start trace T%d for point TP%d above facet f%d\n", qh TRACElevel, furthestid, facet->id));
    qh IStracing= qh TRACElevel;
    qhmem.IStracing= qh TRACElevel;
  }else if (qh TRACEpoint != qh_IDnone && qh TRACEdist < REALmax/2) {
    qh IStracing= 0;
    qhmem.IStracing= 0;
  }
#endif
  if (qh REPORTfreq && (qh facet_id-1 > qh lastreport + (unsigned int)qh REPORTfreq)) {
    qh lastreport= qh facet_id-1;
    time(&timedata);
    tp= localtime(&timedata);
    cpu= (double)qh_CPUclock - (double)qh hulltime;
    cpu /= (double)qh_SECticks;
    total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
    zinc_(Zdistio);
    qh_distplane(furthest, facet, &dist);
    qh_fprintf(qh ferr, 8119, "\n\
At %02d:%02d:%02d & %2.5g CPU secs, qhull has created %d facets and merged %d.\n\
 The current hull contains %d facets and %d vertices.  There are %d\n\
 outside points.  Next is point p%d(v%d), %2.2g above f%d.\n",
      tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, qh facet_id -1,
      total, qh num_facets, qh num_vertices, qh num_outside+1,
      furthestid, qh vertex_id, dist, getid_(facet));
  }else if (qh IStracing >=1) {
    cpu= (double)qh_CPUclock - (double)qh hulltime;
    cpu /= (double)qh_SECticks;
    qh_distplane(furthest, facet, &dist);
    qh_fprintf(qh ferr, 1049, "qh_addpoint: add p%d(v%d) %2.2g above f%d to hull of %d facets, %d merges, %d outside at %4.4g CPU secs.  Previous p%d(v%d) delta %4.4g CPU, %d facets, %d merges, %d hyperplanes, %d distplanes, %d retries\n",
      furthestid, qh vertex_id, dist, getid_(facet), qh num_facets, zzval_(Ztotmerge), qh num_outside+1, cpu, qh furthest_id, qh vertex_id - 1,
      cpu - qh lastcpu, qh num_facets - qh lastfacets,  zzval_(Ztotmerge) - qh lastmerges, zzval_(Zsetplane) - qh lastplanes, zzval_(Zdistplane) - qh lastdist, qh retry_addpoint);
    qh lastcpu= cpu;
    qh lastfacets= qh num_facets;
    qh lastmerges= zzval_(Ztotmerge);
    qh lastplanes= zzval_(Zsetplane);
    qh lastdist= zzval_(Zdistplane);
  }
  zmax_(Zvisit2max, (int)qh visit_id/2);
  if (qh visit_id > (unsigned int) INT_MAX) { /* 31 bits */
    zinc_(Zvisit);
    if (!qh_checklists(qh facet_list)) {
      qh_fprintf(qh ferr, 6370, "qhull internal error: qh_checklists failed on reset of qh.visit_id %u\n", qh visit_id);
      qh_errexit(qh_ERRqhull, NULL, NULL);
    }
    qh visit_id= 0;
    FORALLfacets
      facet->visitid= 0;
  }
  zmax_(Zvvisit2max, (int)qh vertex_visit/2);
  if (qh vertex_visit > (unsigned int) INT_MAX) { /* 31 bits */
    zinc_(Zvvisit);
    if (qh visit_id && !qh_checklists(qh facet_list)) {
      qh_fprintf(qh ferr, 6371, "qhull internal error: qh_checklists failed on reset of qh.vertex_visit %u\n", qh vertex_visit);
      qh_errexit(qh_ERRqhull, NULL, NULL);
    }
    qh vertex_visit= 0;
    FORALLvertices
      vertex->visitid= 0;
  }
  qh furthest_id= furthestid;
  qh RANDOMdist= qh old_randomdist;
} /* buildtracing */

/*---------------------------------

  qh_errexit2( exitcode, facet, otherfacet )
    return exitcode to system after an error
    report two facets

  returns:
    assumes exitcode non-zero

  see:
    normally use qh_errexit() in user.c(reports a facet and a ridge)
*/
void qh_errexit2(int exitcode, facetT *facet, facetT *otherfacet) {
  qh tracefacet= NULL;  /* avoid infinite recursion through qh_fprintf */
  qh traceridge= NULL;
  qh tracevertex= NULL;
  qh_errprint("ERRONEOUS", facet, otherfacet, NULL, NULL);
  qh_errexit(exitcode, NULL, NULL);
} /* errexit2 */


/*---------------------------------

  qh_findhorizon( point, facet, goodvisible, goodhorizon )
    given a visible facet, find the point's horizon and visible facets
    for all facets, !facet-visible

  returns:
    returns qh.visible_list/num_visible with all visible facets
      marks visible facets with ->visible
    updates count of good visible and good horizon facets
    updates qh.max_outside, qh.max_vertex, facet->maxoutside

  see:
    similar to qh_delpoint()

  design:
    move facet to qh.visible_list at end of qh.facet_list
    for all visible facets
     for each unvisited neighbor of a visible facet
       compute distance of point to neighbor
       if point above neighbor
         move neighbor to end of qh.visible_list
       else if point is coplanar with neighbor
         update qh.max_outside, qh.max_vertex, neighbor->maxoutside
         mark neighbor coplanar (will create a samecycle later)
         update horizon statistics
*/
void qh_findhorizon(pointT *point, facetT *facet, int *goodvisible, int *goodhorizon) {
  facetT *neighbor, **neighborp, *visible;
  int numhorizon= 0, coplanar= 0;
  realT dist;

  trace1((qh ferr, 1040, "qh_findhorizon: find horizon for point p%d facet f%d\n",qh_pointid(point),facet->id));
  *goodvisible= *goodhorizon= 0;
  zinc_(Ztotvisible);
  qh_removefacet(facet);  /* visible_list at end of qh facet_list */
  qh_appendfacet(facet);
  qh num_visible= 1;
  if (facet->good)
    (*goodvisible)++;
  qh visible_list= facet;
  facet->visible= True;
  facet->f.replace= NULL;
  if (qh IStracing >=4)
    qh_errprint("visible", facet, NULL, NULL, NULL);
  qh visit_id++;
  FORALLvisible_facets {
    if (visible->tricoplanar && !qh TRInormals) {
      qh_fprintf(qh ferr, 6230, "qhull internal error (qh_findhorizon): does not work for tricoplanar facets.  Use option 'Q11'\n");
      qh_errexit(qh_ERRqhull, visible, NULL);
    }
    if (qh_setsize(visible->neighbors) == 0) {
      qh_fprintf(qh ferr, 6295, "qhull internal error (qh_findhorizon): visible facet f%d does not have neighbors\n", visible->id);
      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->coplanarhorizon= True;
          zzinc_(Zcoplanarhorizon);
          qh_joggle_restart("coplanar horizon");
          coplanar++;
          if (qh MERGING) {
            if (dist > 0) {
              maximize_(qh max_outside, dist);
              maximize_(qh max_vertex, dist);
#if qh_MAXoutside
              maximize_(neighbor->maxoutside, dist);
#endif
            }else
              minimize_(qh min_vertex, dist);  /* due to merge later */
          }
          trace2((qh ferr, 2057, "qh_findhorizon: point p%d is coplanar to horizon f%d, dist=%2.7g < qh MINvisible(%2.7g)\n",
              qh_pointid(point), neighbor->id, dist, qh MINvisible));
        }else
          neighbor->coplanarhorizon= False;
        zinc_(Ztothorizon);
        numhorizon++;
        if (neighbor->good)
          (*goodhorizon)++;
        if (qh IStracing >=4)
          qh_errprint("horizon", neighbor, NULL, NULL, NULL);
      }
    }
  }
  if (!numhorizon) {
    qh_joggle_restart("empty horizon");
    qh_fprintf(qh ferr, 6168, "qhull topology error (qh_findhorizon): empty horizon for p%d.  It was above all facets.\n", qh_pointid(point));
    if (qh num_facets < 100) {
      qh_printfacetlist(qh facet_list, NULL, True);
    }
    qh_errexit(qh_ERRtopology, NULL, NULL);
  }
  trace1((qh ferr, 1041, "qh_findhorizon: %d horizon facets(good %d), %d visible(good %d), %d coplanar\n",
       numhorizon, *goodhorizon, qh num_visible, *goodvisible, coplanar));
  if (qh IStracing >= 4 && qh num_facets < 100)
    qh_printlists();
} /* findhorizon */

/*---------------------------------

  qh_joggle_restart( reason )
    if joggle ('QJn') and not merging, restart on precision and topology errors
*/
void qh_joggle_restart(const char *reason) {

  if (qh JOGGLEmax < REALmax/2) {
    if (qh ALLOWrestart && !qh PREmerge && !qh MERGEexact) {
      trace0((qh ferr, 26, "qh_joggle_restart: qhull restart because of %s\n", reason));
      /* May be called repeatedly if qh ALLOWrestart */
      longjmp(qh restartexit, qh_ERRprec);
    }
  }
} /* qh_joggle_restart */

/*---------------------------------

  qh_nextfurthest( visible )
    returns next furthest point and visible facet for qh_addpoint()
    starts search at qh.facet_next

  returns:
    removes furthest point from outside set
    NULL if none available
    advances qh.facet_next over facets with empty outside sets

  design:
    for each facet from qh.facet_next
      if empty outside set
        advance qh.facet_next
      else if qh.NARROWhull
        determine furthest outside point
        if furthest point is not outside
          advance qh.facet_next(point will be coplanar)
    remove furthest point from outside set
*/
pointT *qh_nextfurthest(facetT **visible) {
  facetT *facet;
  int size, idx, loopcount= 0;
  realT randr, dist;
  pointT *furthest;

  while ((facet= qh facet_next) != qh facet_tail) {
    if (!facet || loopcount++ > qh num_facets) {
      qh_fprintf(qh ferr, 6406, "qhull internal error (qh_nextfurthest): null facet or infinite loop detected for qh.facet_next f%d facet_tail f%d\n",
        getid_(facet), getid_(qh facet_tail));
      qh_printlists();
      qh_errexit2(qh_ERRqhull, facet, 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);
      randr= floor((qh num_outside - outcoplanar) * randr);
      idx= (int)randr;
      FORALLfacet_(qh facet_next) {
        if (facet->outsideset) {
          SETreturnsize_(facet->outsideset, size);
          if (!size)
            qh_setfree(&facet->outsideset);
          else if (size > idx) {
            *visible= facet;
            return ((pointT *)qh_setdelnth(facet->outsideset, idx));
          }else
            idx -= size;
        }
      }
      qh_fprintf(qh ferr, 6169, "qhull internal error (qh_nextfurthest): num_outside %d is too low\nby at least %d, or a random real %g >= 1.0\n",
              qh num_outside, idx+1, randr);
      qh_errexit(qh_ERRqhull, NULL, NULL);
    }else { /* VIRTUALmemory */
      facet= qh facet_tail->previous;
      if (!(furthest= (pointT *)qh_setdellast(facet->outsideset))) {
        if (facet->outsideset)
          qh_setfree(&facet->outsideset);
        qh_removefacet(facet);
        qh_prependfacet(facet, &qh facet_list);
        continue;
      }
      *visible= facet;
      return furthest;
    }
  }
  return NULL;
} /* nextfurthest */

/*---------------------------------

  qh_partitionall( vertices, points, numpoints )
    partitions all points in points/numpoints to the outsidesets of facets
    vertices= vertices in qh.facet_list(!partitioned)

  returns:
    builds facet->outsideset
    does not partition qh.GOODpoint
    if qh.ONLYgood && !qh.MERGING,
      does not partition qh.GOODvertex

  notes:
    faster if qh.facet_list sorted by anticipated size of outside set

  design:
    initialize pointset with all points
    remove vertices from pointset
    remove qh.GOODpointp from pointset (unless it's qh.STOPcone or qh.STOPpoint)
    for all facets
      for all remaining points in pointset
        compute distance from point to facet
        if point is outside facet
          remove point from pointset (by not reappending)
          update bestpoint
          append point or old bestpoint to facet's outside set
      append bestpoint to facet's outside set (furthest)
    for all points remaining in pointset
      partition point into facets' outside sets and coplanar sets
*/
void qh_partitionall(setT *vertices, pointT *points, int numpoints){
  setT *pointset;
  vertexT *vertex, **vertexp;
  pointT *point, **pointp, *bestpoint;
  int size, point_i, point_n, point_end, remaining, i, id;
  facetT *facet;
  realT bestdist= -REALmax, dist, distoutside;

  trace1((qh ferr, 1042, "qh_partitionall: partition all points into outside sets\n"));
  pointset= qh_settemp(numpoints);
  qh num_outside= 0;
  pointp= SETaddr_(pointset, pointT);
  for (i=numpoints, point= points; i--; point += qh hull_dim)
    *(pointp++)= point;
  qh_settruncate(pointset, numpoints);
  FOREACHvertex_(vertices) {
    if ((id= qh_pointid(vertex->point)) >= 0)
      SETelem_(pointset, id)= NULL;
  }
  id= qh_pointid(qh GOODpointp);
  if (id >=0 && qh STOPcone-1 != id && -qh STOPpoint-1 != id)
    SETelem_(pointset, id)= NULL;
  if (qh GOODvertexp && qh ONLYgood && !qh MERGING) { /* matches qhull()*/
    if ((id= qh_pointid(qh GOODvertexp)) >= 0)
      SETelem_(pointset, id)= NULL;
  }
  if (!qh BESToutside) {  /* matches conditional for qh_partitionpoint below */
    distoutside= qh_DISToutside; /* multiple of qh.MINoutside & qh.max_outside, see user.h */
    zval_(Ztotpartition)= qh num_points - qh hull_dim - 1; /*misses GOOD... */
    remaining= qh num_facets;
    point_end= numpoints;
    FORALLfacets {
      size= point_end/(remaining--) + 100;
      facet->outsideset= qh_setnew(size);
      bestpoint= NULL;
      point_end= 0;
      FOREACHpoint_i_(pointset) {
        if (point) {
          zzinc_(Zpartitionall);
          qh_distplane(point, facet, &dist);
          if (dist < distoutside)
            SETelem_(pointset, point_end++)= point;
          else {
            qh num_outside++;
            if (!bestpoint) {
              bestpoint= point;
              bestdist= dist;
            }else if (dist > bestdist) {
              qh_setappend(&facet->outsideset, bestpoint);
              bestpoint= point;
              bestdist= dist;
            }else
              qh_setappend(&facet->outsideset, point);
          }
        }
      }
      if (bestpoint) {
        qh_setappend(&facet->outsideset, bestpoint);
#if !qh_COMPUTEfurthest
        facet->furthestdist= bestdist;
#endif
      }else
        qh_setfree(&facet->outsideset);
      qh_settruncate(pointset, point_end);
    }
  }
  /* if !qh BESToutside, pointset contains points not assigned to outsideset */
  if (qh BESToutside || qh MERGING || qh KEEPcoplanar || qh KEEPinside || qh KEEPnearinside) {
    qh findbestnew= True;
    FOREACHpoint_i_(pointset) {
      if (point)
        qh_partitionpoint(point, qh facet_list);
    }
    qh findbestnew= False;
  }
  zzadd_(Zpartitionall, zzval_(Zpartition));
  zzval_(Zpartition)= 0;
  qh_settempfree(&pointset);
  if (qh IStracing >= 4)
    qh_printfacetlist(qh facet_list, NULL, True);
} /* partitionall */


/*---------------------------------

  qh_partitioncoplanar( point, facet, dist, allnew )
    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 allnew (qh.findbestnew)
      searches new facets instead of using qh_findbest()

  returns:
    qh.max_ouside updated
    if qh.KEEPcoplanar or qh.KEEPinside
      point assigned to best coplanarset
    qh.repart_facetid==0 (for detecting infinite recursion via qh_partitionpoint)

  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, boolT allnew) {
  facetT *bestfacet;
  pointT *oldfurthest;
  realT bestdist, angle, nearest, dist2= 0.0;
  int numpart= 0;
  boolT isoutside, oldfindbest, repartition= False;

  trace4((qh ferr, 4090, "qh_partitioncoplanar: partition coplanar point p%d starting with f%d dist? %2.2g, allnew? %d, gh.repart_facetid f%d\n",
    qh_pointid(point), facet->id, (dist ? *dist : 0.0), allnew, qh repart_facetid));
  qh WAScoplanar= True;
  if (!dist) {
    if (allnew)
      bestfacet= qh_findbestnew(point, facet, &bestdist, qh_ALL, &isoutside, &numpart);
    else
      bestfacet= qh_findbest(point, facet, qh_ALL, !qh_ISnewfacets, qh DELAUNAY,
                          &bestdist, &isoutside, &numpart);
    zinc_(Ztotpartcoplanar);
    zzadd_(Zpartcoplanar, numpart);
    if (!qh DELAUNAY && !qh KEEPinside) { /*  for 'd', bestdist skips upperDelaunay facets */
      if (qh KEEPnearinside) {
        if (bestdist < -qh NEARinside) {
          zinc_(Zcoplanarinside);
          trace4((qh ferr, 4062, "qh_partitioncoplanar: point p%d is more than near-inside facet f%d dist %2.2g allnew? %d\n",
                  qh_pointid(point), bestfacet->id, bestdist, allnew));
          qh repart_facetid= 0;
          return;
        }
      }else if (bestdist < -qh MAXcoplanar) {
          trace4((qh ferr, 4063, "qh_partitioncoplanar: point p%d is inside facet f%d dist %2.2g allnew? %d\n",
                  qh_pointid(point), bestfacet->id, bestdist, allnew));
        zinc_(Zcoplanarinside);
        qh repart_facetid= 0;
        return;
      }
    }
  }else {
    bestfacet= facet;
    bestdist= *dist;
  }
  if(bestfacet->visible){
    qh_fprintf(qh ferr, 6405, "qhull internal error (qh_partitioncoplanar): cannot partition coplanar p%d of f%d into visible facet f%d\n",
        qh_pointid(point), facet->id, bestfacet->id);
    qh_errexit2(qh_ERRqhull, facet, bestfacet);
  }
  if (bestdist > qh max_outside) {
    if (!dist && facet != bestfacet) { /* can't be recursive from qh_partitionpoint since facet != bestfacet */
      zinc_(Zpartangle);
      angle= qh_getangle(facet->normal, bestfacet->normal);
      if (angle < 0) {
        nearest= qh_vertex_bestdist(bestfacet->vertices);
        /* typically due to deleted vertex and coplanar facets, e.g.,
        RBOX 1000 s Z1 G1e-13 t1001185205 | QHULL Tv */
        zinc_(Zpartcorner);
        trace2((qh ferr, 2058, "qh_partitioncoplanar: repartition coplanar point p%d from f%d as an outside point above corner facet f%d dist %2.2g with angle %2.2g\n",
          qh_pointid(point), facet->id, bestfacet->id, bestdist, angle));
        repartition= True;
      }
    }
    if (!repartition) {
      if (bestdist > qh MAXoutside * qh_RATIOcoplanaroutside) {
        nearest= qh_vertex_bestdist(bestfacet->vertices);
        if (facet->id == bestfacet->id) {
          if (facet->id == qh repart_facetid) {
            qh_fprintf(qh ferr, 6404, "Qhull internal error (qh_partitioncoplanar): infinite loop due to recursive call to qh_partitionpoint.  Repartition point p%d from f%d as a outside point dist %2.2g nearest vertices %2.2g\n",
              qh_pointid(point), facet->id, bestdist, nearest);
            qh_errexit(qh_ERRqhull, facet, NULL);
          }
          qh repart_facetid= facet->id; /* reset after call to qh_partitionpoint */
        }
        if (point == qh coplanar_apex) {
          /* otherwise may loop indefinitely, the point is well above a facet, yet near a vertex */
          qh_fprintf(qh ferr, 6425, "Qhull topology error (qh_partitioncoplanar): can not repartition coplanar point p%d from f%d as outside point above f%d.  It previously failed to form a cone of facets, dist %2.2g, nearest vertices %2.2g\n",
            qh_pointid(point), facet->id, bestfacet->id, bestdist, nearest);
          qh_errexit(qh_ERRtopology, facet, NULL);
        }
        if (nearest < 2 * qh MAXoutside * qh_RATIOcoplanaroutside) {
          zinc_(Zparttwisted);
          qh_fprintf(qh ferr, 7085, "Qhull precision warning: repartition coplanar point p%d from f%d as an outside point above twisted facet f%d dist %2.2g nearest vertices %2.2g\n",
            qh_pointid(point), facet->id, bestfacet->id, bestdist, nearest);
        }else {
          zinc_(Zparthidden);
          qh_fprintf(qh ferr, 7086, "Qhull precision warning: repartition coplanar point p%d from f%d as an outside point above hidden facet f%d dist %2.2g nearest vertices %2.2g\n",
            qh_pointid(point), facet->id, bestfacet->id, bestdist, nearest);
        }
        repartition= True;
      }
    }
    if (repartition) {
      oldfindbest= qh findbestnew;
      qh findbestnew= False;
      qh_partitionpoint(point, bestfacet);
      qh findbestnew= oldfindbest;
      qh repart_facetid= 0;
      return;
    }
    qh repart_facetid= 0;
    qh max_outside= bestdist;
    if (bestdist > qh TRACEdist || qh IStracing >= 3) {
      qh_fprintf(qh ferr, 3041, "qh_partitioncoplanar: == p%d from f%d increases qh.max_outside to %2.2g of f%d last p%d\n",
                     qh_pointid(point), facet->id, bestdist, bestfacet->id, qh furthest_id);
      qh_errprint("DISTANT", facet, bestfacet, NULL, NULL);
    }
  }
  if (qh KEEPcoplanar + qh KEEPinside + qh KEEPnearinside) {
    oldfurthest= (pointT *)qh_setlast(bestfacet->coplanarset);
    if (oldfurthest) {
      zinc_(Zcomputefurthest);
      qh_distplane(oldfurthest, bestfacet, &dist2);
    }
    if (!oldfurthest || dist2 < bestdist)
      qh_setappend(&bestfacet->coplanarset, point);
    else
      qh_setappend2ndlast(&bestfacet->coplanarset, point);
  }
  trace4((qh ferr, 4064, "qh_partitioncoplanar: point p%d is coplanar with facet f%d (or inside) dist %2.2g\n",
          qh_pointid(point), bestfacet->id, bestdist));
} /* partitioncoplanar */

/*---------------------------------

  qh_partitionpoint( point, facet )
    assigns point to an outside set, coplanar set, or inside set (i.e., dropt)
    if qh.findbestnew
      uses qh_findbestnew() to search all new facets
    else
      uses qh_findbest()

  notes:
    after qh_distplane(), this and qh_findbest() are most expensive in 3-d

  design:
    find best facet for point
      (either exhaustive search of new facets or directed search from facet)
    if qh.NARROWhull
      retain coplanar and nearinside points as outside points
    if point is outside bestfacet
      if point above furthest point for bestfacet
        append point to outside set (it becomes the new furthest)
        if outside set was empty
          move bestfacet to end of qh.facet_list (i.e., after qh.facet_next)
        update bestfacet->furthestdist
      else
        append point one before end of outside set
    else if point is coplanar to bestfacet
      if keeping coplanar points or need to update qh.max_outside
        partition coplanar point into bestfacet
    else if near-inside point
      partition as coplanar point into bestfacet
    else is an inside point
      if keeping inside points
        partition as coplanar point into bestfacet
*/
void qh_partitionpoint(pointT *point, facetT *facet) {
  realT bestdist, previousdist;
  boolT isoutside, isnewoutside= False;
  facetT *bestfacet;
  int numpart;

  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(bestfacet->visible){
    qh_fprintf(qh ferr, 6293, "qhull internal error (qh_partitionpoint): cannot partition p%d of f%d into visible facet f%d\n",
      qh_pointid(point), facet->id, bestfacet->id);
    qh_errexit2(qh_ERRqhull, facet, bestfacet);
  }
  if (qh NARROWhull) {
    if (qh DELAUNAY && !isoutside && bestdist >= -qh MAXcoplanar)
      qh_joggle_restart("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)) { /* empty outside set */
      qh_setappend(&(bestfacet->outsideset), point);
      if (!qh NARROWhull || bestdist > qh MINoutside)
        isnewoutside= True;
#if !qh_COMPUTEfurthest
      bestfacet->furthestdist= bestdist;
#endif
    }else {
#if qh_COMPUTEfurthest
      zinc_(Zcomputefurthest);
      qh_distplane(oldfurthest, bestfacet, &previousdist);
      if (previousdist < bestdist)
        qh_setappend(&(bestfacet->outsideset), point);
      else
        qh_setappend2ndlast(&(bestfacet->outsideset), point);
#else
      previousdist= bestfacet->furthestdist;
      if (previousdist < bestdist) {
        qh_setappend(&(bestfacet->outsideset), point);
        bestfacet->furthestdist= bestdist;
        if (qh NARROWhull && previousdist < qh MINoutside && bestdist >= qh MINoutside)
          isnewoutside= True;
      }else
        qh_setappend2ndlast(&(bestfacet->outsideset), point);
#endif
    }
    if (isnewoutside && qh facet_next != bestfacet) {
      if (bestfacet->newfacet) {
        if (qh facet_next->newfacet)
          qh facet_next= qh newfacet_list; /* make sure it's after qh.facet_next */
      }else {
        qh_removefacet(bestfacet);  /* make sure it's after qh.facet_next */
        qh_appendfacet(bestfacet);
        if(qh newfacet_list){
          bestfacet->newfacet= True;
        }
      }
    }
    qh num_outside++;
    trace4((qh ferr, 4065, "qh_partitionpoint: point p%d is outside facet f%d newfacet? %d, newoutside? %d (or narrowhull)\n",
          qh_pointid(point), bestfacet->id, bestfacet->newfacet, isnewoutside));
  }else if (qh DELAUNAY || bestdist >= -qh MAXcoplanar) { /* for 'd', bestdist skips upperDelaunay facets */
    if (qh DELAUNAY)
      qh_joggle_restart("nearly incident point");
    /* allow coplanar points with joggle, may be interior */
    zzinc_(Zcoplanarpart);
    if ((qh KEEPcoplanar + qh KEEPnearinside) || bestdist > qh max_outside)
      qh_partitioncoplanar(point, bestfacet, &bestdist, qh findbestnew);
    else {
      trace4((qh ferr, 4066, "qh_partitionpoint: point p%d is coplanar to facet f%d (dropped)\n",
          qh_pointid(point), bestfacet->id));
    }
  }else if (qh KEEPnearinside && bestdist >= -qh NEARinside) {
    zinc_(Zpartnear);
    qh_partitioncoplanar(point, bestfacet, &bestdist, qh findbestnew);
  }else {
    zinc_(Zpartinside);
    trace4((qh ferr, 4067, "qh_partitionpoint: point p%d is inside all facets, closest to f%d dist %2.2g\n",
          qh_pointid(point), bestfacet->id, bestdist));
    if (qh KEEPinside)
      qh_partitioncoplanar(point, bestfacet, &bestdist, qh findbestnew);
  }
} /* partitionpoint */

/*---------------------------------

  qh_partitionvisible( allpoints, numoutside )
    partitions outside points in visible facets (qh.visible_list) to qh.newfacet_list
    if keeping coplanar/near-inside/inside points
      partitions coplanar points; repartitions if 'allpoints' (not used)
    1st neighbor (if any) of visible facets points to a horizon facet or a new facet

  returns:
    updates outside sets and coplanar sets of qh.newfacet_list
    updates qh.num_outside (count of outside points)
    does not truncate f.outsideset, f.coplanarset, or qh.del_vertices (see qh_deletevisible)

  notes:
    called by qh_qhull, qh_addpoint, and qh_all_vertexmerges
    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(boolT allpoints, int *numoutside /* qh.visible_list */) {
  facetT *visible, *newfacet;
  pointT *point, **pointp;
  int delsize, coplanar=0, size;
  vertexT *vertex, **vertexp;

  trace3((qh ferr, 3042, "qh_partitionvisible: partition outside and coplanar points of visible and merged facets f%d into new facets f%d\n",
    qh visible_list->id, qh newfacet_list->id));
  if (qh ONLYmax)
    maximize_(qh MINoutside, qh max_vertex);
  *numoutside= 0;
  FORALLvisible_facets {
    if (!visible->outsideset && !visible->coplanarset)
      continue;
    newfacet= qh_getreplacement(visible);
    if (!newfacet)
      newfacet= qh newfacet_list;
    if (!newfacet->next) {
      qh_fprintf(qh ferr, 6170, "qhull topology error (qh_partitionvisible): all new facets deleted as\n       degenerate facets. Can not continue.\n");
      qh_errexit(qh_ERRtopology, 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, qh findbestnew);
      }
    }
  }
  delsize= qh_setsize(qh del_vertices);
  if (delsize > 0) {
    trace3((qh ferr, 3049, "qh_partitionvisible: partition %d deleted vertices as coplanar? %d points into new facets f%d\n",
      delsize, !allpoints, qh newfacet_list->id));
    FOREACHvertex_(qh del_vertices) {
      if (vertex->point && !vertex->partitioned) {
        if (!qh newfacet_list || qh newfacet_list == qh facet_tail) {
          qh_fprintf(qh ferr, 6284, "qhull internal error (qh_partitionvisible): all new facets deleted or none defined.  Can not partition deleted v%d.\n", vertex->id);
          qh_errexit(qh_ERRqhull, NULL, NULL);
        }
        if (allpoints) /* not used */
          /* [apr'2019] infinite loop if vertex recreates the same facets from the same horizon
             e.g., qh_partitionpoint if qh.DELAUNAY with qh.MERGEindependent for all mergetype, ../eg/qtest.sh t427764 '1000 s W1e-13 D3' 'd' */
          qh_partitionpoint(vertex->point, qh newfacet_list);
        else
          qh_partitioncoplanar(vertex->point, qh newfacet_list, NULL, qh_ALL); /* search all new facets */
        vertex->partitioned= True;
      }
    }
  }
  trace1((qh ferr, 1043,"qh_partitionvisible: partitioned %d points from outsidesets, %d points from coplanarsets, and %d deleted vertices\n", *numoutside, coplanar, delsize));
} /* partitionvisible */

/*---------------------------------

  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
    updates qh.facet_visit to detect infinite loop

  design:
    determine number of points, vertices, and coplanar points
    print summary
*/
void qh_printsummary(FILE *fp) {
  realT ratio, outerplane, innerplane;
  double cpu;
  int size, id, nummerged, numpinched, numvertices, numcoplanars= 0, nonsimplicial=0, numdelaunay= 0;
  facetT *facet;
  const char *s;
  int numdel= zzval_(Zdelvertextot);
  int numtricoplanars= 0;
  boolT goodused;

  size= qh num_points + qh_setsize(qh other_points);
  numvertices= qh num_vertices - qh_setsize(qh del_vertices);
  id= qh_pointid(qh GOODpointp);
  if (!qh_checklists(qh facet_list) && !qh ERREXITcalled) {
    qh_fprintf(fp, 6372, "qhull internal error: qh_checklists failed at qh_printsummary\n");
    if (qh num_facets < 4000)
      qh_printlists();
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  if (qh DELAUNAY && qh ERREXITcalled) {
    /* update f.good and determine qh.num_good as in qh_findgood_all */
    FORALLfacets {
      if (facet->visible)
        facet->good= False; /* will be deleted */
      else if (facet->good) {
        if (facet->normal && !qh_inthresholds(facet->normal, NULL))
          facet->good= False;
        else
          numdelaunay++;
      }
    }
    qh num_good= numdelaunay;
  }
  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 STOPadd || qh STOPcone || qh STOPpoint)
    qh_fprintf(fp, 9288, "\nEarly exit due to 'TAn', 'TVn', 'TCn', 'TRn', or precision error with 'QJn'.");
  goodused= False;
  if (qh ERREXITcalled)
    ; /* qh_findgood_all not called */
  else if (qh UPPERdelaunay) {
    if (qh GOODvertex || qh GOODpoint || qh SPLITthresholds)
      goodused= True;
  }else if (qh DELAUNAY) {
    if (qh GOODvertex || qh GOODpoint || qh GOODthreshold)
      goodused= True;
  }else if (qh num_good > 0 || qh GOODthreshold)
    goodused= True;
  nummerged= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
  if (qh VORONOI) {
    if (qh UPPERdelaunay)
      qh_fprintf(fp, 9289, "\n\
Furthest-site Voronoi vertices by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
    else
      qh_fprintf(fp, 9290, "\n\
Voronoi diagram by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
    qh_fprintf(fp, 9291, "  Number of Voronoi regions%s: %d\n",
              qh ATinfinity ? " and at-infinity" : "", numvertices);
    if (numdel)
      qh_fprintf(fp, 9292, "  Total number of deleted points due to merging: %d\n", numdel);
    if (numcoplanars - numdel > 0)
      qh_fprintf(fp, 9293, "  Number of nearly incident points: %d\n", numcoplanars - numdel);
    else if (size - numvertices - numdel > 0)
      qh_fprintf(fp, 9294, "  Total number of nearly incident points: %d\n", size - numvertices - numdel);
    qh_fprintf(fp, 9295, "  Number of%s Voronoi vertices: %d\n",
              goodused ? " 'good'" : "", qh num_good);
    if (nonsimplicial)
      qh_fprintf(fp, 9296, "  Number of%s non-simplicial Voronoi vertices: %d\n",
              goodused ? " 'good'" : "", nonsimplicial);
  }else if (qh DELAUNAY) {
    if (qh UPPERdelaunay)
      qh_fprintf(fp, 9297, "\n\
Furthest-site Delaunay triangulation by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
    else
      qh_fprintf(fp, 9298, "\n\
Delaunay triangulation by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
    qh_fprintf(fp, 9299, "  Number of input sites%s: %d\n",
              qh ATinfinity ? " and at-infinity" : "", numvertices);
    if (numdel)
      qh_fprintf(fp, 9300, "  Total number of deleted points due to merging: %d\n", numdel);
    if (numcoplanars - numdel > 0)
      qh_fprintf(fp, 9301, "  Number of nearly incident points: %d\n", numcoplanars - numdel);
    else if (size - numvertices - numdel > 0)
      qh_fprintf(fp, 9302, "  Total number of nearly incident points: %d\n", size - numvertices - numdel);
    qh_fprintf(fp, 9303, "  Number of%s Delaunay regions: %d\n",
              goodused ? " 'good'" : "", qh num_good);
    if (nonsimplicial)
      qh_fprintf(fp, 9304, "  Number of%s non-simplicial Delaunay regions: %d\n",
              goodused ? " 'good'" : "", nonsimplicial);
  }else if (qh HALFspace) {
    qh_fprintf(fp, 9305, "\n\
Halfspace intersection by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
    qh_fprintf(fp, 9306, "  Number of halfspaces: %d\n", size);
    qh_fprintf(fp, 9307, "  Number of non-redundant halfspaces: %d\n", numvertices);
    if (numcoplanars) {
      if (qh KEEPinside && qh KEEPcoplanar)
        s= "similar and redundant";
      else if (qh KEEPinside)
        s= "redundant";
      else
        s= "similar";
      qh_fprintf(fp, 9308, "  Number of %s halfspaces: %d\n", s, numcoplanars);
    }
    qh_fprintf(fp, 9309, "  Number of intersection points: %d\n", qh num_facets - qh num_visible);
    if (goodused)
      qh_fprintf(fp, 9310, "  Number of 'good' intersection points: %d\n", qh num_good);
    if (nonsimplicial)
      qh_fprintf(fp, 9311, "  Number of%s non-simplicial intersection points: %d\n",
              goodused ? " 'good'" : "", nonsimplicial);
  }else {
    qh_fprintf(fp, 9312, "\n\
Convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
    qh_fprintf(fp, 9313, "  Number of vertices: %d\n", numvertices);
    if (numcoplanars) {
      if (qh KEEPinside && qh KEEPcoplanar)
        s= "coplanar and interior";
      else if (qh KEEPinside)
        s= "interior";
      else
        s= "coplanar";
      qh_fprintf(fp, 9314, "  Number of %s points: %d\n", s, numcoplanars);
    }
    qh_fprintf(fp, 9315, "  Number of facets: %d\n", qh num_facets - qh num_visible);
    if (goodused)
      qh_fprintf(fp, 9316, "  Number of 'good' facets: %d\n", qh num_good);
    if (nonsimplicial)
      qh_fprintf(fp, 9317, "  Number of%s non-simplicial facets: %d\n",
              goodused ? " 'good'" : "", nonsimplicial);
  }
  if (numtricoplanars)
      qh_fprintf(fp, 9318, "  Number of triangulated facets: %d\n", numtricoplanars);
  qh_fprintf(fp, 9319, "\nStatistics for: %s | %s",
                      qh rbox_command, qh qhull_command);
  if (qh ROTATErandom != INT_MIN)
    qh_fprintf(fp, 9320, " QR%d\n\n", qh ROTATErandom);
  else
    qh_fprintf(fp, 9321, "\n\n");
  qh_fprintf(fp, 9322, "  Number of points processed: %d\n", zzval_(Zprocessed));
  qh_fprintf(fp, 9323, "  Number of hyperplanes created: %d\n", zzval_(Zsetplane));
  if (qh DELAUNAY)
    qh_fprintf(fp, 9324, "  Number of facets in hull: %d\n", qh num_facets - qh num_visible);
  qh_fprintf(fp, 9325, "  Number of distance tests for qhull: %d\n", zzval_(Zpartition)+
      zzval_(Zpartitionall)+zzval_(Znumvisibility)+zzval_(Zpartcoplanar));
#if 0  /* NOTE: must print before printstatistics() */
  {realT stddev, ave;
  qh_fprintf(fp, 9326, "  average new facet balance: %2.2g\n",
          wval_(Wnewbalance)/zval_(Zprocessed));
  stddev= qh_stddev(zval_(Zprocessed), wval_(Wnewbalance),
                                 wval_(Wnewbalance2), &ave);
  qh_fprintf(fp, 9327, "  new facet standard deviation: %2.2g\n", stddev);
  qh_fprintf(fp, 9328, "  average partition balance: %2.2g\n",
          wval_(Wpbalance)/zval_(Zpbalance));
  stddev= qh_stddev(zval_(Zpbalance), wval_(Wpbalance),
                                 wval_(Wpbalance2), &ave);
  qh_fprintf(fp, 9329, "  partition standard deviation: %2.2g\n", stddev);
  }
#endif
  if (nummerged) {
    qh_fprintf(fp, 9330,"  Number of distance tests for merging: %d\n",zzval_(Zbestdist)+
          zzval_(Zcentrumtests)+zzval_(Zvertextests)+zzval_(Zdistcheck)+zzval_(Zdistzero));
    qh_fprintf(fp, 9331,"  Number of distance tests for checking: %d\n",zzval_(Zcheckpart)+zzval_(Zdistconvex));
    qh_fprintf(fp, 9332,"  Number of merged facets: %d\n", nummerged);
  }
  numpinched= zzval_(Zpinchduplicate) + zzval_(Zpinchedvertex);
  if (numpinched)
    qh_fprintf(fp, 9375,"  Number of merged pinched vertices: %d\n", numpinched);
  if (!qh RANDOMoutside && qh QHULLfinished) {
    cpu= (double)qh hulltime;
    cpu /= (double)qh_SECticks;
    wval_(Wcpu)= cpu;
    qh_fprintf(fp, 9333, "  CPU seconds to compute hull (after input): %2.4g\n", cpu);
  }
  if (qh RERUN) {
    if (!qh PREmerge && !qh MERGEexact)
      qh_fprintf(fp, 9334, "  Percentage of runs with precision errors: %4.1f\n",
           zzval_(Zretry)*100.0/qh build_cnt);  /* careful of order */
  }else if (qh JOGGLEmax < REALmax/2) {
    if (zzval_(Zretry))
      qh_fprintf(fp, 9335, "  After %d retries, input joggled by: %2.2g\n",
         zzval_(Zretry), qh JOGGLEmax);
    else
      qh_fprintf(fp, 9336, "  Input joggled by: %2.2g\n", qh JOGGLEmax);
  }
  if (qh totarea != 0.0)
    qh_fprintf(fp, 9337, "  %s facet area:   %2.8g\n",
            zzval_(Ztotmerge) ? "Approximate" : "Total", qh totarea);
  if (qh totvol != 0.0)
    qh_fprintf(fp, 9338, "  %s volume:       %2.8g\n",
            zzval_(Ztotmerge) ? "Approximate" : "Total", qh totvol);
  if (qh MERGING) {
    qh_outerinner(NULL, &outerplane, &innerplane);
    if (outerplane > 2 * qh DISTround) {
      qh_fprintf(fp, 9339, "  Maximum distance of point above facet: %2.2g", outerplane);
      ratio= outerplane/(qh ONEmerge + qh DISTround);
      /* don't report ratio if MINoutside is large */
      if (ratio > 0.05 && 2* qh ONEmerge > qh MINoutside && qh JOGGLEmax > REALmax/2)
        qh_fprintf(fp, 9340, " (%.1fx)\n", ratio);
      else
        qh_fprintf(fp, 9341, "\n");
    }
    if (innerplane < -2 * qh DISTround) {
      qh_fprintf(fp, 9342, "  Maximum distance of vertex below facet: %2.2g", innerplane);
      ratio= -innerplane/(qh ONEmerge+qh DISTround);
      if (ratio > 0.05 && qh JOGGLEmax > REALmax/2)
        qh_fprintf(fp, 9343, " (%.1fx)\n", ratio);
      else
        qh_fprintf(fp, 9344, "\n");
    }
  }
  qh_fprintf(fp, 9345, "\n");
} /* printsummary */


qhull-2020.2/src/libqhull/libqhull.h0000644060175106010010000016502213662355222015572 0ustar  bbarber/*
  ---------------------------------

   libqhull.h
   user-level header file for using qhull.a library

   see qh-qhull.htm, qhull_a.h

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull/libqhull.h#11 $$Change: 2958 $
   $DateTime: 2020/05/26 16:17:49 $$Author: bbarber $

   NOTE: access to qh_qh is via the 'qh' macro.  This allows
   qh_qh to be either a pointer or a structure.  An example
   of using qh is "qh.DROPdim" which accesses the DROPdim
   field of qh_qh.  Similarly, access to qh_qhstat is via
   the 'qhstat' macro.

   includes function prototypes for libqhull.c, geom.c, global.c, io.c, user.c

   use mem.h for mem.c
   use qset.h for qset.c

   see unix.c for an example of using libqhull.h

   recompile qhull if you change this file
*/

#ifndef qhDEFlibqhull
#define qhDEFlibqhull 1

/*=========================== -included files ==============*/

/* user.h first for QHULL_CRTDBG */
#include "user.h"      /* user definable constants (e.g., realT). */

#include "mem.h"   /* Needed for qhT in libqhull_r.h.  Here for compatibility */
#include "qset.h"   /* Needed for QHULL_LIB_CHECK */
/* include stat.h after defining boolT.  Needed for qhT in libqhull_r.h.  Here for compatibility */

#include 
#include 
#include 
#include 
#include 

#if defined(__MWERKS__) && defined(__POWERPC__)
#include  
#include  
#include        
#endif

#ifndef __STDC__
#ifndef __cplusplus
#if     !defined(_MSC_VER)
#error  Neither __STDC__ nor __cplusplus is defined.  Please use strict ANSI C or C++ to compile
#error  Qhull.  You may need to turn off compiler extensions in your project configuration.  If
#error  your compiler is a standard C compiler, you can delete this warning from libqhull.h
#endif
#endif
#endif

/*============ constants and basic types ====================*/

extern const char qh_version[]; /* defined in global.c */
extern const char qh_version2[]; /* defined in global.c */

/*----------------------------------

  coordT
    coordinates and coefficients are stored as realT (i.e., double)

  notes:
    Qhull works well if realT is 'float'.  If so joggle (QJ) is not effective.

    Could use 'float' for data and 'double' for calculations (realT vs. coordT)
      This requires many type casts, and adjusted error bounds.
      Also C compilers may do expressions in double anyway.
*/
#define coordT realT

/*----------------------------------

  pointT
    a point is an array of coordinates, usually qh.hull_dim
    qh_pointid returns
      qh_IDnone if point==0 or qh is undefined
      qh_IDinterior for qh.interior_point
      qh_IDunknown if point is neither in qh.first_point... nor qh.other_points

  notes:
    qh.STOPcone and qh.STOPpoint assume that qh_IDunknown==-1 (other negative numbers indicate points)
    qh_IDunknown is also returned by getid_() for unknown facet, ridge, or vertex
*/
#define pointT coordT
typedef enum
{
    qh_IDnone= -3, qh_IDinterior= -2, qh_IDunknown= -1
}
qh_pointT;

/*----------------------------------

  flagT
    Boolean flag as a bit
*/
#define flagT unsigned int

/*----------------------------------

  boolT
    boolean value, either True or False

  notes:
    needed for portability
    Use qh_False/qh_True as synonyms
*/
#define boolT unsigned int
#ifdef False
#undef False
#endif
#ifdef True
#undef True
#endif
#define False 0
#define True 1
#define qh_False 0
#define qh_True 1

#include "stat.h"  /* needs boolT */

/*----------------------------------

  qh_CENTER
    to distinguish facet->center
*/
typedef enum
{
    qh_ASnone= 0,    /* If not MERGING and not VORONOI */
    qh_ASvoronoi,    /* Set by qh_clearcenters on qh_prepare_output, or if not MERGING and VORONOI */
    qh_AScentrum     /* If MERGING (assumed during merging) */
}
qh_CENTER;

/*----------------------------------

  qh_PRINT
    output formats for printing (qh.PRINTout).
    'Fa' 'FV' 'Fc' 'FC'


   notes:
   some of these names are similar to qhT names.  The similar names are only
   used in switch statements in qh_printbegin() etc.
*/
typedef enum {qh_PRINTnone= 0,
  qh_PRINTarea, qh_PRINTaverage,           /* 'Fa' 'FV' 'Fc' 'FC' */
  qh_PRINTcoplanars, qh_PRINTcentrums,
  qh_PRINTfacets, qh_PRINTfacets_xridge,   /* 'f' 'FF' 'G' 'FI' 'Fi' 'Fn' */
  qh_PRINTgeom, qh_PRINTids, qh_PRINTinner, qh_PRINTneighbors,
  qh_PRINTnormals, qh_PRINTouter, qh_PRINTmaple, /* 'n' 'Fo' 'i' 'm' 'Fm' 'FM', 'o' */
  qh_PRINTincidences, qh_PRINTmathematica, qh_PRINTmerges, qh_PRINToff,
  qh_PRINToptions, qh_PRINTpointintersect, /* 'FO' 'Fp' 'FP' 'p' 'FQ' 'FS' */
  qh_PRINTpointnearest, qh_PRINTpoints, qh_PRINTqhull, qh_PRINTsize,
  qh_PRINTsummary, qh_PRINTtriangles,      /* 'Fs' 'Ft' 'Fv' 'FN' 'Fx' */
  qh_PRINTvertices, qh_PRINTvneighbors, qh_PRINTextremes,
  qh_PRINTEND} qh_PRINT;

/*----------------------------------

  qh_ALL
    argument flag for selecting everything
*/
#define qh_ALL      True
#define qh_NOupper  True      /* argument for qh_findbest */
#define qh_IScheckmax  True   /* argument for qh_findbesthorizon */
#define qh_ISnewfacets  True  /* argument for qh_findbest */
#define qh_RESETvisible  True /* argument for qh_resetlists */

/*----------------------------------

  qh_ERR...
    Qhull exit status codes, for indicating errors
    See: MSG_ERROR (6000) and MSG_WARNING (7000) [user.h]
*/
#define qh_ERRnone  0    /* no error occurred during qhull */
#define qh_ERRinput 1    /* input inconsistency */
#define qh_ERRsingular 2 /* singular input data, calls qh_printhelp_singular */
#define qh_ERRprec  3    /* precision error, calls qh_printhelp_degenerate */
#define qh_ERRmem   4    /* insufficient memory, matches mem.h */
#define qh_ERRqhull 5    /* internal error detected, matches mem.h, calls qh_printhelp_internal */
#define qh_ERRother 6    /* other error detected */
#define qh_ERRtopology 7 /* topology error, maybe due to nearly adjacent vertices, calls qh_printhelp_topology */
#define qh_ERRwide 8     /* wide facet error, maybe due to nearly adjacent vertices, calls qh_printhelp_wide */
#define qh_ERRdebug 9    /* qh_errexit from debugging code */

/*----------------------------------

qh_FILEstderr
Fake stderr to distinguish error output from normal output
For C++ interface.  Must redefine qh_fprintf_qhull
*/
#define qh_FILEstderr ((FILE *)1)

/* ============ -structures- ====================
   each of the following structures is defined by a typedef
   all realT and coordT fields occur at the beginning of a structure
        (otherwise space may be wasted due to alignment)
   define all flags together and pack into 32-bit number

   DEFsetT is likewise defined in mem.h and qset.h
*/

typedef struct vertexT vertexT;
typedef struct ridgeT ridgeT;
typedef struct facetT facetT;
typedef struct qhT qhT;
#ifndef DEFsetT
#define DEFsetT 1
typedef struct setT setT;        /* defined in qset.h */
#endif

/*----------------------------------

  facetT
    defines a facet

  notes:
   qhull() generates the hull as a list of facets.

  topological information:
    f.previous,next     doubly-linked list of facets, next is always defined
    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 or Voronoi center for output
    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 qh_mergefacet
                        Actual outer plane is +DISTround and
                        computed outer plane is +2*DISTround.
                        Initial maxoutside is qh.DISTround, otherwise distance tests need to account for DISTround */
#endif
  coordT   offset;      /* exact offset of hyperplane from origin */
  coordT  *normal;      /* normal of hyperplane, hull_dim coefficients */
                        /*   if f.tricoplanar, shared with a neighbor */
  union {               /* in order of testing */
   realT   area;        /* area of facet, only in io.c if  f.isarea */
   facetT *replace;     /* replacement facet for qh.NEWfacets with f.visible
                             NULL if qh_mergedegen_redundant, interior, or !NEWfacets */
   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;      /* set according to qh.CENTERtype */
                        /*   qh_ASnone:    no center (not MERGING) */
                        /*   qh_AScentrum: centrum for testing convexity (qh_getcentrum) */
                        /*                 assumed qh_AScentrum while merging */
                        /*   qh_ASvoronoi: Voronoi center (qh_facetcenter) */
                        /* after constructing the hull, it may be changed (qh_clearcenter) */
                        /* if tricoplanar and !keepcentrum, shared with a neighbor */
  facetT  *previous;    /* previous facet in the facet_list or NULL, for C++ interface */
  facetT  *next;        /* next facet in the facet_list or facet_tail */
  setT    *vertices;    /* vertices for this facet, inverse sorted by ID
                           if simplicial, 1st vertex was apex/furthest
                           qh_reduce_vertices removes extraneous vertices via qh_remove_extravertices
                           if f.visible, vertices may be on qh.del_vertices */
  setT    *ridges;      /* explicit ridges for nonsimplicial facets or nonsimplicial neighbors.
                           For simplicial facets, neighbors define the ridges
                           qh_makeridges() converts simplicial facets by creating ridges prior to merging
                           If qh.NEWtentative, new facets have horizon ridge, but not vice versa
                           if f.visible && qh.NEWfacets, ridges is empty */
  setT    *neighbors;   /* neighbors of the facet.  Neighbors may be f.visible
                           If simplicial, the kth neighbor is opposite the kth vertex and the
                           first neighbor is the horizon facet for the first vertex.
                           dupridges marked by qh_DUPLICATEridge (0x01) and qh_MERGEridge (0x02)
                           if f.visible && qh.NEWfacets, neighbors is empty */
  setT    *outsideset;  /* set of points outside this facet
                           if non-empty, last point is furthest
                           if NARROWhull, includes coplanars (less than qh.MINoutside) 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 int visitid; /* visit_id, for visiting all neighbors,
                           all uses are independent */
  unsigned int id;      /* unique identifier from qh.facet_id, 1..qh.facet_id, 0 is sentinel, printed as 'f%d' */
  unsigned int nummerge:9; /* number of merges */
#define qh_MAXnummerge 511 /* 2^9-1 */
                        /* 23 flags (at most 23 due to nummerge), printed by "flags:" in io.c */
  flagT    tricoplanar:1; /* True if TRIangulate and simplicial and coplanar with a neighbor */
                          /*   all tricoplanars share the same apex */
                          /*   all tricoplanars share the same ->center, ->normal, ->offset, ->maxoutside */
                          /*     ->keepcentrum is true for the owner.  It has the ->coplanareset */
                          /*   if ->degenerate, does not span facet (one logical ridge) */
                          /*   during qh_triangulate, f.trivisible points to original facet */
  flagT    newfacet:1;  /* True if facet on qh.newfacet_list (new/qh.first_newfacet 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 facet has one or more dupridge in a new facet (qh_matchneighbor),
                             a dupridge has a subridge shared by more than one new facet */
  flagT    mergeridge:1; /* True if facet or neighbor has a qh_MERGEridge (qh_mark_dupridges)
                            ->normal defined for mergeridge and mergeridge2 */
  flagT    mergeridge2:1; /* True if neighbor has a qh_MERGEridge (qh_mark_dupridges) */
  flagT    coplanarhorizon:1;  /* True if horizon facet is coplanar at last use */
  flagT     mergehorizon:1; /* True if will merge into horizon (its first neighbor w/ f.coplanarhorizon). */
  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
                             Set by qh_updatetested if more than qh_MAXnewcentrum extra vertices
                             Set by qh_mergefacet if |maxdist| > qh.WIDEfacet */
  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)
                         Maybe merge degenerate and redundant to gain another flag */
};


/*----------------------------------

  ridgeT
    defines a ridge

  notes:
  a ridge is hull_dim-1 simplex between two neighboring facets.  If the
  facets are non-simplicial, there may be more than one ridge between
  two facets.  E.G. a 4-d hypercube has two triangles between each pair
  of neighboring facets.

  topological information:
    vertices            a set of vertices
    top,bottom          neighboring facets with orientation

  geometric information:
    tested              True if ridge is clearly convex
    nonconvex           True if ridge is non-convex
*/
struct ridgeT {
  setT    *vertices;    /* vertices belonging to this ridge, inverse sorted by ID
                           NULL if a degen ridge (matchsame) */
  facetT  *top;         /* top facet for this ridge */
  facetT  *bottom;      /* bottom facet for this ridge
                        ridge oriented by odd/even vertex order and top/bottom */
  unsigned int id;      /* unique identifier.  Same size as vertex_id, printed as 'r%d' */
  flagT    seen:1;      /* used to perform operations only once */
  flagT    tested:1;    /* True when ridge is tested for convexity by centrum or opposite vertices */
  flagT    nonconvex:1; /* True if getmergeset detected a non-convex neighbor
                           only one ridge between neighbors may have nonconvex */
  flagT    mergevertex:1; /* True if pending qh_appendvertexmerge due to
                             qh_maybe_duplicateridge or qh_maybe_duplicateridges
                             disables check for duplicate vertices in qh_checkfacet */
  flagT    mergevertex2:1; /* True if qh_drop_mergevertex of MRGvertices, printed but not used */
  flagT    simplicialtop:1; /* True if top was simplicial (original vertices) */
  flagT    simplicialbot:1; /* True if bottom was simplicial (original vertices)
                             use qh_test_centrum_merge if top and bot, need to retest since centrum may change */
};

/*----------------------------------

  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 or vertex_tail */
  vertexT *previous;    /* previous vertex in vertex_list or NULL, for C++ interface */
  pointT  *point;       /* hull_dim coordinates (coordT) */
  setT    *neighbors;   /* neighboring facets of vertex, qh_vertexneighbors()
                           initialized in io.c or after first merge
                           qh_update_vertices for qh_addpoint or qh_triangulate
                           updated by merges
                           qh_order_vertexneighbors by 2-d (orientation) 3-d (adjacency), n-d (f.visitid,id) */
  unsigned int id;      /* unique identifier, 1..qh.vertex_id,  0 for sentinel, printed as 'r%d' */
  unsigned int visitid; /* for use with qh.vertex_visit, size must match */
  flagT    seen:1;      /* used to perform operations only once */
  flagT    seen2:1;     /* another seen flag */
  flagT    deleted:1;   /* vertex will be deleted via qh.del_vertices */
  flagT    delridge:1;  /* vertex belonged to a deleted ridge, cleared by qh_reducevertices */
  flagT    newfacet:1;  /* true if vertex is in a new facet
                           vertex is on qh.newvertex_list and it has a facet on qh.newfacet_list
                           or vertex is on qh.newvertex_list due to qh_newvertices while merging
                           cleared by qh_resetlists */
  flagT    partitioned:1; /* true if deleted vertex has been partitioned */
};

/*======= -global variables -qh ============================*/

/*----------------------------------

  qhT
   All global variables for qhull are in qhT, qhmemT, and qhstatT

  notes:
   qhmem is defined in mem.h, qhstat is defined in stat.h, qhrbox is defined in rboxpoints.h
   Access to qh_qh is via the "qh" macro.  See qh_QHpointer in user.h

   All global variables for qhull are in qh, qhmem, and qhstat
   qh must be unique for each instance of qhull
   qhstat may be shared between qhull instances.
   qhmem may be shared across multiple instances of Qhull.
   Rbox uses global variables rbox_inuse and rbox, but does not persist data across calls.

   Qhull is not multi-threaded.  Global state could be stored in thread-local storage.

   QHULL_LIB_CHECK checks that a program and the corresponding
   qhull library were built with the same type of header files.

   QHULL_LIB_TYPE is QHULL_NON_REENTRANT, QHULL_QH_POINTER, or QHULL_REENTRANT
*/

#define QHULL_NON_REENTRANT 0
#define QHULL_QH_POINTER 1
#define QHULL_REENTRANT 2

#ifdef qh_QHpointer_dllimport
#define qh qh_qh->
__declspec(dllimport) extern qhT *qh_qh;     /* allocated in global.c */
#define QHULL_LIB_TYPE QHULL_QH_POINTER

#elif qh_QHpointer
#define qh qh_qh->
extern qhT *qh_qh;     /* allocated in global.c */
#define QHULL_LIB_TYPE QHULL_QH_POINTER

#elif defined(qh_dllimport)
#define qh qh_qh.
__declspec(dllimport) extern qhT qh_qh;      /* allocated in global.c */
#define QHULL_LIB_TYPE QHULL_NON_REENTRANT

#else
#define qh qh_qh.
extern qhT qh_qh;
#define QHULL_LIB_TYPE QHULL_NON_REENTRANT
#endif

#define QHULL_LIB_CHECK qh_lib_check(QHULL_LIB_TYPE, sizeof(qhT), sizeof(vertexT), sizeof(ridgeT), sizeof(facetT), sizeof(setT), sizeof(qhmemT));
#define QHULL_LIB_CHECK_RBOX qh_lib_check(QHULL_LIB_TYPE, sizeof(qhT), sizeof(vertexT), sizeof(ridgeT), sizeof(facetT), 0, 0);

struct qhT {

/*----------------------------------

  qh constants
    configuration flags and constants for Qhull

  notes:
    The user configures Qhull by defining flags.  They are
    copied into qh by qh_setflags().  qh-quick.htm#options defines the flags.
*/
  boolT ALLpoints;        /* true 'Qs' if search all points for initial simplex */
  boolT ALLOWshort;       /* true 'Qa' allow input with fewer or more points than coordinates */
  boolT ALLOWwarning;     /* true 'Qw' if allow option warnings */
  boolT ALLOWwide;        /* true 'Q12' if allow wide facets and wide dupridges, c.f. qh_WIDEmaxoutside */
  boolT ANGLEmerge;       /* true 'Q1' if sort potential merges by type/angle instead of type/distance  */
  boolT APPROXhull;       /* true 'Wn' if MINoutside set */
  realT MINoutside;       /*   Minimum distance for an outside point ('Wn' or 2*qh.MINvisible) */
  boolT ANNOTATEoutput;   /* true 'Ta' if annotate output with message codes */
  boolT ATinfinity;       /* true 'Qz' if point num_points-1 is "at-infinity"
                             for improving precision in Delaunay triangulations */
  boolT AVOIDold;         /* true 'Q4' if avoid old->new merges */
  boolT BESToutside;      /* true 'Qf' if partition points into best outsideset */
  boolT CDDinput;         /* true 'Pc' if input uses CDD format (1.0/offset first) */
  boolT CDDoutput;        /* true 'PC' if print normals in CDD format (offset first) */
  boolT CHECKduplicates;  /* true 'Q15' if qh_maybe_duplicateridges after each qh_mergefacet */
  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' or 'v' if computing DELAUNAY triangulation */
  boolT DOintersections;  /* true 'Gh' if print hyperplane intersections */
  int   DROPdim;          /* drops dim 'GDn' for 4-d -> 3-d output */
  boolT FLUSHprint;       /* true 'Tf' if flush after qh_fprintf for segfaults */
  boolT FORCEoutput;      /* true 'Po' if forcing output despite degeneracies */
  int   GOODpoint;        /* 'QGn' or 'QG-n' (n+1, n-1), good facet if visible from point n (or not) */
  pointT *GOODpointp;     /*   the actual point */
  boolT GOODthreshold;    /* true 'Pd/PD' if qh.lower_threshold/upper_threshold defined
                             set if qh.UPPERdelaunay (qh_initbuild)
                             false if qh.SPLITthreshold */
  int   GOODvertex;       /* 'QVn' or 'QV-n' (n+1, n-1), good facet if vertex for point n (or not) */
  pointT *GOODvertexp;     /*   the actual point */
  boolT HALFspace;        /* true 'Hn,n,n' if halfspace intersection */
  boolT ISqhullQh;        /* Set by Qhull.cpp on initialization */
  int   IStracing;        /* 'Tn' 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*/
  int   MAXwide;          /* 'QWn' max ratio for wide facet, otherwise error unless Q12-allow-wide */
  boolT MERGEexact;       /* true 'Qx' if exact merges (concave, degen, dupridge, flipped)
                             tested by qh_checkzero and qh_test_*_merge */
  boolT MERGEindependent; /* true if merging independent sets of coplanar facets. 'Q2' disables */
  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 MERGEpinched;     /* true 'Q14' if merging pinched vertices due to dupridge */
  boolT MERGEvertices;    /* true if merging redundant vertices, 'Q3' disables or qh.hull_dim > qh_DIMmergeVertex */
  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, qh_check_points may fail */
  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
                             PGood set if 'd', 'PAn', 'PFn', 'PMn', 'QGn', 'QG-n', 'QVn', or 'QV-n' */
  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 RANDOMdist;       /* true 'Rn' if randomly change distplane and setfacetplane */
  realT RANDOMfactor;     /*    maximum random perturbation */
  realT RANDOMa;          /*    qh_randomfactor is randr * RANDOMa + RANDOMb */
  realT RANDOMb;
  boolT RANDOMoutside;    /* true 'Qr' if select a random outside point */
  int   REPORTfreq;       /* 'TFn' 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' n<-1 random seed, n==-1 time is seed, n==0 random rotation by time, n>0 rotate input */
  boolT SCALEinput;       /* true 'Qbk' if scaling input */
  boolT SCALElast;        /* true 'Qbb' if scale last coord to max prev coord */
  boolT SETroundoff;      /* true 'En' if qh.DISTround is predefined */
  boolT SKIPcheckmax;     /* true 'Q5' if skip qh_check_maxout, qh_check_points may fail */
  boolT SKIPconvex;       /* true 'Q6' if skip convexity testing during pre-merge */
  boolT SPLITthresholds;  /* true 'Pd/PD' if upper_/lower_threshold defines a region
                               else qh.GOODthresholds
                               set if qh.DELAUNAY (qh_initbuild)
                               used only for printing (!for qh.ONLYgood) */
  int   STOPadd;          /* 'TAn' 1+n for stop after adding n vertices */
  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, use qh_IDunknown (-1) after qh_buildhull and qh_postmerge */
  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 ->normal and ->center (sets Qt) */
  boolT UPPERdelaunay;    /* true 'Qu' if computing furthest-site Delaunay */
  boolT USEstdout;        /* true 'Tz' if using stdout instead of stderr */
  boolT VERIFYoutput;     /* true 'Tv' if verify output at end of qhull */
  boolT VIRTUALmemory;    /* true 'Q7' if depth-first processing in buildhull */
  boolT VORONOI;          /* true 'v' if computing Voronoi diagram, also sets qh.DELAUNAY */

  /*--------input constants ---------*/
  realT AREAfactor;       /* 1/(hull_dim-1)! for converting det's to area */
  boolT DOcheckmax;       /* true if calling qh_check_maxout (!qh.SKIPcheckmax && qh.MERGING) */
  char  *feasible_string;  /* feasible point 'Hn,n,n' for halfspace intersection */
  coordT *feasible_point;  /*    as coordinates, both malloc'd */
  boolT GETarea;          /* true 'Fa', 'FA', 'FS', 'PAn', 'PFn' if compute facet area/Voronoi volume in io.c */
  boolT KEEPnearinside;   /* true if near-inside points in coplanarset */
  int   hull_dim;         /* dimension of hull, set by initbuffers */
  int   input_dim;        /* dimension of input, set by initbuffers */
  int   num_points;       /* number of input points */
  pointT *first_point;    /* array of input points, see POINTSmalloc */
  boolT POINTSmalloc;     /*   true if qh.first_point/num_points allocated */
  pointT *input_points;   /* copy of original qh.first_point for input points for qh_joggleinput */
  boolT input_malloc;     /* true if qh.input_points malloc'd */
  char  qhull_command[256];/* command line that invoked this program */
  int   qhull_commandsiz2; /*    size of qhull_command at qh_clear_outputflags */
  char  rbox_command[256]; /* command line that produced the input points */
  char  qhull_options[512];/* descriptive list of options */
  int   qhull_optionlen;  /*    length of last line */
  int   qhull_optionsiz;  /*    size of qhull_options at qh_build_withrestart */
  int   qhull_optionsiz2; /*    size of qhull_options at qh_clear_outputflags */
  int   run_id;           /* non-zero, random identifier for this instance of qhull */
  boolT VERTEXneighbors;  /* true if maintaining vertex neighbors */
  boolT ZEROcentrum;      /* true if 'C-0' or 'C-0 Qx' and not post-merging or 'A-n'.  Sets ZEROall_ok */
  realT *upper_threshold; /* don't print if facet->normal[k]>=upper_threshold[k]
                             must set either GOODthreshold or SPLITthreshold
                             if qh.DELAUNAY, default is 0.0 for upper envelope (qh_initbuild) */
  realT *lower_threshold; /* don't print if facet->normal[k] <=lower_threshold[k] */
  realT *upper_bound;     /* scale point[k] to new upper bound */
  realT *lower_bound;     /* scale point[k] to new lower bound
                             project if both upper_ and lower_bound == 0 */

/*----------------------------------

  qh precision constants
    precision constants for Qhull

  notes:
    qh_detroundoff [geom2.c] 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 ('Cn' + 2*qh.DISTround) */
  realT cos_max;          /* max cosine for convexity (roundoff added) */
  realT DISTround;        /* max round off error for distances, qh.SETroundoff ('En') overrides qh_distround */
  realT MAXabs_coord;     /* max absolute coordinate */
  realT MAXlastcoord;     /* max last coordinate for qh_scalelast */
  realT MAXoutside;       /* max target for qh.max_outside/f.maxoutside, base for qh_RATIO...
                             recomputed at qh_addpoint, unrelated to qh_MAXoutside */
  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 */
  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 */
  boolT NARROWhull;       /* set in qh_initialhull if angle < qh_MAXnarrow */

/*----------------------------------

  qh internal constants
    internal constants for Qhull
*/
  char qhull[sizeof("qhull")]; /* "qhull" for checking ownership while debugging */
  jmp_buf errexit;        /* exit label for qh_errexit, defined by setjmp() and NOerrexit */
  char    jmpXtra[40];    /* extra bytes in case jmp_buf is defined wrong by compiler */
  jmp_buf restartexit;    /* restart label for qh_errexit, defined by setjmp() and ALLOWrestart */
  char    jmpXtra2[40];   /* extra bytes in case jmp_buf is defined wrong by compiler*/
  FILE *  fin;            /* pointer to input file, init by qh_initqhull_start2 */
  FILE *  fout;           /* pointer to output file */
  FILE *  ferr;           /* pointer to error file */
  pointT *interior_point; /* center point of the initial simplex*/
  int     normal_size;    /* size in bytes for facet normals and point coords */
  int     center_size;    /* size in bytes for Voronoi centers */
  int     TEMPsize;       /* size for small, temporary sets (in quick mem) */

/*----------------------------------

  qh facet and vertex lists
    defines lists of facets, new facets, visible facets, vertices, and
    new vertices.  Includes counts, next ids, and trace ids.
  see:
    qh_resetlists()
*/
  facetT *facet_list;     /* first facet */
  facetT *facet_tail;     /* end of facet_list (dummy facet with id 0 and next==NULL) */
  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
                             qh_postmerge sets newfacet_list to facet_list */
  facetT *visible_list;   /* list of visible facets preceding newfacet_list,
                             end of visible list if !facet->visible, same as newfacet_list
                             qh_findhorizon sets visible_list at end of facet_list
                             qh_willdelete prepends to visible_list
                             qh_triangulate appends mirror facets to visible_list at end of facet_list
                             qh_postmerge sets visible_list to facet_list
                             qh_deletevisible deletes the visible facets */
  int       num_visible;  /* current number of visible facets */
  unsigned int tracefacet_id; /* set at init, then can print whenever */
  facetT  *tracefacet;    /*   set in newfacet/mergefacet, undone in delfacet and qh_errexit */
  unsigned int traceridge_id; /* set at init, then can print whenever */
  ridgeT  *traceridge;    /*   set in newridge, undone in delridge, errexit, errexit2, makenew_nonsimplicial, mergecycle_ridges */
  unsigned int tracevertex_id; /* set at buildtracing, can print whenever */
  vertexT *tracevertex;   /*   set in newvertex, undone in delvertex and qh_errexit */
  vertexT *vertex_list;   /* list of all vertices, to vertex_tail */
  vertexT *vertex_tail;   /*      end of vertex_list (dummy vertex with ID 0, next NULL) */
  vertexT *newvertex_list; /* list of vertices in newfacet_list, to vertex_tail
                             all vertices have 'newfacet' set */
  int   num_facets;       /* number of facets in facet_list
                             includes visible 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 qh_findgood_all or qh_markkeep) */
  unsigned int facet_id;  /* ID of next, new facet from newfacet() */
  unsigned int ridge_id;  /* ID of next, new ridge from newridge() */
  unsigned int vertex_id; /* ID of next, new vertex from newvertex() */
  unsigned int first_newfacet; /* ID of first_newfacet for qh_buildcone, or 0 if none */

/*----------------------------------

  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 long' to avoid wrap-around errors */
  boolT ALLOWrestart;     /* true if qh_joggle_restart 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 */
  int   last_errcode;     /* last errcode from qh_fprintf, reset in qh_build_withrestart */
  facetT *GOODclosest;    /* closest facet to GOODthreshold in qh_findgood */
  pointT *coplanar_apex;  /* last apex declared a coplanar point by qh_getpinchedmerges, prevents infinite loop */
  boolT hasAreaVolume;    /* true if totarea, totvol was defined by qh_getarea */
  boolT hasTriangulation; /* true if triangulation created by qh_triangulate */
  boolT isRenameVertex;   /* true during qh_merge_pinchedvertices, disables duplicate ridge vertices in qh_checkfacet */
  realT JOGGLEmax;        /* set 'QJn' if randomly joggle input. 'QJ'/'QJ0.0' sets default (qh_detjoggle) */
  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 qh_makecone/qh_attachnewfacets to qh_resetlists */
  boolT NEWtentative;     /* true while new facets are tentative due to !qh.IGNOREpinched or qh.ONLYgood
                              from qh_makecone to qh_attachnewfacets */
  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, cleared after setjmp.  See qh.ERREXITcalled */
  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 */
  unsigned int repart_facetid; /* previous facetid to prevent recursive qh_partitioncoplanar+qh_partitionpoint */
  int   retry_addpoint;   /* number of retries of qh_addpoint due to merging pinched vertices */
  boolT QHULLfinished;    /* True after qhull() is finished */
  realT totarea;          /* 'FA': total facet area computed by qh_getarea, hasAreaVolume */
  realT totvol;           /* 'FA': total volume computed by qh_getarea, hasAreaVolume */
  unsigned int visit_id;  /* unique ID for searching neighborhoods, */
  unsigned int vertex_visit; /* unique ID for searching vertices, reset with qh_buildtracing */
  boolT WAScoplanar;      /* True if qh_partitioncoplanar (qh_check_maxout) */
  boolT ZEROall_ok;       /* True if qh_checkzero always succeeds */

/*----------------------------------

  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 *vertex_mergeset;  /* temporary set of vertex merges */
  setT *hash_table;       /* hash table for matching ridges in qh_matchfacets
                             size is setsize() */
  setT *other_points;     /* additional points */
  setT *del_vertices;     /* vertices to partition and delete with visible
                             facets.  v.deleted is set for checkfacet */

/*----------------------------------

  qh global buffers
    defines buffers for maxtrix operations, input, and error messages
*/
  coordT *gm_matrix;      /* (dim+1)Xdim matrix for geom.c */
  coordT **gm_row;        /* array of gm_matrix rows */
  char* line;             /* malloc'd input line of maxline+1 chars */
  int maxline;
  coordT *half_space;     /* malloc'd input array for halfspace (qh.normal_size+coordT) */
  coordT *temp_malloc;    /* malloc'd input array for points */

/*----------------------------------

  qh static variables
    defines static variables for individual functions

  notes:
    do not use 'static' within a function.  Multiple instances of qhull
    may exist.

    do not assume zero initialization, 'QPn' may cause a restart
*/
  boolT ERREXITcalled;    /* true during qh_errexit (prevents duplicate calls).  see qh.NOerrexit */
  boolT firstcentrum;     /* for qh_printcentrum */
  boolT old_randomdist;   /* save RANDOMdist flag during io, tracing, or statistics */
  setT *coplanarfacetset; /* set of coplanar facets for searching qh_findbesthorizon() */
  realT last_low;         /* qh_scalelast parameters for qh_setdelaunay */
  realT last_high;
  realT last_newhigh;
  realT lastcpu;          /* for qh_buildtracing */
  int   lastfacets;       /*   last qh.num_facets */
  int   lastmerges;       /*   last zzval_(Ztotmerge) */ 
  int   lastplanes;       /*   last zzval_(Zsetplane) */ 
  int   lastdist;         /*   last zzval_(Zdistplane) */ 
  unsigned int lastreport; /*  last qh.facet_id */
  int mergereport;        /* for qh_tracemerging */
  qhstatT *old_qhstat;    /* for saving qh_qhstat in save_qhull() and UsingLibQhull.  Free with qh_free() */
  setT *old_tempstack;    /* for saving qhmem.tempstack in save_qhull */
  int   ridgeoutnum;      /* number of ridges for 4OFF output (qh_printbegin,etc) */
};

/*=========== -macros- =========================*/

/*----------------------------------

  otherfacet_(ridge, facet)
    return neighboring facet for a ridge in facet
*/
#define otherfacet_(ridge, facet) \
                        (((ridge)->top == (facet)) ? (ridge)->bottom : (ridge)->top)

/*----------------------------------

  getid_(p)
    return int ID for facet, ridge, or vertex
    return qh_IDunknown(-1) if NULL
    return 0 if facet_tail or vertex_tail
*/
#define getid_(p)       ((p) ? (int)((p)->id) : qh_IDunknown)

/*============== FORALL macros ===================*/

/*----------------------------------

  FORALLfacets { ... }
    assign 'facet' to each facet in qh.facet_list

  notes:
    uses 'facetT *facet;'
    assumes last facet is a sentinel

  see:
    FORALLfacet_( facetlist )
*/
#define FORALLfacets for (facet=qh facet_list;facet && facet->next;facet=facet->next)

/*----------------------------------

  FORALLpoints { ... }
    assign 'point' to each point in qh.first_point, qh.num_points

  notes:

  declare:
    coordT *point, *pointtemp;
*/
#define FORALLpoints FORALLpoint_(qh first_point, qh num_points)

/*----------------------------------

  FORALLpoint_(points, num) { ... }
    assign 'point' to each point in points array of num points

  declare:
    coordT *point, *pointtemp;
*/
#define FORALLpoint_(points, num) for (point=(points), \
      pointtemp= (points)+qh hull_dim*(num); point < pointtemp; point += qh hull_dim)

/*----------------------------------

  FORALLvertices { ... }
    assign 'vertex' to each vertex in qh.vertex_list

  declare:
    vertexT *vertex;

  notes:
    assumes qh.vertex_list terminated by NULL or a sentinel (v.next==NULL)
*/
#define FORALLvertices for (vertex=qh vertex_list;vertex && vertex->next;vertex= vertex->next)

/*----------------------------------

  FOREACHfacet_( facets ) { ... }
    assign 'facet' to each facet in facets

  declare:
    facetT *facet, **facetp;

  notes:
    assumes set is not modified

  see:
    FOREACHsetelement_
*/
#define FOREACHfacet_(facets)    FOREACHsetelement_(facetT, facets, facet)

/*----------------------------------

  FOREACHneighbor_( facet ) { ... }
    assign 'neighbor' to each neighbor in facet->neighbors

  FOREACHneighbor_( vertex ) { ... }
    assign 'neighbor' to each neighbor in vertex->neighbors

  declare:
    facetT *neighbor, **neighborp;

  notes:
    assumes set is not modified

  see:
    FOREACHsetelement_
*/
#define FOREACHneighbor_(facet)  FOREACHsetelement_(facetT, facet->neighbors, neighbor)

/*----------------------------------

  FOREACHpoint_( points ) { ... }
    assign 'point' to each point in points set

  declare:
    pointT *point, **pointp;

  notes:
    assumes set is not modified

  see:
    FOREACHsetelement_
*/
#define FOREACHpoint_(points)    FOREACHsetelement_(pointT, points, point)

/*----------------------------------

  FOREACHridge_( ridges ) { ... }
    assign 'ridge' to each ridge in ridges set

  declare:
    ridgeT *ridge, **ridgep;

  notes:
    assumes set is not modified

  see:
    FOREACHsetelement_
*/
#define FOREACHridge_(ridges)    FOREACHsetelement_(ridgeT, ridges, ridge)

/*----------------------------------

  FOREACHvertex_( vertices ) { ... }
    assign 'vertex' to each vertex in vertices set

  declare:
    vertexT *vertex, **vertexp;

  notes:
    assumes set is not modified

  see:
    FOREACHsetelement_
*/
#define FOREACHvertex_(vertices) FOREACHsetelement_(vertexT, vertices,vertex)

/*----------------------------------

  FOREACHfacet_i_( facets ) { ... }
    assign 'facet' and 'facet_i' for each facet in facets set

  declare:
    facetT *facet;
    int     facet_n, facet_i;

  see:
    FOREACHsetelement_i_
*/
#define FOREACHfacet_i_(facets)    FOREACHsetelement_i_(facetT, facets, facet)

/*----------------------------------

  FOREACHneighbor_i_( facet ) { ... }
    assign 'neighbor' and 'neighbor_i' for each neighbor in facet->neighbors

  declare:
    facetT *neighbor;
    int     neighbor_n, neighbor_i;

  notes:
    see FOREACHsetelement_i_
    for facet neighbors of vertex, need to define a new macro
*/
#define FOREACHneighbor_i_(facet)  FOREACHsetelement_i_(facetT, facet->neighbors, neighbor)

/*----------------------------------

  FOREACHpoint_i_( points ) { ... }
    assign 'point' and 'point_i' for each point in points set

  declare:
    pointT *point;
    int     point_n, point_i;

  see:
    FOREACHsetelement_i_
*/
#define FOREACHpoint_i_(points)    FOREACHsetelement_i_(pointT, points, point)

/*----------------------------------

  FOREACHridge_i_( ridges ) { ... }
    assign 'ridge' and 'ridge_i' for each ridge in ridges set

  declare:
    ridgeT *ridge;
    int     ridge_n, ridge_i;

  see:
    FOREACHsetelement_i_
*/
#define FOREACHridge_i_(ridges)    FOREACHsetelement_i_(ridgeT, ridges, ridge)

/*----------------------------------

  FOREACHvertex_i_( vertices ) { ... }
    assign 'vertex' and 'vertex_i' for each vertex in vertices set

  declare:
    vertexT *vertex;
    int     vertex_n, vertex_i;

  see:
    FOREACHsetelement_i_
*/
#define FOREACHvertex_i_(vertices) FOREACHsetelement_i_(vertexT, vertices, vertex)

/********* -libqhull.c prototypes (duplicated from qhull_a.h) **********************/

void    qh_qhull(void);
boolT   qh_addpoint(pointT *furthest, facetT *facet, boolT checkdist);
void    qh_errexit2(int exitcode, facetT *facet, facetT *otherfacet);
void    qh_printsummary(FILE *fp);

/********* -user.c prototypes (alphabetical) **********************/

void    qh_errexit(int exitcode, facetT *facet, ridgeT *ridge);
void    qh_errprint(const char* string, facetT *atfacet, facetT *otherfacet, ridgeT *atridge, vertexT *atvertex);
int     qh_new_qhull(int dim, int numpoints, coordT *points, boolT ismalloc,
                char *qhull_cmd, FILE *outfile, FILE *errfile);
void    qh_printfacetlist(facetT *facetlist, setT *facets, boolT printall);
void    qh_printhelp_degenerate(FILE *fp);
void    qh_printhelp_internal(FILE *fp);
void    qh_printhelp_narrowhull(FILE *fp, realT minangle);
void    qh_printhelp_singular(FILE *fp);
void    qh_printhelp_topology(FILE *fp);
void    qh_printhelp_wide(FILE *fp);
void    qh_user_memsizes(void);

/********* -usermem.c prototypes (alphabetical) **********************/
void    qh_exit(int exitcode);
void    qh_fprintf_stderr(int msgcode, const char *fmt, ... );
void    qh_free(void *mem);
void   *qh_malloc(size_t size);

/********* -userprintf.c and userprintf_rbox.c prototypes **********************/
void    qh_fprintf(FILE *fp, int msgcode, const char *fmt, ... );
void    qh_fprintf_rbox(FILE *fp, int msgcode, const char *fmt, ... );

/***** -geom.c/geom2.c/random.c prototypes (duplicated from geom.h, random.h) ****************/

facetT *qh_findbest(pointT *point, facetT *startfacet,
                     boolT bestoutside, boolT newfacets, boolT noupper,
                     realT *dist, boolT *isoutside, int *numpart);
facetT *qh_findbestnew(pointT *point, facetT *startfacet,
                     realT *dist, boolT bestoutside, boolT *isoutside, int *numpart);
boolT   qh_gram_schmidt(int dim, realT **rows);
void    qh_outerinner(facetT *facet, realT *outerplane, realT *innerplane);
void    qh_printsummary(FILE *fp);
void    qh_projectinput(void);
void    qh_randommatrix(realT *buffer, int dim, realT **row);
void    qh_rotateinput(realT **rows);
void    qh_scaleinput(void);
void    qh_setdelaunay(int dim, int count, pointT *points);
coordT  *qh_sethalfspace_all(int dim, int count, coordT *halfspaces, pointT *feasible);

/***** -global.c prototypes (alphabetical) ***********************/

unsigned long qh_clock(void);
void    qh_checkflags(char *command, char *hiddenflags);
void    qh_clear_outputflags(void);
void    qh_freebuffers(void);
void    qh_freeqhull(boolT allmem);
void    qh_freeqhull2(boolT allmem);
void    qh_init_A(FILE *infile, FILE *outfile, FILE *errfile, int argc, char *argv[]);
void    qh_init_B(coordT *points, int numpoints, int dim, boolT ismalloc);
void    qh_init_qhull_command(int argc, char *argv[]);
void    qh_initbuffers(coordT *points, int numpoints, int dim, boolT ismalloc);
void    qh_initflags(char *command);
void    qh_initqhull_buffers(void);
void    qh_initqhull_globals(coordT *points, int numpoints, int dim, boolT ismalloc);
void    qh_initqhull_mem(void);
void    qh_initqhull_outputflags(void);
void    qh_initqhull_start(FILE *infile, FILE *outfile, FILE *errfile);
void    qh_initqhull_start2(FILE *infile, FILE *outfile, FILE *errfile);
void    qh_initthresholds(char *command);
void    qh_lib_check(int qhullLibraryType, int qhTsize, int vertexTsize, int ridgeTsize, int facetTsize, int setTsize, int qhmemTsize);
void    qh_option(const char *option, int *i, realT *r);
#if qh_QHpointer
void    qh_restore_qhull(qhT **oldqh);
qhT    *qh_save_qhull(void);
#endif

/***** -io.c prototypes (duplicated from io.h) ***********************/

void    qh_dfacet(unsigned int id);
void    qh_dvertex(unsigned int id);
void    qh_printneighborhood(FILE *fp, qh_PRINT format, facetT *facetA, facetT *facetB, boolT printall);
void    qh_produce_output(void);
coordT *qh_readpoints(int *numpoints, int *dimension, boolT *ismalloc);


/********* -mem.c prototypes (duplicated from mem.h) **********************/

void qh_meminit(FILE *ferr);
void qh_memfreeshort(int *curlong, int *totlong);

/********* -poly.c/poly2.c prototypes (duplicated from poly.h) **********************/

void    qh_check_output(void);
void    qh_check_points(void);
setT   *qh_facetvertices(facetT *facetlist, setT *facets, boolT allfacets);
facetT *qh_findbestfacet(pointT *point, boolT bestoutside,
           realT *bestdist, boolT *isoutside);
vertexT *qh_nearvertex(facetT *facet, pointT *point, realT *bestdistp);
pointT *qh_point(int id);
setT   *qh_pointfacet(void /* qh.facet_list */);
int     qh_pointid(pointT *point);
setT   *qh_pointvertex(void /* qh.facet_list */);
void    qh_setvoronoi_all(void);
void    qh_triangulate(void /* qh.facet_list */);

/********* -rboxlib.c prototypes **********************/
int     qh_rboxpoints(FILE* fout, FILE* ferr, char* rbox_command);
void    qh_errexit_rbox(int exitcode);

/********* -stat.c prototypes (duplicated from stat.h) **********************/

void    qh_collectstatistics(void);
void    qh_printallstatistics(FILE *fp, const char *string);

#endif /* qhDEFlibqhull */
qhull-2020.2/src/libqhull/libqhull.pro0000644060175106010010000000356612646573131016151 0ustar  bbarber# -------------------------------------------------
# libqhull.pro -- Qt project for Qhull shared library
# -------------------------------------------------

include(../qhull-warn.pri)

DESTDIR = ../../lib
DLLDESTDIR = ../../bin
TEMPLATE = lib
CONFIG += shared warn_on
CONFIG -= qt

build_pass:CONFIG(debug, debug|release):{
    TARGET = qhull_d
    OBJECTS_DIR = Debug
}else:build_pass:CONFIG(release, debug|release):{
    TARGET = qhull
    OBJECTS_DIR = Release
}
win32-msvc* : QMAKE_LFLAGS += /INCREMENTAL:NO

win32-msvc* : DEF_FILE += ../../src/libqhull/qhull-exports.def

# Order object files by frequency of execution.  Small files at end.

# libqhull/libqhull.pro and ../qhull-libqhull-src.pri have the same SOURCES and HEADERS
SOURCES += ../libqhull/global.c
SOURCES += ../libqhull/stat.c
SOURCES += ../libqhull/geom2.c
SOURCES += ../libqhull/poly2.c
SOURCES += ../libqhull/merge.c
SOURCES += ../libqhull/libqhull.c
SOURCES += ../libqhull/geom.c
SOURCES += ../libqhull/poly.c
SOURCES += ../libqhull/qset.c
SOURCES += ../libqhull/mem.c
SOURCES += ../libqhull/random.c
SOURCES += ../libqhull/usermem.c
SOURCES += ../libqhull/userprintf.c
SOURCES += ../libqhull/io.c
SOURCES += ../libqhull/user.c
SOURCES += ../libqhull/rboxlib.c
SOURCES += ../libqhull/userprintf_rbox.c

HEADERS += ../libqhull/geom.h
HEADERS += ../libqhull/io.h
HEADERS += ../libqhull/libqhull.h
HEADERS += ../libqhull/mem.h
HEADERS += ../libqhull/merge.h
HEADERS += ../libqhull/poly.h
HEADERS += ../libqhull/random.h
HEADERS += ../libqhull/qhull_a.h
HEADERS += ../libqhull/qset.h
HEADERS += ../libqhull/stat.h
HEADERS += ../libqhull/user.h

OTHER_FILES += Mborland
OTHER_FILES += qh-geom.htm
OTHER_FILES += qh-globa.htm
OTHER_FILES += qh-io.htm
OTHER_FILES += qh-mem.htm
OTHER_FILES += qh-merge.htm
OTHER_FILES += qh-poly.htm
OTHER_FILES += qh-qhull.htm
OTHER_FILES += qh-set.htm
OTHER_FILES += qh-stat.htm
OTHER_FILES += qh-user.htm
qhull-2020.2/src/libqhull/Makefile0000644060175106010010000002425013724272754015251 0ustar  bbarber# Simple gcc Makefile for non-reentrant qhull and rbox (default gcc/g++)
#
#   make help
#   See README.txt and ../../Makefile
#       
# Variables
#   DESTDIR        directory for staged installs (GNU Makefile standards)
#   PREFIX         install directory for 'make install' (default /usr/local)
#   BINDIR         directory where to copy executables
#   DOCDIR         directory where to copy html documentation
#   INCDIR         directory where to copy headers
#   LIBDIR         directory where to copy libraries
#   MANDIR         directory where to copy manual pages
#   PCDIR          directory where to copy pkg-config files
#   PRINTMAN       command for printing manual pages
#   PRINTC         command for printing C files
#   CC             ANSI C or C++ compiler
#   CC_OPTS1       options used to compile .c files
#   CC_OPTS2       options used to link .o files
#   CC_OPTS3       options to build shared libraries
#
#   LIBQHULL_OBJS  .o files for linking
#   LIBQHULL_HDRS  .h files for printing
#   CFILES         .c files for printing
#   DOCFILES       documentation files
#   FILES          miscellaneous files for printing
#   TFILES         .txt versions of html files
#   FILES          all other files
#   LIBQHULL_OBJS  specifies the object files of libqhullstatic.a
#
# Results
#   rbox           Generates points sets for qhull, qconvex, etc.
#   qhull          Computes convex hulls and related structures
#   qconvex, qdelaunay, qhalf, qvoronoi
#                  Specializations of qhull for each geometric structure
#   libqhullstatic.a Static library for non-reentrant qhull
#   testqset       Standalone test of non-reentrant qset.c with mem.c
#   user_eg        An example of using qhull (non-reentrant)
#   user_eg2       An example of using qhull (non-reentrant)
#
# Make targets
#   make           Build results using gcc or another compiler
#   make all
#   make clean     Remove object files
#   make cleanall  Remove generated files
#   make doc       Print documentation
#   make help
#   make install   Copy results and documentation to BINDIR, DOCDIR, INCDIR, LIBDIR, MANDIR, PCDOC
#   make uninstall Delete Qhull files from BINDIR, DOCDIR, INCDIR, LIBDIR, MANDIR, PCDOC
#   make new       Rebuild qhull and rbox from source
#   make printall  Print all files
#   make qtest     Quick test of qset, rbox, and qhull
#   make test      Quck test of qhull, qconvex, etc.
#
# $Id: //main/2019/qhull/src/libqhull/Makefile#13 $

# Do not replace tabs with spaces.  Needed for build rules
# Unix line endings (\n)

PREFIX ?= /usr/local
BINDIR ?= bin
INCDIR ?= include
LIBDIR ?= lib
DOCDIR ?= share/doc/qhull
MANDIR ?= share/man/man1
PCDIR  ?= $(LIBDIR)/pkgconfig

ABS_BINDIR = $(DESTDIR)$(PREFIX)/$(BINDIR)
ABS_INCDIR = $(DESTDIR)$(PREFIX)/$(INCDIR)
ABS_LIBDIR = $(DESTDIR)$(PREFIX)/$(LIBDIR)
ABS_DOCDIR = $(DESTDIR)$(PREFIX)/$(DOCDIR)
ABS_MANDIR = $(DESTDIR)$(PREFIX)/$(MANDIR)
ABS_PCDIR  = $(DESTDIR)$(PREFIX)/$(PCDIR)

qhull_VERSION=$(shell grep 'set.qhull_VERSION ' ../../CMakeLists.txt | grep -o '[0-9.]\+' || echo 0unknown)

# 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, -O3 for optimization, -g for debugging, -pg for profiling
# caller may define CC_WARNINGS
# Qhull uses less memory for 32-bit builds on 64-bit hosts
# Enable 32-bit builds with 'make M32=-m32'
# M32     = -m32
# -fpic is required for linking to shared libraries
# -fpic may be slower for 32-bit builds on 64-bit hosts
# Disable -fpic with 'make FPIC=' 
FPIC      = -fpic
CC        = gcc
CC_OPTS1  = -O3 -ansi -I../../src $(CC_WARNINGS) $(M32) $(FPIC)

# for Sun's cc compiler, -fast or O2 for optimization, -g for debugging, -Xc for ANSI
#CC       = cc
#CC_OPTS1 = -Xc -v -fast -I../../src 

# for Silicon Graphics cc compiler, -O2 for optimization, -g for debugging
#CC       = cc
#CC_OPTS1 = -ansi -O2 -I../../src 

# for Next cc compiler with fat executable
#CC       = cc
#CC_OPTS1 = -ansi -O2 -I../../src -arch m68k -arch i386 -arch hppa

# For loader, ld, 
CC_OPTS2 = $(CC_OPTS1)

# Default targets for make

all: qhull_links qhull_all qtest

help:
	head -n 54 Makefile

clean:
	rm -f *.o 
	# Delete linked files from other directories [qhull_links]
	rm -f qconvex.c unix.c qdelaun.c qhalf.c qvoronoi.c rbox.c
	rm -f user_eg.c user_eg2.c testqset.c
	
cleanall: clean
	rm -f qconvex qdelaunay qhalf qvoronoi qhull *.exe
	rm -f core user_eg user_eg2 testqset libqhullstatic.a

doc: 
	$(PRINTMAN) $(TXTFILES) $(DOCFILES)

install:
	mkdir -p $(ABS_BINDIR)
	mkdir -p $(ABS_DOCDIR)/src
	mkdir -p $(ABS_INCDIR)/libqhull
	mkdir -p $(ABS_LIBDIR)
	mkdir -p $(ABS_MANDIR)
	mkdir -p $(ABS_PCDIR)
	cp -p qconvex qdelaunay qhalf qhull qvoronoi rbox $(ABS_BINDIR)
	cp -p libqhullstatic.a $(ABS_LIBDIR)
	(cd ../.. && cp -p README.txt REGISTER.txt Announce.txt COPYING.txt index.htm $(ABS_DOCDIR)/)
	(cd ../.. && cp -pr html $(ABS_DOCDIR)/)
	(cd ../.. && cp -p src/Changes.txt $(ABS_DOCDIR)/src/)
	cp -p ../../html/qhull.man $(ABS_MANDIR)/qhull.1
	cp -p ../../html/rbox.man $(ABS_MANDIR)/rbox.1
	cp DEPRECATED.txt *.h $(ABS_INCDIR)/libqhull
	sed \
		-e 's#@qhull_VERSION@#$(qhull_VERSION)#' \
		-e 's#@CMAKE_INSTALL_PREFIX@#$(PREFIX)#' \
		-e 's#@LIB_INSTALL_DIR@#$(LIBDIR)#' \
		-e 's#@INCLUDE_INSTALL_DIR@#$(INCDIR)#' \
		-e 's#@LIBRARY_NAME@#qhullstatic#' \
		-e 's#@LIBRARY_DESCRIPTION@#Qhull static library#' \
		../../build/qhull.pc.in > $(ABS_PCDIR)/qhullstatic.pc

uninstall:
	-(cd $(ABS_BINDIR) && rm -f qconvex qdelaunay qhalf qhull qvoronoi rbox)
	-(cd $(ABS_BINDIR) && rm -f qconvex.exe qdelaunay.exe qhalf.exe qhull.exe qvoronoi.exe rbox.exe)
	-(cd $(ABS_MANDIR) && rm -f qhull.1 rbox.1)
	-(cd $(ABS_DOCDIR) && rm -f README.txt REGISTER.txt Announce.txt COPYING.txt index.htm src/Changes.txt)
	-(cd $(ABS_DOCDIR) && rm -rf html)
	-(cd $(ABS_LIBDIR) && rm -f libqhullstatic.a)
	-(cd $(ABS_INCDIR) && rm -rf libqhull)
	-(cd $(ABS_PCDIR) && rm -f qhullstatic.pc)
	-rmdir $(ABS_DOCDIR)/src
	-rmdir $(ABS_DOCDIR)

new:	cleanall all

printall: doc printh printc printf

printh:
	$(PRINTC) $(LIBQHULL_HDRS)

printc:
	$(PRINTC) $(CFILES)

# LIBQHULL_OBJS_1 ordered by frequency of execution with small files at end.  Better locality.
# Same definitions as ../../Makefile

LIBQHULLS_OBJS_1= global.o stat.o geom2.o poly2.o merge.o \
	libqhull.o geom.o poly.o qset.o mem.o random.o 

LIBQHULLS_OBJS_2= $(LIBQHULLS_OBJS_1) usermem.o userprintf.o io.o user.o

LIBQHULLS_OBJS= $(LIBQHULLS_OBJS_2)  rboxlib.o userprintf_rbox.o

LIBQHULL_HDRS= user.h libqhull.h qhull_a.h geom.h \
	io.h mem.h merge.h poly.h random.h \
	qset.h stat.h

# CFILES for 'printc', ordered alphabetically after libqhull.c 
CFILES= ../qhull/unix.c libqhull.c geom.c geom2.c global.c io.c \
	mem.c merge.c poly.c poly2.c random.c rboxlib.c \
	qset.c stat.c user.c usermem.c userprintf.c \
	../qconvex/qconvex.c ../qdelaunay/qdelaun.c \
	../qhalf/qhalf.c ../qvoronoi/qvoronoi.c

TXTFILES= ../../Announce.txt ../../REGISTER.txt ../../COPYING.txt ../../README.txt ../Changes.txt
DOCFILES= ../../html/rbox.txt ../../html/qhull.txt

.c.o:
	$(CC) -c $(CC_OPTS1) -o $@ $<

# Work around problems with ../ in Red Hat Linux
qhull_links:
	# On MINSYS, 'ln -s' may create a copy instead of a symbolic link
	[ -f qconvex.c ]  || ln -s ../qconvex/qconvex.c
	[ -f qdelaun.c ]  || ln -s ../qdelaunay/qdelaun.c
	[ -f qhalf.c ]    || ln -s ../qhalf/qhalf.c
	[ -f qvoronoi.c ] || ln -s ../qvoronoi/qvoronoi.c
	[ -f rbox.c ]     || ln -s ../rbox/rbox.c
	[ -f testqset.c ] || ln -s ../testqset/testqset.c
	[ -f unix.c ]     || ln -s ../qhull/unix.c
	[ -f user_eg.c ]  || ln -s ../user_eg/user_eg.c
	[ -f user_eg2.c ] || ln -s ../user_eg2/user_eg2.c
	# user_eg3.c not compiled.  It requires all of libqhullcpp; use qhull/Makefile instead

# compile qhull without using bin/libqhullstatic.a
qhull_all: qconvex.o qdelaun.o qhalf.o qvoronoi.o unix.o user_eg.o user_eg2.o rbox.o testqset.o $(LIBQHULLS_OBJS)
	$(CC) -o qconvex $(CC_OPTS2) $(LIBQHULLS_OBJS_2) qconvex.o -lm
	$(CC) -o qdelaunay $(CC_OPTS2) $(LIBQHULLS_OBJS_2) qdelaun.o -lm
	$(CC) -o qhalf $(CC_OPTS2) $(LIBQHULLS_OBJS_2) qhalf.o -lm
	$(CC) -o qvoronoi $(CC_OPTS2) $(LIBQHULLS_OBJS_2) qvoronoi.o -lm
	$(CC) -o qhull $(CC_OPTS2) $(LIBQHULLS_OBJS_2) unix.o -lm
	$(CC) -o rbox $(CC_OPTS2) $(LIBQHULLS_OBJS) rbox.o -lm
	$(CC) -o user_eg $(CC_OPTS2) $(LIBQHULLS_OBJS_2) user_eg.o -lm
	$(CC) -o user_eg2 $(CC_OPTS2) $(LIBQHULLS_OBJS_1) user_eg2.o  usermem.o userprintf.o io.o -lm
	$(CC) -o testqset $(CC_OPTS2) mem.o qset.o usermem.o testqset.o -lm
	-ar -rs libqhullstatic.a $(LIBQHULLS_OBJS)
	#libqhullstatic.a is not needed for qhull
	#If 'ar -rs' fails try using 'ar -s' with 'ranlib'
	#ranlib libqhullstatic.a

qtest:
	@echo ============================================
	@echo == make qtest ==============================
	@echo ============================================
	@echo -n "== "
	@date
	@echo
	@echo Testing qset.c and mem.c with testqset
	./testqset 10000
	@echo Run the qhull smoketest
	./rbox D4 | ./qhull
	@echo ============================================
	@echo == To smoketest qhull programs
	@echo '==     make test'
	@echo ============================================
	@echo
	@echo ============================================
	@echo == To install qhull or show help
	@echo '==     make help'
	@echo '==     make install'
	@echo ============================================
	@echo

test: qtest
	@echo ==============================
	@echo ========= qconvex ============
	@echo ==============================
	-./rbox 10 | ./qconvex Tv 
	@echo
	@echo ==============================
	@echo ========= qdelaunay ==========
	@echo ==============================
	-./rbox 10 | ./qdelaunay Tv 
	@echo
	@echo ==============================
	@echo ========= qhalf ==============
	@echo ==============================
	-./rbox 10 | ./qconvex FQ FV n Tv | ./qhalf Tv
	@echo
	@echo ==============================
	@echo ========= qvoronoi ===========
	@echo ==============================
	-./rbox 10 | ./qvoronoi Tv
	@echo
	@echo ==============================
	@echo ========= user_eg ============
	@echo == w/o shared library ========
	@echo ==============================
	-./user_eg
	@echo
	@echo ==============================
	@echo ========= user_eg2 ===========
	@echo ==============================
	-./user_eg2
	@echo

# end of Makefile
qhull-2020.2/src/libqhull/Mborland0000644060175106010010000001366711710424412015263 0ustar  bbarber#########################################################################
#  Borland C++ 4.02 for Win32 and DOS Power Pack			#
#  Makefile for qhull and rbox					        #
#								        #
#       make -fMborland all       to produce qconvex, qhull, and rbox   #
#       make -fMborland user_eg   to produce user_eg		        #
#       make -fMborland user_eg2  to produce user_eg2		        #
#       make -fMborland new       to rebuild qhull and rbox from source #
#       make -fMborland clean     to remove object files		#
#       make -fMborland cleanall  to remove all generated files	        #
#       make -fMborland test      to test rbox and qhull		#
#								        #
#  Author: D. Zwick of Germany, C.B. Barber			        #
#########################################################################

CC      = bcc32    # 32 bit compiler for DOS
		   # bcc32i - Intel's compiler
LINKER  = $(CC)    # bcc calls tlink32 with needed options
CFLAGS  = -w- -A -O2   
		    # -w- no warnings, bcc doesn't handle assigns in conditions
			# -A Ansi standard
			# -X no auto-dependency outputs
			# -v debugging, use CCOPTS for both 
			# -O2 optimization   
!if $d(_DPMI)
LFLAGS  = -WX -w-   # -WX loads DPMI library
!else
LFLAGS  = -lap -lx -lc
					# -lap 32-bit console application
					# -lx no map file
					# -lc case is significant 
!endif

EXERB = rbox
EXEQH = qhull
EXEQC = qconvex
EXEQD = qdelaunay
EXEQV = qvoronoi
EXEQF = qhalf
EXEEG = user_eg
EXEEG2 = user_eg2

TMPFILE = BCC32tmp.cfg

OBJS1 =   global.obj stat.obj geom2.obj poly2.obj merge.obj
OBJS2 =   libqhull.obj geom.obj poly.obj qset.obj mem.obj 
OBJS3 =   random.obj usermem.obj userprintf.obj io.obj user.obj
OBJS4 =   rboxlib.obj random.obj usermem.obj userprintf_rbox.obj

HFILES1 = libqhull.h stat.h qhull_a.h user.h


# General rules

.c.obj:
	$(CC) -c $(CFLAGS) $<

# Default

all:	  $(EXERB) $(EXEQH) $(EXEQC) $(EXEQD) $(EXEQV) $(EXEQF) test

help:
	@echo  USAGE:
	@echo  "make all       to produce qhull, rbox, qconvex, qdelaun, qvoronoi, qhalf"
	@echo  "make user_eg   to produce user_eg"
	@echo  "make user_eg2  to produce user_eg2"
	@echo  "make new       to rebuild qhull and rbox from source"
	@echo  "make clean     to remove object files"
	@echo  "make cleanall  to remove all generated file"
	@echo  "make test      to test rbox and qhull"
	@echo  OPTIONS (default is 32-bit console app):
	@echo  "-D_DPMI	for C++ 4.01 and DOS Power Pack"

# Executables

$(EXEQH):     ..\..\bin\$(EXEQH).exe
	@echo Made ..\..\bin\$(EXEQH).exe

unix.obj: ..\qhull\unix.c 
..\..\bin\$(EXEQH).exe: unix.obj $(OBJS1) $(OBJS2) $(OBJS3)
	@echo unix.obj > $(TMPFILE)
	@echo $(OBJS1) >> $(TMPFILE)
	@echo $(OBJS2) >> $(TMPFILE)
	@echo $(OBJS3) >> $(TMPFILE)
	$(LINKER) -e$@ $(CFLAGS) $(LFLAGS) @$(TMPFILE)

$(EXEQC):     ..\..\bin\$(EXEQC).exe
	@echo Made ..\..\bin\$(EXEQC).exe

qconvex.obj: ..\qconvex\qconvex.c
..\..\bin\$(EXEQC).exe: qconvex.obj $(OBJS1) $(OBJS2) $(OBJS3)
	@echo qconvex.obj > $(TMPFILE)
	@echo $(OBJS1) >> $(TMPFILE)
	@echo $(OBJS2) >> $(TMPFILE)
	@echo $(OBJS3) >> $(TMPFILE)
	$(LINKER) -e$@ $(CFLAGS) $(LFLAGS) @$(TMPFILE)

$(EXEQD):     ..\..\bin\$(EXEQD).exe
	@echo Made ..\..\bin\$(EXEQD).exe

qdelaun.obj: ..\qdelaunay\qdelaun.c
..\..\bin\$(EXEQD).exe: qdelaun.obj $(OBJS1) $(OBJS2) $(OBJS3)
	@echo qdelaun.obj > $(TMPFILE)
	@echo $(OBJS1) >> $(TMPFILE)
	@echo $(OBJS2) >> $(TMPFILE)
	@echo $(OBJS3) >> $(TMPFILE)
	$(LINKER) -e$@ $(CFLAGS) $(LFLAGS) @$(TMPFILE)

$(EXEQV):     ..\..\bin\$(EXEQV).exe
	@echo Made ..\..\bin\$(EXEQV).exe

qvoronoi.obj: ..\qvoronoi\qvoronoi.c
..\..\bin\$(EXEQV).exe: qvoronoi.obj $(OBJS1) $(OBJS2) $(OBJS3)
	@echo qvoronoi.obj > $(TMPFILE)
	@echo $(OBJS1) >> $(TMPFILE)
	@echo $(OBJS2) >> $(TMPFILE)
	@echo $(OBJS3) >> $(TMPFILE)
	$(LINKER) -e$@ $(CFLAGS) $(LFLAGS) @$(TMPFILE)

$(EXEQF):     ..\..\bin\$(EXEQF).exe
	@echo Made ..\..\bin\$(EXEQF).exe

qhalf.obj: ..\qhalf\qhalf.c
..\..\bin\$(EXEQF).exe:  qhalf.obj $(OBJS1) $(OBJS2) $(OBJS3)
	@echo qhalf.obj > $(TMPFILE)
	@echo $(OBJS1) >> $(TMPFILE)
	@echo $(OBJS2) >> $(TMPFILE)
	@echo $(OBJS3) >> $(TMPFILE)
	$(LINKER) -e$@ $(CFLAGS) $(LFLAGS) @$(TMPFILE)

$(EXEEG):     ..\..\bin\$(EXEEG).exe
	@echo Made ..\..\bin\$(EXEEG).exe

user_eg.obj: ..\user_eg\user_eg.c
..\..\bin\$(EXEEG).exe: user_eg.obj $(OBJS1) $(OBJS2) $(OBJS3)
	@echo user_eg.obj > $(TMPFILE)
	@echo $(OBJS1) >> $(TMPFILE)
	@echo $(OBJS2) >> $(TMPFILE)
	@echo $(OBJS3) >> $(TMPFILE)
	$(LINKER) -e$@ $(CFLAGS) $(LFLAGS) @$(TMPFILE)

$(EXEEG2):     ..\..\bin\$(EXEEG2).exe
	@echo Made ..\..\bin\$(EXEEG2).exe

user_eg2.obj: ..\user_eg2\user_eg2.c
..\..\bin\$(EXEEG2).exe: user_eg2.obj $(OBJS1) $(OBJS2) $(OBJS3)
	@echo user_eg2.obj > $(TMPFILE)
	@echo $(OBJS1) >> $(TMPFILE)
	@echo $(OBJS2) >> $(TMPFILE)
	@echo $(OBJS3) >> $(TMPFILE)
	$(LINKER) -e$@ $(CFLAGS) $(LFLAGS) @$(TMPFILE)

$(EXERB):     ..\..\bin\$(EXERB).exe
	@echo Made ..\..\bin\$(EXERB).exe

rbox.obj: ..\rbox\rbox.c 
..\..\bin\$(EXERB).exe: rbox.obj $(OBJS4)
	@echo rbox.obj > $(TMPFILE)
	@echo $(OBJS4) >> $(TMPFILE)
	$(LINKER) -e$@ $(CFLAGS) $(LFLAGS) @$(TMPFILE)

# Test rbox and qhull

test:   
	@..\..\bin\rbox D4 > test.x
	@..\..\bin\qhull 
  ---------------------------------

  mem.c
    memory management routines for qhull

  This is a standalone program.

  To initialize memory:

    qh_meminit(stderr);
    qh_meminitbuffers(qh IStracing, qh_MEMalign, 7, qh_MEMbufsize,qh_MEMinitbuf);
    qh_memsize((int)sizeof(facetT));
    qh_memsize((int)sizeof(facetT));
    ...
    qh_memsetup();

  To free up all memory buffers:
    qh_memfreeshort(&curlong, &totlong);

  if qh_NOmem,
    malloc/free is used instead of mem.c

  notes:
    uses Quickfit algorithm (freelists for commonly allocated sizes)
    assumes small sizes for freelists (it discards the tail of memory buffers)

  see:
    qh-mem.htm and mem.h
    global.c (qh_initbuffers) for an example of using mem.c

  Copyright (c) 1993-2020 The Geometry Center.
  $Id: //main/2019/qhull/src/libqhull/mem.c#4 $$Change: 2953 $
  $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
*/

#include "user.h"  /* for QHULL_CRTDBG */
#include "mem.h"
#include 
#include 
#include 

#ifndef qhDEFlibqhull
typedef struct ridgeT ridgeT;
typedef struct facetT facetT;
#ifdef _MSC_VER  /* Microsoft Visual C++ -- warning level 4 */
#pragma warning( disable : 4127)  /* conditional expression is constant */
#pragma warning( disable : 4706)  /* assignment within conditional function */
#endif
void    qh_errexit(int exitcode, facetT *, ridgeT *);
void    qh_exit(int exitcode);
void    qh_fprintf(FILE *fp, int msgcode, const char *fmt, ... );
void    qh_fprintf_stderr(int msgcode, const char *fmt, ... );
void    qh_free(void *mem);
void   *qh_malloc(size_t size);
#endif

/*============ -global data structure ==============
    see mem.h for definition
*/

qhmemT qhmem= {0,0,0,0,0,0,0,0,0,0,0,
               0,0,0,0,0,0,0,0,0,0,0,
               0,0,0,0,0,0,0};     /* remove "= {0}" if this causes a compiler error */

#ifndef qh_NOmem

/*============= internal functions ==============*/

static int qh_intcompare(const void *i, const void *j);

/*========== functions in alphabetical order ======== */

/*---------------------------------

  qh_intcompare( i, j )
    used by qsort and bsearch to compare two integers
*/
static int qh_intcompare(const void *i, const void *j) {
  return(*((const int *)i) - *((const int *)j));
} /* intcompare */


/*----------------------------------

  qh_memalloc( insize )
    returns object of insize bytes
    qhmem is the global memory structure

  returns:
    pointer to allocated memory
    errors if insufficient memory

  notes:
    use explicit type conversion to avoid type warnings on some compilers
    actual object may be larger than insize
    use qh_memalloc_() for inline code for quick allocations
    logs allocations if 'T5'
    caller is responsible for freeing the memory.
    short memory is freed on shutdown by qh_memfreeshort unless qh_NOmem

  design:
    if size < qhmem.LASTsize
      if qhmem.freelists[size] non-empty
        return first object on freelist
      else
        round up request to size of qhmem.freelists[size]
        allocate new allocation buffer if necessary
        allocate object from allocation buffer
    else
      allocate object with qh_malloc() in user.c
*/
void *qh_memalloc(int insize) {
  void **freelistp, *newbuffer;
  int idx, size, n;
  int outsize, bufsize;
  void *object;

  if (insize<0) {
      qh_fprintf(qhmem.ferr, 6235, "qhull error (qh_memalloc): negative request size (%d).  Did int overflow due to high-D?\n", insize); /* WARN64 */
      qh_errexit(qhmem_ERRmem, NULL, NULL);
  }
  if (insize>=0 && insize <= qhmem.LASTsize) {
    idx= qhmem.indextable[insize];
    outsize= qhmem.sizetable[idx];
    qhmem.totshort += outsize;
    freelistp= qhmem.freelists+idx;
    if ((object= *freelistp)) {
      qhmem.cntquick++;
      qhmem.totfree -= outsize;
      *freelistp= *((void **)*freelistp);  /* replace freelist with next object */
#ifdef qh_TRACEshort
      n= qhmem.cntshort+qhmem.cntquick+qhmem.freeshort;
      if (qhmem.IStracing >= 5)
          qh_fprintf(qhmem.ferr, 8141, "qh_mem %p n %8d alloc quick: %d bytes (tot %d cnt %d)\n", object, n, outsize, qhmem.totshort, qhmem.cntshort+qhmem.cntquick-qhmem.freeshort);
#endif
      return(object);
    }else {
      qhmem.cntshort++;
      if (outsize > qhmem.freesize) {
        qhmem.totdropped += qhmem.freesize;
        if (!qhmem.curbuffer)
          bufsize= qhmem.BUFinit;
        else
          bufsize= qhmem.BUFsize;
        if (!(newbuffer= qh_malloc((size_t)bufsize))) {
          qh_fprintf(qhmem.ferr, 6080, "qhull error (qh_memalloc): insufficient memory to allocate short memory buffer (%d bytes)\n", bufsize);
          qh_errexit(qhmem_ERRmem, NULL, NULL);
        }
        *((void **)newbuffer)= qhmem.curbuffer;  /* prepend newbuffer to curbuffer
                                                    list.  newbuffer!=0 by QH6080 */
        qhmem.curbuffer= newbuffer;
        size= ((int)sizeof(void **) + qhmem.ALIGNmask) & ~qhmem.ALIGNmask;
        qhmem.freemem= (void *)((char *)newbuffer+size);
        qhmem.freesize= bufsize - size;
        qhmem.totbuffer += bufsize - size; /* easier to check */
        /* Periodically test totbuffer.  It matches at beginning and exit of every call */
        n= qhmem.totshort + qhmem.totfree + qhmem.totdropped + qhmem.freesize - outsize;
        if (qhmem.totbuffer != n) {
            qh_fprintf(qhmem.ferr, 6212, "qhull internal error (qh_memalloc): short totbuffer %d != totshort+totfree... %d\n", qhmem.totbuffer, n);
            qh_errexit(qhmem_ERRmem, NULL, NULL);
        }
      }
      object= qhmem.freemem;
      qhmem.freemem= (void *)((char *)qhmem.freemem + outsize);
      qhmem.freesize -= outsize;
      qhmem.totunused += outsize - insize;
#ifdef qh_TRACEshort
      n= qhmem.cntshort+qhmem.cntquick+qhmem.freeshort;
      if (qhmem.IStracing >= 5)
          qh_fprintf(qhmem.ferr, 8140, "qh_mem %p n %8d alloc short: %d bytes (tot %d cnt %d)\n", object, n, outsize, qhmem.totshort, qhmem.cntshort+qhmem.cntquick-qhmem.freeshort);
#endif
      return object;
    }
  }else {                     /* long allocation */
    if (!qhmem.indextable) {
      qh_fprintf(qhmem.ferr, 6081, "qhull internal error (qh_memalloc): qhmem has not been initialized.\n");
      qh_errexit(qhmem_ERRqhull, NULL, NULL);
    }
    outsize= insize;
    qhmem.cntlong++;
    qhmem.totlong += outsize;
    if (qhmem.maxlong < qhmem.totlong)
      qhmem.maxlong= qhmem.totlong;
    if (!(object= qh_malloc((size_t)outsize))) {
      qh_fprintf(qhmem.ferr, 6082, "qhull error (qh_memalloc): insufficient memory to allocate %d bytes\n", outsize);
      qh_errexit(qhmem_ERRmem, NULL, NULL);
    }
    if (qhmem.IStracing >= 5)
      qh_fprintf(qhmem.ferr, 8057, "qh_mem %p n %8d alloc long: %d bytes (tot %d cnt %d)\n", object, qhmem.cntlong+qhmem.freelong, outsize, qhmem.totlong, qhmem.cntlong-qhmem.freelong);
  }
  return(object);
} /* memalloc */


/*----------------------------------

  qh_memcheck( )
*/
void qh_memcheck(void) {
  int i, count, totfree= 0;
  void *object;

  if (qhmem.ferr == 0 || qhmem.IStracing < 0 || qhmem.IStracing > 10 || (((qhmem.ALIGNmask+1) & qhmem.ALIGNmask) != 0)) {
    qh_fprintf_stderr(6244, "qhull internal error (qh_memcheck): either qhmem is overwritten or qhmem is not initialized.  Call qh_meminit or qh_new_qhull before calling qh_mem routines.  ferr 0x%x, IsTracing %d, ALIGNmask 0x%x\n", 
          qhmem.ferr, qhmem.IStracing, qhmem.ALIGNmask);
    qh_exit(qhmem_ERRqhull);  /* can not use qh_errexit() */
  }
  if (qhmem.IStracing != 0)
    qh_fprintf(qhmem.ferr, 8143, "qh_memcheck: check size of freelists on qhmem\nqh_memcheck: A segmentation fault indicates an overwrite of qhmem\n");
  for (i=0; i < qhmem.TABLEsize; i++) {
    count=0;
    for (object= qhmem.freelists[i]; object; object= *((void **)object))
      count++;
    totfree += qhmem.sizetable[i] * count;
  }
  if (totfree != qhmem.totfree) {
    qh_fprintf(qhmem.ferr, 6211, "qhull internal error (qh_memcheck): totfree %d not equal to freelist total %d\n", qhmem.totfree, totfree);
    qh_errexit(qhmem_ERRqhull, NULL, NULL);
  }
  if (qhmem.IStracing != 0)
    qh_fprintf(qhmem.ferr, 8144, "qh_memcheck: total size of freelists totfree is the same as qhmem.totfree\n", totfree);
} /* memcheck */

/*----------------------------------

  qh_memfree( object, insize )
    free up an object of size bytes
    size is insize from qh_memalloc

  notes:
    object may be NULL
    type checking warns if using (void **)object
    use qh_memfree_() for quick free's of small objects

  design:
    if size <= qhmem.LASTsize
      append object to corresponding freelist
    else
      call qh_free(object)
*/
void qh_memfree(void *object, int insize) {
  void **freelistp;
  int idx, outsize;

  if (!object)
    return;
  if (insize <= qhmem.LASTsize) {
    qhmem.freeshort++;
    idx= qhmem.indextable[insize];
    outsize= qhmem.sizetable[idx];
    qhmem.totfree += outsize;
    qhmem.totshort -= outsize;
    freelistp= qhmem.freelists + idx;
    *((void **)object)= *freelistp;
    *freelistp= object;
#ifdef qh_TRACEshort
    idx= qhmem.cntshort+qhmem.cntquick+qhmem.freeshort;
    if (qhmem.IStracing >= 5)
        qh_fprintf(qhmem.ferr, 8142, "qh_mem %p n %8d free short: %d bytes (tot %d cnt %d)\n", object, idx, outsize, qhmem.totshort, qhmem.cntshort+qhmem.cntquick-qhmem.freeshort);
#endif
  }else {
    qhmem.freelong++;
    qhmem.totlong -= insize;
    if (qhmem.IStracing >= 5)
      qh_fprintf(qhmem.ferr, 8058, "qh_mem %p n %8d free long: %d bytes (tot %d cnt %d)\n", object, qhmem.cntlong+qhmem.freelong, insize, qhmem.totlong, qhmem.cntlong-qhmem.freelong);
    qh_free(object);
  }
} /* memfree */


/*---------------------------------

  qh_memfreeshort( curlong, totlong )
    frees up all short and qhmem memory allocations

  returns:
    number and size of current long allocations

  notes:
    if qh_NOmem (qh_malloc() for all allocations),
       short objects (e.g., facetT) are not recovered.
       use qh_freeqhull(qh_ALL) instead.

  see:
    qh_freeqhull(allMem)
    qh_memtotal(curlong, totlong, curshort, totshort, maxlong, totbuffer);
*/
void qh_memfreeshort(int *curlong, int *totlong) {
  void *buffer, *nextbuffer;
  FILE *ferr;

  *curlong= qhmem.cntlong - qhmem.freelong;
  *totlong= qhmem.totlong;
  for (buffer=qhmem.curbuffer; buffer; buffer= nextbuffer) {
    nextbuffer= *((void **) buffer);
    qh_free(buffer);
  }
  qhmem.curbuffer= NULL;
  if (qhmem.LASTsize) {
    qh_free(qhmem.indextable);
    qh_free(qhmem.freelists);
    qh_free(qhmem.sizetable);
  }
  ferr= qhmem.ferr;
  memset((char *)&qhmem, 0, sizeof(qhmem));  /* every field is 0, FALSE, NULL */
  qhmem.ferr= ferr;
} /* memfreeshort */


/*----------------------------------

  qh_meminit( ferr )
    initialize qhmem and test sizeof(void *)
    Does not throw errors.  qh_exit on failure
*/
void qh_meminit(FILE *ferr) {

  memset((char *)&qhmem, 0, sizeof(qhmem));  /* every field is 0, FALSE, NULL */
  if (ferr)
    qhmem.ferr= ferr;
  else
    qhmem.ferr= stderr;
  if (sizeof(void *) < sizeof(int)) {
    qh_fprintf(qhmem.ferr, 6083, "qhull internal error (qh_meminit): sizeof(void *) %d < sizeof(int) %d.  qset.c will not work\n", (int)sizeof(void*), (int)sizeof(int));
    qh_exit(qhmem_ERRqhull);  /* can not use qh_errexit() */
  }
  if (sizeof(void *) > sizeof(ptr_intT)) {
    qh_fprintf(qhmem.ferr, 6084, "qhull internal error (qh_meminit): sizeof(void *) %d > sizeof(ptr_intT) %d. Change ptr_intT in mem.h to 'long long'\n", (int)sizeof(void*), (int)sizeof(ptr_intT));
    qh_exit(qhmem_ERRqhull);  /* can not use qh_errexit() */
  }
  qh_memcheck();
} /* meminit */

/*---------------------------------

  qh_meminitbuffers( tracelevel, alignment, numsizes, bufsize, bufinit )
    initialize qhmem
    if tracelevel >= 5, trace memory allocations
    alignment= desired address alignment for memory allocations
    numsizes= number of freelists
    bufsize=  size of additional memory buffers for short allocations
    bufinit=  size of initial memory buffer for short allocations
*/
void qh_meminitbuffers(int tracelevel, int alignment, int numsizes, int bufsize, int bufinit) {

  qhmem.IStracing= tracelevel;
  qhmem.NUMsizes= numsizes;
  qhmem.BUFsize= bufsize;
  qhmem.BUFinit= bufinit;
  qhmem.ALIGNmask= alignment-1;
  if (qhmem.ALIGNmask & ~qhmem.ALIGNmask) {
    qh_fprintf(qhmem.ferr, 6085, "qhull internal error (qh_meminit): memory alignment %d is not a power of 2\n", alignment);
    qh_errexit(qhmem_ERRqhull, NULL, NULL);
  }
  qhmem.sizetable= (int *) calloc((size_t)numsizes, sizeof(int));
  qhmem.freelists= (void **) calloc((size_t)numsizes, sizeof(void *));
  if (!qhmem.sizetable || !qhmem.freelists) {
    qh_fprintf(qhmem.ferr, 6086, "qhull error (qh_meminit): insufficient memory\n");
    qh_errexit(qhmem_ERRmem, NULL, NULL);
  }
  if (qhmem.IStracing >= 1)
    qh_fprintf(qhmem.ferr, 8059, "qh_meminitbuffers: memory initialized with alignment %d\n", alignment);
} /* meminitbuffers */

/*---------------------------------

  qh_memsetup( )
    set up memory after running memsize()
*/
void qh_memsetup(void) {
  int k,i;

  qsort(qhmem.sizetable, (size_t)qhmem.TABLEsize, sizeof(int), qh_intcompare);
  qhmem.LASTsize= qhmem.sizetable[qhmem.TABLEsize-1];
  if (qhmem.LASTsize >= qhmem.BUFsize || qhmem.LASTsize >= qhmem.BUFinit) {
    qh_fprintf(qhmem.ferr, 6087, "qhull error (qh_memsetup): largest mem size %d is >= buffer size %d or initial buffer size %d\n",
            qhmem.LASTsize, qhmem.BUFsize, qhmem.BUFinit);
    qh_errexit(qhmem_ERRmem, NULL, NULL);
  }
  if (!(qhmem.indextable= (int *)qh_malloc((size_t)(qhmem.LASTsize+1) * sizeof(int)))) {
    qh_fprintf(qhmem.ferr, 6088, "qhull error (qh_memsetup): insufficient memory\n");
    qh_errexit(qhmem_ERRmem, NULL, NULL);
  }
  for (k=qhmem.LASTsize+1; k--; )
    qhmem.indextable[k]= k;
  i= 0;
  for (k=0; k <= qhmem.LASTsize; k++) {
    if (qhmem.indextable[k] <= qhmem.sizetable[i])
      qhmem.indextable[k]= i;
    else
      qhmem.indextable[k]= ++i;
  }
} /* memsetup */

/*---------------------------------

  qh_memsize( size )
    define a free list for this size
*/
void qh_memsize(int size) {
  int k;

  if (qhmem.LASTsize) {
    qh_fprintf(qhmem.ferr, 6089, "qhull internal error (qh_memsize): qh_memsize called after qh_memsetup\n");
    qh_errexit(qhmem_ERRqhull, NULL, NULL);
  }
  size= (size + qhmem.ALIGNmask) & ~qhmem.ALIGNmask;
  if (qhmem.IStracing >= 3)
    qh_fprintf(qhmem.ferr, 3078, "qh_memsize: quick memory of %d bytes\n", size);
  for (k=qhmem.TABLEsize; k--; ) {
    if (qhmem.sizetable[k] == size)
      return;
  }
  if (qhmem.TABLEsize < qhmem.NUMsizes)
    qhmem.sizetable[qhmem.TABLEsize++]= size;
  else
    qh_fprintf(qhmem.ferr, 7060, "qhull warning (qh_memsize): free list table has room for only %d sizes\n", qhmem.NUMsizes);
} /* memsize */


/*---------------------------------

  qh_memstatistics( fp )
    print out memory statistics

    Verifies that qhmem.totfree == sum of freelists
*/
void qh_memstatistics(FILE *fp) {
  int i;
  int count;
  void *object;

  qh_memcheck();
  qh_fprintf(fp, 9278, "\nmemory statistics:\n\
%7d quick allocations\n\
%7d short allocations\n\
%7d long allocations\n\
%7d short frees\n\
%7d long frees\n\
%7d bytes of short memory in use\n\
%7d bytes of short memory in freelists\n\
%7d bytes of dropped short memory\n\
%7d bytes of unused short memory (estimated)\n\
%7d bytes of long memory allocated (max, except for input)\n\
%7d bytes of long memory in use (in %d pieces)\n\
%7d bytes of short memory buffers (minus links)\n\
%7d bytes per short memory buffer (initially %d bytes)\n",
           qhmem.cntquick, qhmem.cntshort, qhmem.cntlong,
           qhmem.freeshort, qhmem.freelong,
           qhmem.totshort, qhmem.totfree,
           qhmem.totdropped + qhmem.freesize, qhmem.totunused,
           qhmem.maxlong, qhmem.totlong, qhmem.cntlong - qhmem.freelong,
           qhmem.totbuffer, qhmem.BUFsize, qhmem.BUFinit);
  if (qhmem.cntlarger) {
    qh_fprintf(fp, 9279, "%7d calls to qh_setlarger\n%7.2g     average copy size\n",
           qhmem.cntlarger, ((double)qhmem.totlarger)/(double)qhmem.cntlarger);
    qh_fprintf(fp, 9280, "  freelists(bytes->count):");
  }
  for (i=0; i < qhmem.TABLEsize; i++) {
    count=0;
    for (object= qhmem.freelists[i]; object; object= *((void **)object))
      count++;
    qh_fprintf(fp, 9281, " %d->%d", qhmem.sizetable[i], count);
  }
  qh_fprintf(fp, 9282, "\n\n");
} /* memstatistics */


/*---------------------------------

  qh_NOmem
    turn off quick-fit memory allocation

  notes:
    uses qh_malloc() and qh_free() instead
*/
#else /* qh_NOmem */

void *qh_memalloc(int insize) {
  void *object;

  if (!(object= qh_malloc((size_t)insize))) {
    qh_fprintf(qhmem.ferr, 6090, "qhull error (qh_memalloc): insufficient memory\n");
    qh_errexit(qhmem_ERRmem, NULL, NULL);
  }
  qhmem.cntlong++;
  qhmem.totlong += insize;
  if (qhmem.maxlong < qhmem.totlong)
      qhmem.maxlong= qhmem.totlong;
  if (qhmem.IStracing >= 5)
    qh_fprintf(qhmem.ferr, 8060, "qh_mem %p n %8d alloc long: %d bytes (tot %d cnt %d)\n", object, qhmem.cntlong+qhmem.freelong, insize, qhmem.totlong, qhmem.cntlong-qhmem.freelong);
  return object;
}

void qh_memcheck(void) {
}

void qh_memfree(void *object, int insize) {

  if (!object)
    return;
  qh_free(object);
  qhmem.freelong++;
  qhmem.totlong -= insize;
  if (qhmem.IStracing >= 5)
    qh_fprintf(qhmem.ferr, 8061, "qh_mem %p n %8d free long: %d bytes (tot %d cnt %d)\n", object, qhmem.cntlong+qhmem.freelong, insize, qhmem.totlong, qhmem.cntlong-qhmem.freelong);
}

void qh_memfreeshort(int *curlong, int *totlong) {
  *totlong= qhmem.totlong;
  *curlong= qhmem.cntlong - qhmem.freelong;
  memset((char *)&qhmem, 0, sizeof(qhmem));  /* every field is 0, FALSE, NULL */
}

void qh_meminit(FILE *ferr) {

  memset((char *)&qhmem, 0, sizeof(qhmem));  /* every field is 0, FALSE, NULL */
  if (ferr)
      qhmem.ferr= ferr;
  else
      qhmem.ferr= stderr;
  if (sizeof(void *) < sizeof(int)) {
    qh_fprintf(qhmem.ferr, 6091, "qhull internal error (qh_meminit): sizeof(void *) %d < sizeof(int) %d.  qset.c will not work\n", (int)sizeof(void*), (int)sizeof(int));
    qh_errexit(qhmem_ERRqhull, NULL, NULL);
  }
}

void qh_meminitbuffers(int tracelevel, int alignment, int numsizes, int bufsize, int bufinit) {

  qhmem.IStracing= tracelevel;
}

void qh_memsetup(void) {
}

void qh_memsize(int size) {
}

void qh_memstatistics(FILE *fp) {

  qh_fprintf(fp, 9409, "\nmemory statistics:\n\
%7d long allocations\n\
%7d long frees\n\
%7d bytes of long memory allocated (max, except for input)\n\
%7d bytes of long memory in use (in %d pieces)\n",
           qhmem.cntlong,
           qhmem.freelong,
           qhmem.maxlong, qhmem.totlong, qhmem.cntlong - qhmem.freelong);
}

#endif /* qh_NOmem */

/*---------------------------------

  qh_memtotal( totlong, curlong, totshort, curshort, maxlong, totbuffer )
    Return the total, allocated long and short memory

  returns:
    Returns the total current bytes of long and short allocations
    Returns the current count of long and short allocations
    Returns the maximum long memory and total short buffer (minus one link per buffer)
    Does not error (for deprecated UsingLibQhull.cpp in libqhullpcpp)
*/
void qh_memtotal(int *totlong, int *curlong, int *totshort, int *curshort, int *maxlong, int *totbuffer) {
    *totlong= qhmem.totlong;
    *curlong= qhmem.cntlong - qhmem.freelong;
    *totshort= qhmem.totshort;
    *curshort= qhmem.cntshort + qhmem.cntquick - qhmem.freeshort;
    *maxlong= qhmem.maxlong;
    *totbuffer= qhmem.totbuffer;
} /* memtotlong */

qhull-2020.2/src/libqhull/mem.h0000644060175106010010000002110413661631132014520 0ustar  bbarber/*
  ---------------------------------

   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-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull/mem.h#2 $$Change: 2953 $
   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
*/

#ifndef qhDEFmem
#define qhDEFmem 1

#include 

/*---------------------------------

  qh_NOmem
    turn off quick-fit memory allocation

  notes:
    mem.c implements Quickfit memory allocation for about 20% time
    savings.  If it fails on your machine, try to locate the
    problem, and send the answer to qhull@qhull.org.  If this can
    not be done, define qh_NOmem to use malloc/free instead.

  #define qh_NOmem
*/

/*---------------------------------

qh_TRACEshort
Trace short and quick memory allocations at T5

*/
#define qh_TRACEshort

/*-------------------------------------------
    to avoid bus errors, memory allocation must consider alignment requirements.
    malloc() automatically takes care of alignment.   Since mem.c manages
    its own memory, we need to explicitly specify alignment in
    qh_meminitbuffers().

    A safe choice is sizeof(double).  sizeof(float) may be used if doubles
    do not occur in data structures and pointers are the same size.  Be careful
    of machines (e.g., DEC Alpha) with large pointers.  If gcc is available,
    use __alignof__(double) or fmax_(__alignof__(float), __alignof__(void *)).

   see qh_MEMalign in user.h for qhull's alignment
*/

#define qhmem_ERRmem 4    /* matches qh_ERRmem in libqhull.h */
#define qhmem_ERRqhull 5  /* matches qh_ERRqhull in libqhull.h */

/*----------------------------------

  ptr_intT
    for casting a void * to an integer-type that holds a pointer
    Used for integer expressions (e.g., computing qh_gethash() in poly.c)

  notes:
    WARN64 -- these notes indicate 64-bit issues
    On 64-bit machines, a pointer may be larger than an 'int'.
    qh_meminit()/mem.c checks that 'ptr_intT' holds a 'void*'
    ptr_intT is typically a signed value, but not necessarily so
    size_t is typically unsigned, but should match the parameter type
    Qhull uses int instead of size_t except for system calls such as malloc, qsort, qh_malloc, etc.
    This matches Qt convention and is easier to work with.
*/
#if (defined(__MINGW64__)) && defined(_WIN64)
typedef long long ptr_intT;
#elif defined(_MSC_VER) && defined(_WIN64)
typedef long long ptr_intT;
#else
typedef long ptr_intT;
#endif

/*----------------------------------

  qhmemT
    global memory structure for mem.c

 notes:
   users should ignore qhmem except for writing extensions
   qhmem is allocated in mem.c

   qhmem could be swapable like qh and qhstat, but then
   multiple qh's and qhmem's would need to keep in synch.
   A swapable qhmem would also waste memory buffers.  As long
   as memory operations are atomic, there is no problem with
   multiple qh structures being active at the same time.
   If you need separate address spaces, you can swap the
   contents of qhmem.
*/
typedef struct qhmemT qhmemT;
extern qhmemT qhmem;

#ifndef DEFsetT
#define DEFsetT 1
typedef struct setT setT;          /* defined in qset.h */
#endif

/* mem.c -- Update static initializer list for qhmem if add or remove fields */
struct qhmemT {               /* global memory management variables */
  int      BUFsize;           /* size of memory allocation buffer */
  int      BUFinit;           /* initial size of memory allocation buffer */
  int      TABLEsize;         /* actual number of sizes in free list table */
  int      NUMsizes;          /* maximum number of sizes in free list table */
  int      LASTsize;          /* last size in free list table */
  int      ALIGNmask;         /* worst-case alignment, must be 2^n-1 */
  void   **freelists;          /* free list table, linked by offset 0 */
  int     *sizetable;         /* size of each freelist */
  int     *indextable;        /* size->index table */
  void    *curbuffer;         /* current buffer, linked by offset 0 */
  void    *freemem;           /*   free memory in curbuffer */
  int      freesize;          /*   size of freemem in bytes */
  setT    *tempstack;         /* stack of temporary memory, managed by users */
  FILE    *ferr;              /* file for reporting errors when 'qh' may be undefined */
  int      IStracing;         /* =5 if tracing memory allocations */
  int      cntquick;          /* count of quick allocations */
                              /* Note: removing statistics doesn't effect speed */
  int      cntshort;          /* count of short allocations */
  int      cntlong;           /* count of long allocations */
  int      freeshort;         /* count of short memfrees */
  int      freelong;          /* count of long memfrees */
  int      totbuffer;         /* total short memory buffers minus buffer links */
  int      totdropped;        /* total dropped memory at end of short memory buffers (e.g., freesize) */
  int      totfree;           /* total size of free, short memory on freelists */
  int      totlong;           /* total size of long memory in use */
  int      maxlong;           /*   maximum totlong */
  int      totshort;          /* total size of short memory in use */
  int      totunused;         /* total unused short memory (estimated, short size - request size of first allocations) */
  int      cntlarger;         /* count of setlarger's */
  int      totlarger;         /* total copied by setlarger */
};


/*==================== -macros ====================*/

/*----------------------------------

  qh_memalloc_(insize, freelistp, object, type)
    returns object of size bytes
        assumes size<=qhmem.LASTsize and void **freelistp is a temp
*/

#if defined qh_NOmem
#define qh_memalloc_(insize, freelistp, object, type) {\
  (void)freelistp; /* Avoid warnings */ \
  object= (type *)qh_memalloc(insize); }
#elif defined qh_TRACEshort
#define qh_memalloc_(insize, freelistp, object, type) {\
  (void)freelistp; /* Avoid warnings */ \
  object= (type *)qh_memalloc(insize); }
#else /* !qh_NOmem */

#define qh_memalloc_(insize, freelistp, object, type) {\
  freelistp= qhmem.freelists + qhmem.indextable[insize];\
  if ((object= (type *)*freelistp)) {\
    qhmem.totshort += qhmem.sizetable[qhmem.indextable[insize]]; \
    qhmem.totfree -= qhmem.sizetable[qhmem.indextable[insize]]; \
    qhmem.cntquick++;  \
    *freelistp= *((void **)*freelistp);\
  }else object= (type *)qh_memalloc(insize);}
#endif

/*----------------------------------

  qh_memfree_(object, insize, freelistp)
    free up an object

  notes:
    object may be NULL
    assumes size<=qhmem.LASTsize and void **freelistp is a temp
*/
#if defined qh_NOmem
#define qh_memfree_(object, insize, freelistp) {\
  (void)freelistp; /* Avoid warnings */ \
  qh_memfree(object, insize); }
#elif defined qh_TRACEshort
#define qh_memfree_(object, insize, freelistp) {\
  (void)freelistp; /* Avoid warnings */ \
  qh_memfree(object, insize); }
#else /* !qh_NOmem */

#define qh_memfree_(object, insize, freelistp) {\
  if (object) { \
    qhmem.freeshort++;\
    freelistp= qhmem.freelists + qhmem.indextable[insize];\
    qhmem.totshort -= qhmem.sizetable[qhmem.indextable[insize]]; \
    qhmem.totfree += qhmem.sizetable[qhmem.indextable[insize]]; \
    *((void **)object)= *freelistp;\
    *freelistp= object;}}
#endif

/*=============== prototypes in alphabetical order ============*/

void *qh_memalloc(int insize);
void qh_memcheck(void);
void qh_memfree(void *object, int insize);
void qh_memfreeshort(int *curlong, int *totlong);
void qh_meminit(FILE *ferr);
void qh_meminitbuffers(int tracelevel, int alignment, int numsizes,
                        int bufsize, int bufinit);
void qh_memsetup(void);
void qh_memsize(int size);
void qh_memstatistics(FILE *fp);
void qh_memtotal(int *totlong, int *curlong, int *totshort, int *curshort, int *maxlong, int *totbuffer);

#endif /* qhDEFmem */
qhull-2020.2/src/libqhull/merge.c0000644060175106010010000064360213662355034015056 0ustar  bbarber/*
  ---------------------------------

   merge.c
   merges non-convex facets

   see qh-merge.htm and merge.h

   other modules call qh_premerge() and qh_postmerge()

   the user may call qh_postmerge() to perform additional merges.

   To remove deleted facets and vertices (qhull() in libqhull.c):
     qh_partitionvisible(!qh_ALL, &numoutside);  // visible_list, newfacet_list
     qh_deletevisible();         // qh.visible_list
     qh_resetlists(False, qh_RESETvisible);       // qh.visible_list newvertex_list newfacet_list

   assumes qh.CENTERtype= centrum

   merges occur in qh_mergefacet and in qh_mergecycle
   vertex->neighbors not set until the first merge occurs

   Copyright (c) 1993-2020 C.B. Barber.
   $Id: //main/2019/qhull/src/libqhull/merge.c#12 $$Change: 2958 $
   $DateTime: 2020/05/26 16:17:49 $$Author: bbarber $
*/

#include "qhull_a.h"

#ifndef qh_NOmerge

/* MRGnone, etc. */
const char *mergetypes[]= {
  "none",
  "coplanar",
  "anglecoplanar",
  "concave",
  "concavecoplanar",
  "twisted",
  "flip",
  "dupridge",
  "subridge",
  "vertices",
  "degen",
  "redundant",
  "mirror",
  "coplanarhorizon",
};

/*===== functions(alphabetical after premerge and postmerge) ======*/

/*---------------------------------

  qh_premerge( apexpointid, maxcentrum )
    pre-merge nonconvex facets in qh.newfacet_list for apexpointid
    maxcentrum defines coplanar and concave (qh_test_appendmerge)

  returns:
    deleted facets added to qh.visible_list with facet->visible set

  notes:
    only called by qh_addpoint
    uses globals, qh.MERGEexact, qh.PREmerge

  design:
    mark dupridges in qh.newfacet_list
    merge facet cycles in qh.newfacet_list
    merge dupridges 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(int apexpointid, realT maxcentrum, realT maxangle /* qh.newfacet_list */) {
  boolT othermerge= False;

  if (qh ZEROcentrum && qh_checkzero(!qh_ALL))
    return;
  trace2((qh ferr, 2008, "qh_premerge: premerge centrum %2.2g angle %4.4g for apex p%d newfacet_list f%d\n",
            maxcentrum, maxangle, apexpointid, getid_(qh newfacet_list)));
  if (qh IStracing >= 4 && qh num_facets < 100)
    qh_printlists();
  qh centrum_radius= maxcentrum;
  qh cos_max= maxangle;
  if (qh hull_dim >=3) {
    qh_mark_dupridges(qh newfacet_list, qh_ALL); /* facet_mergeset */
    qh_mergecycle_all(qh newfacet_list, &othermerge);
    qh_forcedmerges(&othermerge /* qh.facet_mergeset */);
  }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);
  }
} /* premerge */

/*---------------------------------

  qh_postmerge( reason, maxcentrum, maxangle, vneighbors )
    post-merge nonconvex facets as defined by maxcentrum and maxangle
    'reason' is for reporting progress
    if vneighbors ('Qv'),
      calls qh_test_vneighbors at end of qh_all_merge from qh_postmerge

  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:
    called by qh_qhull after qh_buildhull
    called if a merge may be needed due to
      qh.MERGEexact ('Qx'), qh_DIMreduceBuild, POSTmerge (e.g., 'Cn'), or TESTvneighbors ('Qv')
    if firstmerge,
      calls qh_reducevertices before qh_getmergeset

  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 occurred
        set vertex->delridge {will retest the ridge}
        if qh.MERGEexact
          call qh_reducevertices()
      if no pre-merging
        merge flipped facets
    determine non-convex facets
    merge all non-convex facets
*/
void qh_postmerge(const char *reason, realT maxcentrum, realT maxangle,
                      boolT vneighbors) {
  facetT *newfacet;
  boolT othermerges= False;
  vertexT *vertex;

  if (qh REPORTfreq || qh IStracing) {
    qh_buildtracing(NULL, NULL);
    qh_printsummary(qh ferr);
    if (qh PRINTstatistics)
      qh_printallstatistics(qh ferr, "reason");
    qh_fprintf(qh ferr, 8062, "\n%s with 'C%.2g' and 'A%.2g'\n",
        reason, maxcentrum, maxangle);
  }
  trace2((qh ferr, 2009, "qh_postmerge: postmerge.  test vneighbors? %d\n",
            vneighbors));
  qh centrum_radius= maxcentrum;
  qh cos_max= maxangle;
  qh POSTmerging= True;
  if (qh visible_list != qh facet_list) {  /* first call due to qh_buildhull, multiple calls if qh.POSTmerge */
    qh NEWfacets= True;
    qh visible_list= qh newfacet_list= qh facet_list;
    FORALLnew_facets {              /* all facets are new facets for qh_postmerge */
      newfacet->newfacet= True;
       if (!newfacet->simplicial)
        newfacet->newmerge= True;   /* test f.vertices for 'delridge'.  'newmerge' was cleared at end of qh_all_merges */
     zinc_(Zpostfacets);
    }
    qh newvertex_list= qh vertex_list;
    FORALLvertices
      vertex->newfacet= True;
    if (qh VERTEXneighbors) {  /* a merge has occurred */
      if (qh MERGEexact && qh hull_dim <= qh_DIMreduceBuild)
        qh_reducevertices();  /* qh_all_merges did not call qh_reducevertices for v.delridge */
    }
    if (!qh PREmerge && !qh MERGEexact)
      qh_flippedmerges(qh newfacet_list, &othermerges);
  }
  qh_getmergeset_initial(qh newfacet_list);
  qh_all_merges(False, vneighbors); /* calls qh_reducevertices before exiting */
  FORALLnew_facets
    newfacet->newmerge= False;   /* Was True if no vertex in f.vertices was 'delridge' */
} /* post_merge */

/*---------------------------------

  qh_all_merges( othermerge, vneighbors )
    merge all non-convex facets

    set othermerge if already merged facets (calls qh_reducevertices)
    if vneighbors ('Qv' at qh.POSTmerge)
      tests vertex neighbors for convexity at end (qh_test_vneighbors)
    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 implicit argument since merges call qh_removefacet()
    [apr'19] restored qh_setdellast in place of qh_next_facetmerge.  Much faster for post-merge

  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 qh.POSTmerging
          periodically call qh_reducevertices to reduce extra vertices and redundant vertices
      after each pass, if qh.VERTEXneighbors
        if qh.POSTmerging or was a merge with qh.hull_dim<=5
          call qh_reducevertices
          update qh.facet_mergeset if degenredundant merges
      if 'Qv' and qh.POSTmerging
        test vertex neighbors for convexity
*/
void qh_all_merges(boolT othermerge, boolT vneighbors) {
  facetT *facet1, *facet2, *newfacet;
  mergeT *merge;
  boolT wasmerge= False, isreduce;
  void **freelistp;  /* used if !qh_NOmem by qh_memfree_() */
  vertexT *vertex;
  realT angle, distance;
  mergeType mergetype;
  int numcoplanar=0, numconcave=0, numconcavecoplanar= 0, numdegenredun= 0, numnewmerges= 0, numtwisted= 0;

  trace2((qh ferr, 2010, "qh_all_merges: starting to merge %d facet and %d degenerate merges for new facets f%d, othermerge? %d\n",
            qh_setsize(qh facet_mergeset), qh_setsize(qh degen_mergeset), getid_(qh newfacet_list), othermerge));

  while (True) {
    wasmerge= False;
    while (qh_setsize(qh facet_mergeset) > 0 || qh_setsize(qh degen_mergeset) > 0) {
      if (qh_setsize(qh degen_mergeset) > 0) {
        numdegenredun += qh_merge_degenredundant();
        wasmerge= True;
      }
      while ((merge= (mergeT *)qh_setdellast(qh facet_mergeset))) {
        facet1= merge->facet1;
        facet2= merge->facet2;
        vertex= merge->vertex1;  /* not used for qh.facet_mergeset*/
        mergetype= merge->mergetype;
        angle= merge->angle;
        distance= merge->distance;
        qh_memfree_(merge, (int)sizeof(mergeT), freelistp);   /* 'merge' is invalid */
        if (facet1->visible || facet2->visible) {
          trace3((qh ferr, 3045, "qh_all_merges: drop merge of f%d (del? %d) into f%d (del? %d) mergetype %d, dist %4.4g, angle %4.4g.  One or both facets is deleted\n",
            facet1->id, facet1->visible, facet2->id, facet2->visible, mergetype, distance, angle));
          continue;
        }else if (mergetype == MRGcoplanar || mergetype == MRGanglecoplanar) {
          if (qh MERGEindependent) {
            if ((!facet1->tested && facet1->newfacet)
            || (!facet2->tested && facet2->newfacet)) {
              trace3((qh ferr, 3064, "qh_all_merges: drop merge of f%d (tested? %d) into f%d (tested? %d) mergetype %d, dist %2.2g, angle %4.4g.  Merge independent sets of coplanar merges\n",
                facet1->id, facet1->visible, facet2->id, facet2->visible, mergetype, distance, angle));
              continue;
            }
          }
        }
        trace3((qh ferr, 3047, "qh_all_merges: merge f%d and f%d type %d dist %2.2g angle %4.4g\n",
          facet1->id, facet2->id, mergetype, distance, angle));
        if (mergetype == MRGtwisted)
          qh_merge_twisted(facet1, facet2);
        else
          qh_merge_nonconvex(facet1, facet2, mergetype);
        numnewmerges++;
        numdegenredun += qh_merge_degenredundant();
        wasmerge= True;
        if (mergetype == MRGconcave)
          numconcave++;
        else if (mergetype == MRGconcavecoplanar)
          numconcavecoplanar++;
        else if (mergetype == MRGtwisted)
          numtwisted++;
        else if (mergetype == MRGcoplanar || mergetype == MRGanglecoplanar)
          numcoplanar++;
        else {
          qh_fprintf(qh ferr, 6394, "qhull internal error (qh_all_merges): expecting concave, coplanar, or twisted merge.  Got merge f%d f%d v%d mergetype %d\n",
            getid_(facet1), getid_(facet2), getid_(vertex), mergetype);
          qh_errexit2(qh_ERRqhull, facet1, facet2);
        }
      } /* while qh_setdellast */
      if (qh POSTmerging && qh hull_dim <= qh_DIMreduceBuild
      && numnewmerges > qh_MAXnewmerges) {
        numnewmerges= 0;
        wasmerge= othermerge= False;
        qh_reducevertices();  /* otherwise large post merges too slow */
      }
      qh_getmergeset(qh newfacet_list); /* qh.facet_mergeset */
    } /* while facet_mergeset or degen_mergeset */
    if (qh VERTEXneighbors) {  /* at least one merge */
      isreduce= False;
      if (qh POSTmerging && qh hull_dim >= 4) {
        isreduce= True;
      }else if (qh POSTmerging || !qh MERGEexact) {
        if ((wasmerge || othermerge) && qh hull_dim > 2 && qh hull_dim <= qh_DIMreduceBuild)
          isreduce= True;
      }
      if (isreduce) {
        wasmerge= othermerge= False;
        if (qh_reducevertices()) {
          qh_getmergeset(qh newfacet_list); /* facet_mergeset */
          continue;
        }
      }
    }
    if (vneighbors && qh_test_vneighbors(/* qh.newfacet_list */))
      continue;
    break;
  } /* while (True) */
  if (wasmerge || othermerge) {
    trace3((qh ferr, 3033, "qh_all_merges: skip qh_reducevertices due to post-merging, no qh.VERTEXneighbors (%d), or hull_dim %d ==2 or >%d\n", qh VERTEXneighbors, qh hull_dim, qh_DIMreduceBuild))
    FORALLnew_facets {
      newfacet->newmerge= False;
    }
  }
  if (qh CHECKfrequently && !qh MERGEexact) {
    qh old_randomdist= qh RANDOMdist;
    qh RANDOMdist= False;
    qh_checkconvex(qh newfacet_list, qh_ALGORITHMfault);
    /* qh_checkconnect(); [this is slow and it changes the facet order] */
    qh RANDOMdist= qh old_randomdist;
  }
  trace1((qh ferr, 1009, "qh_all_merges: merged %d coplanar %d concave %d concavecoplanar %d twisted facets and %d degen or redundant facets.\n",
    numcoplanar, numconcave, numconcavecoplanar, numtwisted, numdegenredun));
  if (qh IStracing >= 4 && qh num_facets < 500)
    qh_printlists();
} /* all_merges */

/*---------------------------------

  qh_all_vertexmerges( apexpointid, facet, &retryfacet )
    merge vertices in qh.vertex_mergeset and subsequent merges

  returns:
    returns retryfacet for facet (if defined)
    updates qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices
    mergesets are empty
    if merges, resets facet lists

  notes:
    called from qh_qhull, qh_addpoint, and qh_buildcone_mergepinched
    vertex merges occur after facet merges and qh_resetlists

  design:
    while merges in vertex_mergeset (MRGvertices)
      merge a pair of pinched vertices
      update vertex neighbors
      merge non-convex and degenerate facets and check for ridges with duplicate vertices
      partition outside points of deleted, "visible" facets
*/
void qh_all_vertexmerges(int apexpointid, facetT *facet, facetT **retryfacet) {
  int numpoints; /* ignore count of partitioned points.  Used by qh_addpoint for Zpbalance */

  if (retryfacet)
    *retryfacet= facet;
  while (qh_setsize(qh vertex_mergeset) > 0) {
    trace1((qh ferr, 1057, "qh_all_vertexmerges: starting to merge %d vertex merges for apex p%d facet f%d\n",
            qh_setsize(qh vertex_mergeset), apexpointid, getid_(facet)));
    if (qh IStracing >= 4  && qh num_facets < 1000)
      qh_printlists();
    qh_merge_pinchedvertices(apexpointid /* qh.vertex_mergeset, visible_list, newvertex_list, newfacet_list */);
    qh_update_vertexneighbors(); /* update neighbors of qh.newvertex_list from qh_newvertices for deleted facets on qh.visible_list */
                           /* test ridges and merge non-convex facets */
    qh_getmergeset(qh newfacet_list);
    qh_all_merges(True, False); /* calls qh_reducevertices */
    if (qh CHECKfrequently)
      qh_checkpolygon(qh facet_list);
    qh_partitionvisible(!qh_ALL, &numpoints /* qh.visible_list qh.del_vertices*/);
    if (retryfacet)
      *retryfacet= qh_getreplacement(*retryfacet);
    qh_deletevisible(/* qh.visible_list  qh.del_vertices*/);
    qh_resetlists(False, qh_RESETvisible /* qh.visible_list newvertex_list qh.newfacet_list */);
    if (qh IStracing >= 4  && qh num_facets < 1000) {
      qh_printlists();
      qh_checkpolygon(qh facet_list);
    }
  }
} /* all_vertexmerges */

/*---------------------------------

  qh_appendmergeset( facet, vertex, neighbor, mergetype, dist, angle )
    appends an entry to qh.facet_mergeset or qh.degen_mergeset
    if 'dist' is unknown, set it to 0.0
        if 'angle' is unknown, set it to 1.0 (coplanar)

  returns:
    merge appended to facet_mergeset or degen_mergeset
      sets ->degenerate or ->redundant if degen_mergeset

  notes:
    caller collects statistics and/or caller of qh_mergefacet
    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 (merged last)
    else if redundant merge
      append to qh.degen_mergeset
*/
void qh_appendmergeset(facetT *facet, facetT *neighbor, mergeType mergetype, coordT dist, realT angle) {
  mergeT *merge, *lastmerge;
  void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */
  const char *mergename;

  if ((facet->redundant && mergetype != MRGmirror) || neighbor->redundant) {
    trace3((qh ferr, 3051, "qh_appendmergeset: f%d is already redundant (%d) or f%d is already redundant (%d).  Ignore merge f%d and f%d type %d\n",
      facet->id, facet->redundant, neighbor->id, neighbor->redundant, facet->id, neighbor->id, mergetype));
    return;
  }
  if (facet->degenerate && mergetype == MRGdegen) {
    trace3((qh ferr, 3077, "qh_appendmergeset: f%d is already degenerate.  Ignore merge f%d type %d (MRGdegen)\n",
      facet->id, facet->id, mergetype));
    return;
  }
  if (!qh facet_mergeset || !qh degen_mergeset) {
    qh_fprintf(qh ferr, 6403, "qhull internal error (qh_appendmergeset): expecting temp set defined for qh.facet_mergeset (0x%x) and qh.degen_mergeset (0x%x).  Got NULL\n",
      qh facet_mergeset, qh degen_mergeset);
    /* otherwise qh_setappend creates a new set that is not freed by qh_freebuild() */
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  if (neighbor->flipped && !facet->flipped) {
    if (mergetype != MRGdupridge) {
      qh_fprintf(qh ferr, 6355, "qhull internal error (qh_appendmergeset): except for MRGdupridge, cannot merge a non-flipped facet f%d into flipped f%d, mergetype %d, dist %4.4g\n",
        facet->id, neighbor->id, mergetype, dist);
      qh_errexit(qh_ERRqhull, NULL, NULL);
    }else {
      trace2((qh ferr, 2106, "qh_appendmergeset: dupridge will merge a non-flipped facet f%d into flipped f%d, dist %4.4g\n",
        facet->id, neighbor->id, dist));
    }
  }
  qh_memalloc_((int)sizeof(mergeT), freelistp, merge, mergeT);
  merge->angle= angle;
  merge->distance= dist;
  merge->facet1= facet;
  merge->facet2= neighbor;
  merge->vertex1= NULL;
  merge->vertex2= NULL;
  merge->ridge1= NULL;
  merge->ridge2= NULL;
  merge->mergetype= mergetype;
  if(mergetype > 0 && mergetype < sizeof(mergetypes)/sizeof(char *))
    mergename= mergetypes[mergetype];
  else
    mergename= mergetypes[MRGnone];
  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->mergetype == MRGdegen)
      qh_setappend(&(qh degen_mergeset), merge);
    else
      qh_setaddnth(&(qh degen_mergeset), 0, merge);    /* merged last */
  }else if (mergetype == MRGredundant) {
    facet->redundant= True;
    qh_setappend(&(qh degen_mergeset), merge);
  }else /* mergetype == MRGmirror */ {
    if (facet->redundant || neighbor->redundant) {
      qh_fprintf(qh ferr, 6092, "qhull internal error (qh_appendmergeset): facet f%d or f%d is already a mirrored facet (i.e., 'redundant')\n",
           facet->id, neighbor->id);
      qh_errexit2(qh_ERRqhull, facet, neighbor);
    }
    if (!qh_setequal(facet->vertices, neighbor->vertices)) {
      qh_fprintf(qh ferr, 6093, "qhull internal 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);
  }
  if (merge->mergetype >= MRGdegen) {
    trace3((qh ferr, 3044, "qh_appendmergeset: append merge f%d and f%d type %d (%s) to qh.degen_mergeset (size %d)\n",
      merge->facet1->id, merge->facet2->id, merge->mergetype, mergename, qh_setsize(qh degen_mergeset)));
  }else {
    trace3((qh ferr, 3027, "qh_appendmergeset: append merge f%d and f%d type %d (%s) dist %2.2g angle %4.4g to qh.facet_mergeset (size %d)\n",
      merge->facet1->id, merge->facet2->id, merge->mergetype, mergename, merge->distance, merge->angle, qh_setsize(qh facet_mergeset)));
  }
} /* appendmergeset */


/*---------------------------------

  qh_appendvertexmerge( vertex, vertex2, mergetype, distance, ridge1, ridge2 )
    appends a vertex merge to qh.vertex_mergeset
    MRGsubridge includes two ridges (from MRGdupridge)
    MRGvertices includes two ridges

  notes:
    called by qh_getpinchedmerges for MRGsubridge
    called by qh_maybe_duplicateridge and qh_maybe_duplicateridges for MRGvertices
    only way to add a vertex merge to qh.vertex_mergeset
    checked by qh_next_vertexmerge
*/
void qh_appendvertexmerge(vertexT *vertex, vertexT *destination, mergeType mergetype, realT distance, ridgeT *ridge1, ridgeT *ridge2) {
  mergeT *merge;
  void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */
  const char *mergename;

  if (!qh vertex_mergeset) {
    qh_fprintf(qh ferr, 6387, "qhull internal error (qh_appendvertexmerge): expecting temp set defined for qh.vertex_mergeset (0x%x).  Got NULL\n",
      qh vertex_mergeset);
    /* otherwise qh_setappend creates a new set that is not freed by qh_freebuild() */
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  qh_memalloc_((int)sizeof(mergeT), freelistp, merge, mergeT);
  merge->angle= qh_ANGLEnone;
  merge->distance= distance;
  merge->facet1= NULL;
  merge->facet2= NULL;
  merge->vertex1= vertex;
  merge->vertex2= destination;
  merge->ridge1= ridge1;
  merge->ridge2= ridge2;
  merge->mergetype= mergetype;
  if(mergetype > 0 && mergetype < sizeof(mergetypes)/sizeof(char *))
    mergename= mergetypes[mergetype];
  else
    mergename= mergetypes[MRGnone];
  if (mergetype == MRGvertices) {
    if (!ridge1 || !ridge2 || ridge1 == ridge2) {
      qh_fprintf(qh ferr, 6106, "qhull internal error (qh_appendvertexmerge): expecting two distinct ridges for MRGvertices.  Got r%d r%d\n",
        getid_(ridge1), getid_(ridge2));
      qh_errexit(qh_ERRqhull, NULL, ridge1);
    }
  }
  qh_setappend(&(qh vertex_mergeset), merge);
  trace3((qh ferr, 3034, "qh_appendvertexmerge: append merge v%d into v%d r%d r%d dist %2.2g type %d (%s)\n",
    vertex->id, destination->id, getid_(ridge1), getid_(ridge2), distance, merge->mergetype, mergename));
} /* appendvertexmerge */


/*---------------------------------

  qh_basevertices( samecycle )
    return temporary set of base vertices for samecycle
    samecycle is first facet in the cycle
    assumes apex is SETfirst_( samecycle->vertices )

  returns:
    vertices(settemp)
    all ->seen are cleared

  notes:
    uses qh_vertex_visit;

  design:
    for each facet in samecycle
      for each unseen vertex in facet->vertices
        append to result
*/
setT *qh_basevertices(facetT *samecycle) {
  facetT *same;
  vertexT *apex, *vertex, **vertexp;
  setT *vertices= qh_settemp(qh TEMPsize);

  apex= SETfirstt_(samecycle->vertices, vertexT);
  apex->visitid= ++qh vertex_visit;
  FORALLsame_cycle_(samecycle) {
    if (same->mergeridge)
      continue;
    FOREACHvertex_(same->vertices) {
      if (vertex->visitid != qh vertex_visit) {
        qh_setappend(&vertices, vertex);
        vertex->visitid= qh vertex_visit;
        vertex->seen= False;
      }
    }
  }
  trace4((qh ferr, 4019, "qh_basevertices: found %d vertices\n",
         qh_setsize(vertices)));
  return vertices;
} /* basevertices */

/*---------------------------------

  qh_check_dupridge( facet1, dist1, facet2, dist2 )
    Check dupridge between facet1 and facet2 for wide merge
    dist1 is the maximum distance of facet1's vertices to facet2
    dist2 is the maximum distance of facet2's vertices to facet1

  returns
    Level 1 log of the dupridge with the minimum distance between vertices
    Throws error if the merge will increase the maximum facet width by qh_WIDEduplicate (100x)

  notes:
    only called from qh_forcedmerges
*/
void qh_check_dupridge(facetT *facet1, realT dist1, facetT *facet2, realT dist2) {
  vertexT *vertex, **vertexp, *vertexA, **vertexAp;
  realT dist, innerplane, mergedist, outerplane, prevdist, ratio, vertexratio;
  realT minvertex= REALmax;

  mergedist= fmin_(dist1, dist2);
  qh_outerinner(NULL, &outerplane, &innerplane);  /* ratio from qh_printsummary */
  FOREACHvertex_(facet1->vertices) {     /* The dupridge is between facet1 and facet2, so either facet can be tested */
    FOREACHvertexA_(facet1->vertices) {
      if (vertex > vertexA){   /* Test each pair once */
        dist= qh_pointdist(vertex->point, vertexA->point, qh hull_dim);
        minimize_(minvertex, dist);
        /* Not quite correct.  A facet may have a dupridge and another pair of nearly adjacent vertices. */
      }
    }
  }
  prevdist= fmax_(outerplane, innerplane);
  maximize_(prevdist, qh ONEmerge + qh DISTround);
  maximize_(prevdist, qh MINoutside + qh DISTround);
  ratio= mergedist/prevdist;
  vertexratio= minvertex/prevdist;
  trace0((qh ferr, 16, "qh_check_dupridge: dupridge between f%d and f%d (vertex dist %2.2g), dist %2.2g, reverse dist %2.2g, ratio %2.2g while processing p%d\n",
        facet1->id, facet2->id, minvertex, dist1, dist2, ratio, qh furthest_id));
  if (ratio > qh_WIDEduplicate) {
    qh_fprintf(qh ferr, 6271, "qhull topology error (qh_check_dupridge): wide merge (%.1fx wider) due to dupridge between f%d and f%d (vertex dist %2.2g), merge dist %2.2g, while processing p%d\n- Allow error with option 'Q12'\n",
      ratio, facet1->id, facet2->id, minvertex, mergedist, qh furthest_id);
    if (vertexratio < qh_WIDEpinched)
      qh_fprintf(qh ferr, 8145, "- Experimental option merge-pinched-vertices ('Q14') may avoid this error.  It merges nearly adjacent vertices.\n");
    if (qh DELAUNAY)
      qh_fprintf(qh ferr, 8145, "- A bounding box for the input sites may alleviate this error.\n");
    if (!qh ALLOWwide)
      qh_errexit2(qh_ERRwide, facet1, facet2);
  }
} /* check_dupridge */

/*---------------------------------

  qh_checkconnect( )
    check that new facets are connected
    new facets are on qh.newfacet_list

  notes:
    this is slow and it changes the order of the facets
    uses qh.visit_id

  design:
    move first new facet to end of qh.facet_list
    for all newly appended facets
      append unvisited neighbors to end of qh.facet_list
    for all new facets
      report error if unvisited
*/
void qh_checkconnect(void /* qh.newfacet_list */) {
  facetT *facet, *newfacet, *errfacet= NULL, *neighbor, **neighborp;

  facet= qh newfacet_list;
  qh_removefacet(facet);
  qh_appendfacet(facet);
  facet->visitid= ++qh visit_id;
  FORALLfacet_(facet) {
    FOREACHneighbor_(facet) {
      if (neighbor->visitid != qh visit_id) {
        qh_removefacet(neighbor);
        qh_appendfacet(neighbor);
        neighbor->visitid= qh visit_id;
      }
    }
  }
  FORALLnew_facets {
    if (newfacet->visitid == qh visit_id)
      break;
    qh_fprintf(qh ferr, 6094, "qhull internal error (qh_checkconnect): f%d is not attached to the new facets\n",
         newfacet->id);
    errfacet= newfacet;
  }
  if (errfacet)
    qh_errexit(qh_ERRqhull, errfacet, NULL);
} /* checkconnect */

/*---------------------------------

  qh_checkdelfacet( facet, mergeset )
    check that mergeset does not reference facet

*/
void qh_checkdelfacet(facetT *facet, setT *mergeset) {
  mergeT *merge, **mergep;

  FOREACHmerge_(mergeset) {
    if (merge->facet1 == facet || merge->facet2 == facet) {
      qh_fprintf(qh ferr, 6390, "qhull internal error (qh_checkdelfacet): cannot delete f%d.  It is referenced by merge f%d f%d mergetype %d\n",
        facet->id, merge->facet1->id, getid_(merge->facet2), merge->mergetype);
      qh_errexit2(qh_ERRqhull, merge->facet1, merge->facet2);
    }
  }
} /* checkdelfacet */

/*---------------------------------

  qh_checkdelridge( )
    check that qh_delridge_merge is not needed for deleted ridges

    notes:
      called from qh_mergecycle, qh_makenewfacets, qh_attachnewfacets
      errors if qh.vertex_mergeset is non-empty
      errors if any visible or new facet has a ridge with r.nonconvex set
      assumes that vertex.delfacet is not needed
*/
void qh_checkdelridge(void /* qh.visible_facets, vertex_mergeset */) {
  facetT *newfacet, *visible;
  ridgeT *ridge, **ridgep;

  if (!SETempty_(qh vertex_mergeset)) {
    qh_fprintf(qh ferr, 6382, "qhull internal error (qh_checkdelridge): expecting empty qh.vertex_mergeset in order to avoid calling qh_delridge_merge.  Got %d merges\n", qh_setsize(qh vertex_mergeset));
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }

  FORALLnew_facets {
    FOREACHridge_(newfacet->ridges) {
      if (ridge->nonconvex) {
        qh_fprintf(qh ferr, 6313, "qhull internal error (qh_checkdelridge): unexpected 'nonconvex' flag for ridge r%d in newfacet f%d.  Otherwise need to call qh_delridge_merge\n",
           ridge->id, newfacet->id);
        qh_errexit(qh_ERRqhull, newfacet, ridge);
      }
    }
  }

  FORALLvisible_facets {
    FOREACHridge_(visible->ridges) {
      if (ridge->nonconvex) {
        qh_fprintf(qh ferr, 6385, "qhull internal error (qh_checkdelridge): unexpected 'nonconvex' flag for ridge r%d in visible facet f%d.  Otherwise need to call qh_delridge_merge\n",
          ridge->id, visible->id);
        qh_errexit(qh_ERRqhull, visible, ridge);
      }
    }
  }
} /* checkdelridge */


/*---------------------------------

  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:
    called by qh_premerge (qh.CHECKzero, 'C-0') and qh_qhull ('Qx')
    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;
  facetT *horizon, *facetlist;
  int neighbor_i, neighbor_n;
  vertexT *vertex, **vertexp;
  realT dist;

  if (testall)
    facetlist= qh facet_list;
  else {
    facetlist= qh newfacet_list;
    FORALLfacet_(facetlist) {
      horizon= SETfirstt_(facet->neighbors, facetT);
      if (!horizon->simplicial)
        goto LABELproblem;
      if (facet->flipped || facet->dupridge || !facet->normal)
        goto LABELproblem;
    }
    if (qh MERGEexact && qh ZEROall_ok) {
      trace2((qh ferr, 2011, "qh_checkzero: skip convexity check until first pre-merge\n"));
      return True;
    }
  }
  FORALLfacet_(facetlist) {
    qh vertex_visit++;
    horizon= NULL;
    FOREACHneighbor_i_(facet) {
      if (!neighbor_i && !testall) {
        horizon= neighbor;
        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 >= -2 * qh DISTround) {  /* need 2x for qh_distround and 'Rn' for qh_checkconvex, same as qh.premerge_centrum */
        qh ZEROall_ok= False;
        if (!qh MERGEexact || testall || dist > qh DISTround)
          goto LABELnonconvex;
      }
    }
    if (!testall && horizon) {
      FOREACHvertex_(horizon->vertices) {
        if (vertex->visitid != qh vertex_visit) {
          zzinc_(Zdistzero);
          qh_distplane(vertex->point, facet, &dist);
          if (dist >= -2 * qh DISTround) {
            qh ZEROall_ok= False;
            if (!qh MERGEexact || dist > qh DISTround)
              goto LABELnonconvexhorizon;
          }
          break;
        }
      }
    }
  }
  trace2((qh ferr, 2012, "qh_checkzero: testall %d, facets are %s\n", testall,
        (qh MERGEexact && !testall) ?
           "not concave, flipped, or dupridge" : "clearly convex"));
  return True;

 LABELproblem:
  qh ZEROall_ok= False;
  trace2((qh ferr, 2013, "qh_checkzero: qh_premerge is needed.  New facet f%d or its horizon f%d is non-simplicial, flipped, dupridge, or mergehorizon\n",
       facet->id, horizon->id));
  return False;

 LABELnonconvex:
  trace2((qh ferr, 2014, "qh_checkzero: facet f%d and f%d are not clearly convex.  v%d dist %.2g\n",
         facet->id, neighbor->id, vertex->id, dist));
  return False;

 LABELnonconvexhorizon:
  trace2((qh ferr, 2060, "qh_checkzero: facet f%d and horizon f%d are not clearly convex.  v%d dist %.2g\n",
      facet->id, horizon->id, vertex->id, dist));
  return False;
} /* checkzero */

/*---------------------------------

  qh_compare_anglemerge( mergeA, mergeB )
    used by qsort() to order qh.facet_mergeset by mergetype and angle (qh.ANGLEmerge, 'Q1')
    lower numbered mergetypes done first (MRGcoplanar before MRGconcave)

  notes:
    qh_all_merges processes qh.facet_mergeset by qh_setdellast
    [mar'19] evaluated various options with eg/q_benchmark and merging of pinched vertices (Q14)
*/
int qh_compare_anglemerge(const void *p1, const void *p2) {
  const mergeT *a= *((mergeT *const*)p1), *b= *((mergeT *const*)p2);

  if (a->mergetype != b->mergetype)
    return (a->mergetype < b->mergetype ? 1 : -1); /* select MRGcoplanar (1) before MRGconcave (3) */
  else
    return (a->angle > b->angle ? 1 : -1);         /* select coplanar merge (1.0) before sharp merge (-0.5) */
} /* compare_anglemerge */

/*---------------------------------

  qh_compare_facetmerge( mergeA, mergeB )
    used by qsort() to order merges by mergetype, first merge, first
    lower numbered mergetypes done first (MRGcoplanar before MRGconcave)
    if same merge type, flat merges are first

  notes:
    qh_all_merges processes qh.facet_mergeset by qh_setdellast
    [mar'19] evaluated various options with eg/q_benchmark and merging of pinched vertices (Q14)
*/
int qh_compare_facetmerge(const void *p1, const void *p2) {
  const mergeT *a= *((mergeT *const*)p1), *b= *((mergeT *const*)p2);

  if (a->mergetype != b->mergetype)
    return (a->mergetype < b->mergetype ? 1 : -1); /* select MRGcoplanar (1) before MRGconcave (3) */
  else if (a->mergetype == MRGanglecoplanar)
    return (a->angle > b->angle ? 1 : -1);         /* if MRGanglecoplanar, select coplanar merge (1.0) before sharp merge (-0.5) */
  else
    return (a->distance < b->distance ? 1 : -1);   /* select flat (0.0) merge before wide (1e-10) merge */
} /* compare_facetmerge */

/*---------------------------------

  qh_comparevisit( vertexA, vertexB )
    used by qsort() to order vertices by their visitid

  notes:
    only called by qh_find_newvertex
*/
int qh_comparevisit(const void *p1, const void *p2) {
  const vertexT *a= *((vertexT *const*)p1), *b= *((vertexT *const*)p2);

  if (a->visitid > b->visitid)
    return 1;
  return -1;
} /* comparevisit */

/*---------------------------------

  qh_copynonconvex( atridge )
    set non-convex flag on other ridges (if any) between same neighbors

  notes:
    may be faster if use smaller ridge set

  design:
    for each ridge of atridge's top facet
      if ridge shares the same neighbor
        set nonconvex flag
*/
void qh_copynonconvex(ridgeT *atridge) {
  facetT *facet, *otherfacet;
  ridgeT *ridge, **ridgep;

  facet= atridge->top;
  otherfacet= atridge->bottom;
  atridge->nonconvex= False;
  FOREACHridge_(facet->ridges) {
    if (otherfacet == ridge->top || otherfacet == ridge->bottom) {
      if (ridge != atridge) {
        ridge->nonconvex= True;
        trace4((qh ferr, 4020, "qh_copynonconvex: moved nonconvex flag from r%d to r%d between f%d and f%d\n",
                atridge->id, ridge->id, facet->id, otherfacet->id));
        break;
      }
    }
  }
} /* copynonconvex */

/*---------------------------------

  qh_degen_redundant_facet( facet )
    check for a degenerate (too few neighbors) or redundant (subset of vertices) facet

  notes:
    called at end of qh_mergefacet, qh_renamevertex, and qh_reducevertices
    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_test_redundant_neighbors, qh_maydropneighbor

  design:
    test for redundant neighbor
    test for degenerate facet
*/
void qh_degen_redundant_facet(facetT *facet) {
  vertexT *vertex, **vertexp;
  facetT *neighbor, **neighborp;

  trace3((qh ferr, 3028, "qh_degen_redundant_facet: test facet f%d for degen/redundant\n",
          facet->id));
  if (facet->flipped) {
    trace2((qh ferr, 3074, "qh_degen_redundant_facet: f%d is flipped, will merge later\n", facet->id));
    return;
  }
  FOREACHneighbor_(facet) {
    if (neighbor->flipped) /* disallow merge of non-flipped into flipped, neighbor will be merged later */
      continue;
    if (neighbor->visible) {
      qh_fprintf(qh ferr, 6357, "qhull internal error (qh_degen_redundant_facet): facet f%d has deleted neighbor f%d (qh.visible_list)\n",
        facet->id, neighbor->id);
      qh_errexit2(qh_ERRqhull, facet, neighbor);
    }
    qh vertex_visit++;
    FOREACHvertex_(neighbor->vertices)
      vertex->visitid= qh vertex_visit;
    FOREACHvertex_(facet->vertices) {
      if (vertex->visitid != qh vertex_visit)
        break;
    }
    if (!vertex) {
      trace2((qh ferr, 2015, "qh_degen_redundant_facet: f%d is contained in f%d.  merge\n", facet->id, neighbor->id));
      qh_appendmergeset(facet, neighbor, MRGredundant, 0.0, 1.0);
      return;
    }
  }
  if (qh_setsize(facet->neighbors) < qh hull_dim) {
    qh_appendmergeset(facet, facet, MRGdegen, 0.0, 1.0);
    trace2((qh ferr, 2016, "qh_degen_redundant_facet: f%d is degenerate.\n", facet->id));
  }
} /* degen_redundant_facet */


/*---------------------------------

  qh_delridge_merge( ridge )
    delete ridge due to a merge

  notes:
    only called by merge.c (qh_mergeridges, qh_renameridgevertex)
    ridges also freed in qh_freeqhull and qh_mergecycle_ridges

  design:
    if needed, moves ridge.nonconvex to another ridge
    sets vertex.delridge for qh_reducevertices
    deletes ridge from qh.vertex_mergeset
    deletes ridge from its neighboring facets
    frees up its memory
*/
void qh_delridge_merge(ridgeT *ridge) {
  vertexT *vertex, **vertexp;
  mergeT *merge;
  int merge_i, merge_n;

  trace3((qh ferr, 3036, "qh_delridge_merge: delete ridge r%d between f%d and f%d\n",
    ridge->id, ridge->top->id, ridge->bottom->id));
  if (ridge->nonconvex)
    qh_copynonconvex(ridge);
  FOREACHvertex_(ridge->vertices)
    vertex->delridge= True;
  FOREACHmerge_i_(qh vertex_mergeset) {
    if (merge->ridge1 == ridge || merge->ridge2 == ridge) {
      trace3((qh ferr, 3029, "qh_delridge_merge: drop merge of v%d into v%d (dist %2.2g r%d r%d) due to deleted, duplicated ridge r%d\n",
        merge->vertex1->id, merge->vertex2->id, merge->distance, merge->ridge1->id, merge->ridge2->id, ridge->id));
      if (merge->ridge1 == ridge)
        merge->ridge2->mergevertex= False;
      else
        merge->ridge1->mergevertex= False;
      qh_setdelnth(qh vertex_mergeset, merge_i);
      merge_i--; merge_n--; /* next merge after deleted */
    }
  }
  qh_setdel(ridge->top->ridges, ridge);
  qh_setdel(ridge->bottom->ridges, ridge);
  qh_delridge(ridge);
} /* delridge_merge */


/*---------------------------------

  qh_drop_mergevertex( merge )

  clear mergevertex flags for ridges of a vertex merge
*/
void qh_drop_mergevertex(mergeT *merge)
{
  if (merge->mergetype == MRGvertices) {
    merge->ridge1->mergevertex= False;
    merge->ridge1->mergevertex2= True;
    merge->ridge2->mergevertex= False;
    merge->ridge2->mergevertex2= True;
    trace3((qh ferr, 3032, "qh_drop_mergevertex: unset mergevertex for r%d and r%d due to dropped vertex merge v%d to v%d.  Sets mergevertex2\n",
      merge->ridge1->id, merge->ridge2->id, merge->vertex1->id, merge->vertex2->id));
  }
} /* drop_mergevertex */

/*---------------------------------

  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 newvertex and oldvertex
    vertices without oldvertex sorted by number of deleted ridges
    qh.vertex_visit updated
    sets v.seen

  notes:
    called by qh_redundant_vertex due to vertex->delridge and qh_rename_sharedvertex
    sets vertex->visitid to 0..setsize() for vertices
    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 ridges
    remove unvisited vertices
    set qh.vertex_visit above all possible values
    sort vertices by number of ridges (minimize ridges that need renaming
    add each ridge to qh.hash_table
    for each vertex in vertices
      find the first 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;
  unsigned int maxvisit;

#ifndef qh_NOtrace
  if (qh IStracing >= 4) {
    qh_fprintf(qh ferr, 8063, "qh_find_newvertex: find new vertex for v%d from ",
             oldvertex->id);
    FOREACHvertex_(vertices)
      qh_fprintf(qh ferr, 8064, "v%d ", vertex->id);
    FOREACHridge_(ridges)
      qh_fprintf(qh ferr, 8065, "r%d ", ridge->id);
    qh_fprintf(qh ferr, 8066, "\n");
  }
#endif
  FOREACHridge_(ridges) {
    FOREACHvertex_(ridge->vertices)
      vertex->seen= False;
  }
  FOREACHvertex_(vertices) {
    vertex->visitid= 0;  /* v.visitid will be number of ridges */
    vertex->seen= True;
  }
  FOREACHridge_(ridges) {
    FOREACHvertex_(ridge->vertices) {
      if (vertex->seen)
        vertex->visitid++;
    }
  }
  FOREACHvertex_(vertices) {
    if (!vertex->visitid) {
      qh_setdelnth(vertices, SETindex_(vertices,vertex));
      vertexp--; /* repeat since deleted this vertex */
    }
  }
  maxvisit= (unsigned int)qh_setsize(ridges);
  maximize_(qh vertex_visit, maxvisit);
  if (!qh_setsize(vertices)) {
    trace4((qh ferr, 4023, "qh_find_newvertex: vertices not in ridges for v%d\n",
            oldvertex->id));
    return NULL;
  }
  qsort(SETaddr_(vertices, vertexT), (size_t)qh_setsize(vertices),
                sizeof(vertexT *), qh_comparevisit);
  /* can now use qh vertex_visit */
  if (qh PRINTstatistics) {
    size= qh_setsize(vertices);
    zinc_(Zintersect);
    zadd_(Zintersecttot, size);
    zmax_(Zintersectmax, size);
  }
  hashsize= qh_newhashtable(qh_setsize(ridges));
  FOREACHridge_(ridges)
    qh_hashridge(qh hash_table, hashsize, ridge, oldvertex);
  FOREACHvertex_(vertices) {
    newridges= qh_vertexridges(vertex, !qh_ALL);
    FOREACHridge_(newridges) {
      if (qh_hashridge_find(qh hash_table, hashsize, ridge, vertex, oldvertex, &hash)) {
        zinc_(Zvertexridge);
        break;
      }
    }
    qh_settempfree(&newridges);
    if (!ridge)
      break;  /* found a rename */
  }
  if (vertex) {
    /* counted in qh_renamevertex */
    trace2((qh ferr, 2020, "qh_find_newvertex: found v%d for old v%d from %d vertices and %d ridges.\n",
      vertex->id, oldvertex->id, qh_setsize(vertices), qh_setsize(ridges)));
  }else {
    zinc_(Zfindfail);
    trace0((qh ferr, 14, "qh_find_newvertex: no vertex for renaming v%d (all duplicated ridges) during p%d\n",
      oldvertex->id, qh furthest_id));
  }
  qh_setfree(&qh hash_table);
  return vertex;
} /* find_newvertex */

/*---------------------------------

  qh_findbest_pinchedvertex( merge, apex, nearestp, distp )
    Determine the best pinched vertex to rename as its nearest neighboring vertex
    Renaming will remove a duplicate MRGdupridge in newfacet_list

  returns:
    pinched vertex (either apex or subridge), nearest vertex (subridge or neighbor vertex), and the distance between them

  notes:
    only called by qh_getpinchedmerges
    assumes qh.VERTEXneighbors
    see qh_findbest_ridgevertex

  design:
    if the facets have the same vertices
      return the nearest vertex pair
    else
      the subridge is the intersection of the two new facets minus the apex
      the subridge consists of qh.hull_dim-2 horizon vertices
      the subridge is also a matched ridge for the new facets (its duplicate)
      determine the nearest vertex to the apex
      determine the nearest pair of subridge vertices
      for each vertex in the subridge
        determine the nearest neighbor vertex (not in the subridge)
*/
vertexT *qh_findbest_pinchedvertex(mergeT *merge, vertexT *apex, vertexT **nearestp, coordT *distp /* qh.newfacet_list */) {
  vertexT *vertex, **vertexp, *vertexA, **vertexAp;
  vertexT *bestvertex= NULL, *bestpinched= NULL;
  setT *subridge, *maybepinched;
  coordT dist, bestdist= REALmax;
  coordT pincheddist= (qh ONEmerge+qh DISTround)*qh_RATIOpinchedsubridge;

  if (!merge->facet1->simplicial || !merge->facet2->simplicial) {
    qh_fprintf(qh ferr, 6351, "qhull internal error (qh_findbest_pinchedvertex): expecting merge of adjacent, simplicial new facets.  f%d or f%d is not simplicial\n",
      merge->facet1->id, merge->facet2->id);
    qh_errexit2(qh_ERRqhull, merge->facet1, merge->facet2);
  }
  subridge= qh_vertexintersect_new(merge->facet1->vertices, merge->facet2->vertices); /* new setT.  No error_exit() */
  if (qh_setsize(subridge) == qh hull_dim) { /* duplicate vertices */
    bestdist= qh_vertex_bestdist2(subridge, &bestvertex, &bestpinched);
    if(bestvertex == apex) {
      bestvertex= bestpinched;
      bestpinched= apex;
    }
  }else {
    qh_setdel(subridge, apex);
    if (qh_setsize(subridge) != qh hull_dim - 2) {
      qh_fprintf(qh ferr, 6409, "qhull internal error (qh_findbest_pinchedvertex): expecting subridge of qh.hull_dim-2 vertices for the intersection of new facets f%d and f%d minus their apex.  Got %d vertices\n",
          merge->facet1->id, merge->facet2->id, qh_setsize(subridge));
      qh_errexit2(qh_ERRqhull, merge->facet1, merge->facet2);
    }
    FOREACHvertex_(subridge) {
      dist= qh_pointdist(vertex->point, apex->point, qh hull_dim);
      if (dist < bestdist) {
        bestpinched= apex;
        bestvertex= vertex;
        bestdist= dist;
      }
    }
    if (bestdist > pincheddist) {
      FOREACHvertex_(subridge) {
        FOREACHvertexA_(subridge) {
          if (vertexA->id > vertex->id) { /* once per vertex pair, do not compare addresses */
            dist= qh_pointdist(vertexA->point, vertex->point, qh hull_dim);
            if (dist < bestdist) {
              bestpinched= vertexA;
              bestvertex= vertex;
              bestdist= dist;
            }
          }
        }
      }
    }
    if (bestdist > pincheddist) {
      FOREACHvertexA_(subridge) {
        maybepinched= qh_neighbor_vertices(vertexA, subridge); /* subridge and apex tested above */
        FOREACHvertex_(maybepinched) {
          dist= qh_pointdist(vertex->point, vertexA->point, qh hull_dim);
          if (dist < bestdist) {
            bestvertex= vertex;
            bestpinched= vertexA;
            bestdist= dist;
          }
        }
        qh_settempfree(&maybepinched);
      }
    }
  }
  *distp= bestdist;
  qh_setfree(&subridge); /* qh_err_exit not called since allocated */
  if (!bestvertex) {  /* should never happen if qh.hull_dim > 2 */
    qh_fprintf(qh ferr, 6274, "qhull internal error (qh_findbest_pinchedvertex): did not find best vertex for subridge of dupridge between f%d and f%d, while processing p%d\n", merge->facet1->id, merge->facet2->id, qh furthest_id);
    qh_errexit2(qh_ERRqhull, merge->facet1, merge->facet2);
  }
  *nearestp= bestvertex;
  trace2((qh ferr, 2061, "qh_findbest_pinchedvertex: best pinched p%d(v%d) and vertex p%d(v%d) are closest (%2.2g) for duplicate subridge between f%d and f%d\n",
      qh_pointid(bestpinched->point), bestpinched->id, qh_pointid(bestvertex->point), bestvertex->id, bestdist, merge->facet1->id, merge->facet2->id));
  return bestpinched;
} /* findbest_pinchedvertex */

/*---------------------------------

  qh_findbest_ridgevertex( ridge, pinchedp, distp )
    Determine the best vertex/pinched-vertex to merge for ridges with the same vertices

  returns:
    vertex, pinched vertex, and the distance between them

  notes:
    assumes qh.hull_dim>=3
    see qh_findbest_pinchedvertex

*/
vertexT *qh_findbest_ridgevertex(ridgeT *ridge, vertexT **pinchedp, coordT *distp) {
  vertexT *bestvertex;

  *distp= qh_vertex_bestdist2(ridge->vertices, &bestvertex, pinchedp);
  trace4((qh ferr, 4069, "qh_findbest_ridgevertex: best pinched p%d(v%d) and vertex p%d(v%d) are closest (%2.2g) for duplicated ridge r%d (same vertices) between f%d and f%d\n",
      qh_pointid((*pinchedp)->point), (*pinchedp)->id, qh_pointid(bestvertex->point), bestvertex->id, *distp, ridge->id, ridge->top->id, ridge->bottom->id));
  return bestvertex;
} /* findbest_ridgevertex */

/*---------------------------------

  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
    initially *bestfacet==NULL and *dist==REALmax

  returns:
    if a better facet (i.e., vertices/centrum of facet closer to neighbor)
      updates bestfacet, dist, mindist, and maxdist

  notes:
    called by qh_findbestneighbor
    ignores pairs of flipped facets, unless that's all there is
*/
void qh_findbest_test(boolT testcentrum, facetT *facet, facetT *neighbor,
      facetT **bestfacet, realT *distp, realT *mindistp, realT *maxdistp) {
  realT dist, mindist, maxdist;

  if (facet->flipped && neighbor->flipped && *bestfacet && !(*bestfacet)->flipped)
    return; /* do not merge flipped into flipped facets */
  if (testcentrum) {
    zzinc_(Zbestdist);
    qh_distplane(facet->center, neighbor, &dist);
    dist *= qh hull_dim; /* estimate furthest vertex */
    if (dist < 0) {
      maxdist= 0;
      mindist= dist;
      dist= -dist;
    }else {
      mindist= 0;
      maxdist= dist;
    }
  }else
    dist= qh_getdistance(facet, neighbor, &mindist, &maxdist);
  if (dist < *distp) {
    *bestfacet= neighbor;
    *mindistp= mindist;
    *maxdistp= maxdist;
    *distp= dist;
  }
} /* findbest_test */

/*---------------------------------

  qh_findbestneighbor( facet, dist, mindist, maxdist )
    finds best neighbor (least dist) of a facet for merging

  returns:
    returns min and max distances and their max absolute value

  notes:
    error if qh_ASvoronoi
    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);

  if(qh CENTERtype==qh_ASvoronoi){
    qh_fprintf(qh ferr, 6272, "qhull internal error: cannot call qh_findbestneighor for f%d while qh.CENTERtype is qh_ASvoronoi\n", facet->id);
    qh_errexit(qh_ERRqhull, facet, NULL);
  }
  *distp= REALmax;
  if (size > qh_BESTcentrum2 * qh hull_dim + qh_BESTcentrum) {
    testcentrum= True;
    zinc_(Zbestcentrum);
    if (!facet->center)
       facet->center= qh_getcentrum(facet);
  }
  if (size > qh hull_dim + qh_BESTnonconvex) {
    FOREACHridge_(facet->ridges) {
      if (ridge->nonconvex) {
        neighbor= otherfacet_(ridge, facet);
        qh_findbest_test(testcentrum, facet, neighbor,
                          &bestfacet, distp, mindistp, maxdistp);
      }
    }
  }
  if (!bestfacet) {
    nonconvex= False;
    FOREACHneighbor_(facet)
      qh_findbest_test(testcentrum, facet, neighbor,
                        &bestfacet, distp, mindistp, maxdistp);
  }
  if (!bestfacet) {
    qh_fprintf(qh ferr, 6095, "qhull internal error (qh_findbestneighbor): no neighbors for f%d\n", facet->id);
    qh_errexit(qh_ERRqhull, facet, NULL);
  }
  if (testcentrum)
    qh_getdistance(facet, bestfacet, mindistp, maxdistp);
  trace3((qh ferr, 3002, "qh_findbestneighbor: f%d is best neighbor for f%d testcentrum? %d nonconvex? %d dist %2.2g min %2.2g max %2.2g\n",
     bestfacet->id, facet->id, testcentrum, nonconvex, *distp, *mindistp, *maxdistp));
  return(bestfacet);
} /* findbestneighbor */


/*---------------------------------

  qh_flippedmerges( facetlist, wasmerge )
    merge flipped facets into best neighbor
    assumes qh.facet_mergeset at top of temporary stack

  returns:
    no flipped facets on facetlist
    sets wasmerge if merge occurred
    degen/redundant merges passed through

  notes:
    othermerges not needed since qh.facet_mergeset is empty before & after
      keep it in case of change

  design:
    append flipped facets to qh.facetmergeset
    for each flipped merge
      find best neighbor
      merge facet into neighbor
      merge degenerate and redundant facets
    remove flipped merges from qh.facet_mergeset
*/
void qh_flippedmerges(facetT *facetlist, boolT *wasmerge) {
  facetT *facet, *neighbor, *facet1;
  realT dist, mindist, maxdist;
  mergeT *merge, **mergep;
  setT *othermerges;
  int nummerge= 0, numdegen= 0;

  trace4((qh ferr, 4024, "qh_flippedmerges: begin\n"));
  FORALLfacet_(facetlist) {
    if (facet->flipped && !facet->visible)
      qh_appendmergeset(facet, facet, MRGflip, 0.0, 1.0);
  }
  othermerges= qh_settemppop();
  if(othermerges != qh facet_mergeset) {
    qh_fprintf(qh ferr, 6392, "qhull internal error (qh_flippedmerges): facet_mergeset (%d merges) not at top of tempstack (%d merges)\n",
        qh_setsize(qh facet_mergeset), qh_setsize(othermerges));
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  qh facet_mergeset= qh_settemp(qh TEMPsize);
  qh_settemppush(othermerges);
  FOREACHmerge_(othermerges) {
    facet1= merge->facet1;
    if (merge->mergetype != MRGflip || facet1->visible)
      continue;
    if (qh TRACEmerge-1 == zzval_(Ztotmerge))
      qhmem.IStracing= qh IStracing= qh TRACElevel;
    neighbor= qh_findbestneighbor(facet1, &dist, &mindist, &maxdist);
    trace0((qh ferr, 15, "qh_flippedmerges: merge flipped f%d into f%d dist %2.2g during p%d\n",
      facet1->id, neighbor->id, dist, qh furthest_id));
    qh_mergefacet(facet1, neighbor, merge->mergetype, &mindist, &maxdist, !qh_MERGEapex);
    nummerge++;
    if (qh PRINTstatistics) {
      zinc_(Zflipped);
      wadd_(Wflippedtot, dist);
      wmax_(Wflippedmax, dist);
    }
  }
  FOREACHmerge_(othermerges) {
    if (merge->facet1->visible || merge->facet2->visible)
      qh_memfree(merge, (int)sizeof(mergeT)); /* invalidates merge and othermerges */
    else
      qh_setappend(&qh facet_mergeset, merge);
  }
  qh_settempfree(&othermerges);
  numdegen += qh_merge_degenredundant(); /* somewhat better here than after each flipped merge -- qtest.sh 10 '500 C1,2e-13 D4' 'd Qbb' */
  if (nummerge)
    *wasmerge= True;
  trace1((qh ferr, 1010, "qh_flippedmerges: merged %d flipped and %d degenredundant facets into a good neighbor\n",
    nummerge, numdegen));
} /* flippedmerges */


/*---------------------------------

  qh_forcedmerges( wasmerge )
    merge dupridges
    calls qh_check_dupridge to report an error on wide merges
    assumes qh_settemppop is qh.facet_mergeset

  returns:
    removes all dupridges 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:
    called by qh_premerge
    dupridges 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 dupridge
      find current facets by chasing f.replace links
      check for wide merge due to dupridge
      determine best direction for facet
      merge one facet into the other
      remove dupridges from qh.facet_mergeset
*/
void qh_forcedmerges(boolT *wasmerge) {
  facetT *facet1, *facet2, *merging, *merged, *newfacet;
  mergeT *merge, **mergep;
  realT dist, mindist, maxdist, dist2, mindist2, maxdist2;
  setT *othermerges;
  int nummerge=0, numflip=0, numdegen= 0;
  boolT wasdupridge= False;

  if (qh TRACEmerge-1 == zzval_(Ztotmerge))
    qhmem.IStracing= qh IStracing= qh TRACElevel;
  trace3((qh ferr, 3054, "qh_forcedmerges: merge dupridges\n"));
  othermerges= qh_settemppop(); /* was facet_mergeset */
  if (qh facet_mergeset != othermerges ) {
      qh_fprintf(qh ferr, 6279, "qhull internal error (qh_forcedmerges): qh_settemppop (size %d) is not qh facet_mergeset (size %d)\n",
          qh_setsize(othermerges), qh_setsize(qh facet_mergeset));
      qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  qh facet_mergeset= qh_settemp(qh TEMPsize);
  qh_settemppush(othermerges);
  FOREACHmerge_(othermerges) {
    if (merge->mergetype != MRGdupridge)
        continue;
    wasdupridge= True;
    if (qh TRACEmerge-1 == zzval_(Ztotmerge))
        qhmem.IStracing= qh IStracing= qh TRACElevel;
    facet1= qh_getreplacement(merge->facet1);  /* must exist, no qh_merge_degenredunant */
    facet2= qh_getreplacement(merge->facet2);  /* previously merged facet, if any */
    if (facet1 == facet2)
      continue;
    if (!qh_setin(facet2->neighbors, facet1)) {
      qh_fprintf(qh ferr, 6096, "qhull internal error (qh_forcedmerges): f%d and f%d had a dupridge 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);
    }
    dist= qh_getdistance(facet1, facet2, &mindist, &maxdist);
    dist2= qh_getdistance(facet2, facet1, &mindist2, &maxdist2);
    qh_check_dupridge(facet1, dist, facet2, dist2);
    if (dist < dist2) {
      if (facet2->flipped && !facet1->flipped && dist2 < qh_WIDEdupridge*(qh ONEmerge+qh DISTround)) { /* prefer merge of flipped facet */
        merging= facet2;
        merged= facet1;
        dist= dist2;
        mindist= mindist2;
        maxdist= maxdist2;
      }else {
        merging= facet1;
        merged= facet2;
      }
    }else {
      if (facet1->flipped && !facet2->flipped && dist < qh_WIDEdupridge*(qh ONEmerge+qh DISTround)) { /* prefer merge of flipped facet */
        merging= facet1;
        merged= facet2;
      }else {
        merging= facet2;
        merged= facet1;
        dist= dist2;
        mindist= mindist2;
        maxdist= maxdist2;
      }
    }
    qh_mergefacet(merging, merged, merge->mergetype, &mindist, &maxdist, !qh_MERGEapex);
    numdegen += qh_merge_degenredundant(); /* better here than at end -- qtest.sh 10 '500 C1,2e-13 D4' 'd Qbb' */
    if (facet1->flipped) {
      zinc_(Zmergeflipdup);
      numflip++;
    }else
      nummerge++;
    if (qh PRINTstatistics) {
      zinc_(Zduplicate);
      wadd_(Wduplicatetot, dist);
      wmax_(Wduplicatemax, dist);
    }
  }
  FOREACHmerge_(othermerges) {
    if (merge->mergetype == MRGdupridge)
      qh_memfree(merge, (int)sizeof(mergeT)); /* invalidates merge and othermerges */
    else
      qh_setappend(&qh facet_mergeset, merge);
  }
  qh_settempfree(&othermerges);
  if (wasdupridge) {
    FORALLnew_facets {
      if (newfacet->dupridge) {
        newfacet->dupridge= False;
        newfacet->mergeridge= False;
        newfacet->mergeridge2= False;
        if (qh_setsize(newfacet->neighbors) < qh hull_dim) { /* not tested for MRGdupridge */
          qh_appendmergeset(newfacet, newfacet, MRGdegen, 0.0, 1.0);
          trace2((qh ferr, 2107, "qh_forcedmerges: dupridge f%d is degenerate with fewer than %d neighbors\n",
                      newfacet->id, qh hull_dim));
        }
      }
    }
    numdegen += qh_merge_degenredundant();
  }
  if (nummerge || numflip) {
    *wasmerge= True;
    trace1((qh ferr, 1011, "qh_forcedmerges: merged %d facets, %d flipped facets, and %d degenredundant facets across dupridges\n",
                  nummerge, numflip, numdegen));
  }
} /* forcedmerges */


/*---------------------------------

  qh_freemergesets( )
    free the merge sets

  notes:
    matches qh_initmergesets
*/
void qh_freemergesets(void) {

  if (!qh facet_mergeset || !qh degen_mergeset || !qh vertex_mergeset) {
    qh_fprintf(qh ferr, 6388, "qhull internal error (qh_freemergesets): expecting mergesets.  Got a NULL mergeset, qh.facet_mergeset (0x%x), qh.degen_mergeset (0x%x), qh.vertex_mergeset (0x%x)\n",
      qh facet_mergeset, qh degen_mergeset, qh vertex_mergeset);
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  if (!SETempty_(qh facet_mergeset) || !SETempty_(qh degen_mergeset) || !SETempty_(qh vertex_mergeset)) {
    qh_fprintf(qh ferr, 6389, "qhull internal error (qh_freemergesets): expecting empty mergesets.  Got qh.facet_mergeset (%d merges), qh.degen_mergeset (%d merges), qh.vertex_mergeset (%d merges)\n",
      qh_setsize(qh facet_mergeset), qh_setsize(qh degen_mergeset), qh_setsize(qh vertex_mergeset));
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  qh_settempfree(&qh facet_mergeset);
  qh_settempfree(&qh vertex_mergeset);
  qh_settempfree(&qh degen_mergeset);
} /* freemergesets */

/*---------------------------------

  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:
    facetlist is qh.facet_newlist, use qh_getmergeset_initial for all facets
    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

  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 mergetype and angle or distance
*/
void qh_getmergeset(facetT *facetlist) {
  facetT *facet, *neighbor, **neighborp;
  ridgeT *ridge, **ridgep;
  int nummerges;
  boolT simplicial;

  nummerges= qh_setsize(qh facet_mergeset);
  trace4((qh ferr, 4026, "qh_getmergeset: started.\n"));
  qh visit_id++;
  FORALLfacet_(facetlist) {
    if (facet->tested)
      continue;
    facet->visitid= qh visit_id;
    FOREACHneighbor_(facet)
      neighbor->seen= False;
    /* facet must be non-simplicial due to merge to qh.facet_newlist */
    FOREACHridge_(facet->ridges) {
      if (ridge->tested && !ridge->nonconvex)
        continue;
      /* if r.tested & r.nonconvex, need to retest and append merge */
      neighbor= otherfacet_(ridge, facet);
      if (neighbor->seen) { /* another ridge for this facet-neighbor pair was already tested in this loop */
        ridge->tested= True;
        ridge->nonconvex= False;   /* only one ridge is marked nonconvex per facet-neighbor pair */
      }else if (neighbor->visitid != qh visit_id) {
        neighbor->seen= True;
        ridge->nonconvex= False;
        simplicial= False;
        if (ridge->simplicialbot && ridge->simplicialtop)
          simplicial= True;
        if (qh_test_appendmerge(facet, neighbor, simplicial))
          ridge->nonconvex= True;
        ridge->tested= True;
      }
    }
    facet->tested= True;
  }
  nummerges= qh_setsize(qh facet_mergeset);
  if (qh ANGLEmerge)
    qsort(SETaddr_(qh facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_compare_anglemerge);
  else
    qsort(SETaddr_(qh facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_compare_facetmerge);
  nummerges += qh_setsize(qh degen_mergeset);
  if (qh POSTmerging) {
    zadd_(Zmergesettot2, nummerges);
  }else {
    zadd_(Zmergesettot, nummerges);
    zmax_(Zmergesetmax, nummerges);
  }
  trace2((qh ferr, 2021, "qh_getmergeset: %d merges found\n", nummerges));
} /* getmergeset */


/*---------------------------------

  qh_getmergeset_initial( facetlist )
    determine initial qh.facet_mergeset for facets
    tests all facet/neighbor pairs on facetlist

  returns:
    sorted qh.facet_mergeset with nonconvex ridges
    sets facet->tested, ridge->tested, and ridge->nonconvex

  notes:
    uses visit_id, assumes ridge->nonconvex is False
    see qh_getmergeset

  design:
    for each facet on facetlist
      for each untested neighbor of facet
        test facet and neighbor for convexity
        if non-convex
          append merge to qh.facet_mergeset
          mark one of the ridges as nonconvex
    sort qh.facet_mergeset by mergetype and angle or distance
*/
void qh_getmergeset_initial(facetT *facetlist) {
  facetT *facet, *neighbor, **neighborp;
  ridgeT *ridge, **ridgep;
  int nummerges;
  boolT simplicial;

  qh visit_id++;
  FORALLfacet_(facetlist) {
    facet->visitid= qh visit_id;
    FOREACHneighbor_(facet) {
      if (neighbor->visitid != qh visit_id) {
        simplicial= False; /* ignores r.simplicialtop/simplicialbot.  Need to test horizon facets */
        if (facet->simplicial && neighbor->simplicial)
          simplicial= True;
        if (qh_test_appendmerge(facet, neighbor, simplicial)) {
          FOREACHridge_(neighbor->ridges) {
            if (facet == otherfacet_(ridge, neighbor)) {
              ridge->nonconvex= True;
              break;    /* only one ridge is marked nonconvex */
            }
          }
        }
      }
    }
    facet->tested= True;
    FOREACHridge_(facet->ridges)
      ridge->tested= True;
  }
  nummerges= qh_setsize(qh facet_mergeset);
  if (qh ANGLEmerge)
    qsort(SETaddr_(qh facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_compare_anglemerge);
  else
    qsort(SETaddr_(qh facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_compare_facetmerge);
  nummerges += qh_setsize(qh degen_mergeset);
  if (qh POSTmerging) {
    zadd_(Zmergeinittot2, nummerges);
  }else {
    zadd_(Zmergeinittot, nummerges);
    zmax_(Zmergeinitmax, nummerges);
  }
  trace2((qh ferr, 2022, "qh_getmergeset_initial: %d merges found\n", nummerges));
} /* getmergeset_initial */

/*---------------------------------

  qh_getpinchedmerges( apex, maxdist, iscoplanar )
    get pinched merges for dupridges in qh.facet_mergeset
    qh.NEWtentative==True
      qh.newfacet_list with apex
      qh.horizon_list is attached to qh.visible_list instead of qh.newfacet_list
      maxdist for vertex-facet of a dupridge
    qh.facet_mergeset is empty
    qh.vertex_mergeset is a temporary set

  returns:
    False if nearest vertex would increase facet width by more than maxdist or qh_WIDEpinched
    True and iscoplanar, if the pinched vertex is the apex (i.e., make the apex a coplanar point)
    True and !iscoplanar, if should merge a pinched vertex of a dupridge
      qh.vertex_mergeset contains one or more MRGsubridge with a pinched vertex and a nearby, neighboring vertex
    qh.facet_mergeset is empty

  notes:
    called by qh_buildcone_mergepinched
    hull_dim >= 3
    a pinched vertex is in a dupridge and the horizon
    selects the pinched vertex that is closest to its neighbor

  design:
    for each dupridge
        determine the best pinched vertex to be merged into a neighboring vertex
        if merging the pinched vertex would produce a wide merge (qh_WIDEpinched)
           ignore pinched vertex with a warning, and use qh_merge_degenredundant instead
        else
           append the pinched vertex to vertex_mergeset for merging
*/
boolT qh_getpinchedmerges(vertexT *apex, coordT maxdupdist, boolT *iscoplanar /* qh.newfacet_list, qh.vertex_mergeset */) {
  mergeT *merge, **mergep, *bestmerge= NULL;
  vertexT *nearest, *pinched, *bestvertex= NULL, *bestpinched= NULL;
  boolT result;
  coordT dist, prevdist, bestdist= REALmax/(qh_RATIOcoplanarapex+1.0); /* allow *3.0 */
  realT ratio;

  trace2((qh ferr, 2062, "qh_getpinchedmerges: try to merge pinched vertices for dupridges in new facets with apex p%d(v%d) max dupdist %2.2g\n",
      qh_pointid(apex->point), apex->id, maxdupdist));
  *iscoplanar= False;
  prevdist= fmax_(qh ONEmerge + qh DISTround, qh MINoutside + qh DISTround);
  maximize_(prevdist, qh max_outside);
  maximize_(prevdist, -qh min_vertex);
  qh_mark_dupridges(qh newfacet_list, !qh_ALL); /* qh.facet_mergeset, creates ridges */
  /* qh_mark_dupridges is called a second time in qh_premerge */
  FOREACHmerge_(qh facet_mergeset) {  /* read-only */
    if (merge->mergetype != MRGdupridge) {
      qh_fprintf(qh ferr, 6393, "qhull internal error (qh_getpinchedmerges): expecting MRGdupridge from qh_mark_dupridges.  Got merge f%d f%d type %d\n",
        getid_(merge->facet1), getid_(merge->facet2), merge->mergetype);
      qh_errexit(qh_ERRqhull, NULL, NULL);
    }
    /* dist is distance between vertices */
    pinched= qh_findbest_pinchedvertex(merge, apex, &nearest, &dist /* qh.newfacet_list */);
    if (pinched == apex && dist < qh_RATIOcoplanarapex*bestdist) { /* prefer coplanar apex since it always works */
      bestdist= dist/qh_RATIOcoplanarapex;
      bestmerge= merge;
      bestpinched= pinched;
      bestvertex= nearest;
    }else if (dist < bestdist) {
      bestdist= dist;
      bestmerge= merge;
      bestpinched= pinched;
      bestvertex= nearest;
    }
  }
  result= False;
  if (bestmerge && bestdist < maxdupdist) {
    ratio= bestdist / prevdist;
    if (ratio > qh_WIDEpinched) {
      if (bestmerge->facet1->mergehorizon || bestmerge->facet2->mergehorizon) { /* e.g., rbox 175 C3,2e-13 t1539182828 | qhull d */
        trace1((qh ferr, 1051, "qh_getpinchedmerges: dupridge (MRGdupridge) of coplanar horizon would produce a wide merge (%.0fx) due to pinched vertices v%d and v%d (dist %2.2g) for f%d and f%d.  qh_mergecycle_all will merge one or both facets\n",
          ratio, bestpinched->id, bestvertex->id, bestdist, bestmerge->facet1->id, bestmerge->facet2->id));
      }else {
        qh_fprintf(qh ferr, 7081, "qhull precision warning (qh_getpinchedmerges): pinched vertices v%d and v%d (dist %2.2g, %.0fx) would produce a wide merge for f%d and f%d.  Will merge dupridge instead\n",
          bestpinched->id, bestvertex->id, bestdist, ratio, bestmerge->facet1->id, bestmerge->facet2->id);
      }
    }else {
      if (bestpinched == apex) {
        trace2((qh ferr, 2063, "qh_getpinchedmerges: will make the apex a coplanar point.  apex p%d(v%d) is the nearest vertex to v%d on dupridge.  Dist %2.2g\n",
          qh_pointid(apex->point), apex->id, bestvertex->id, bestdist*qh_RATIOcoplanarapex));
        qh coplanar_apex= apex->point;
        *iscoplanar= True;
        result= True;
      }else if (qh_setin(bestmerge->facet1->vertices, bestpinched) != qh_setin(bestmerge->facet2->vertices, bestpinched)) { /* pinched in one facet but not the other facet */
        trace2((qh ferr, 2064, "qh_getpinchedmerges: will merge new facets to resolve dupridge between f%d and f%d with pinched v%d and v%d\n",
          bestmerge->facet1->id, bestmerge->facet2->id, bestpinched->id, bestvertex->id));
        qh_appendvertexmerge(bestpinched, bestvertex, MRGsubridge, bestdist, NULL, NULL);
        result= True;
      }else {
        trace2((qh ferr, 2065, "qh_getpinchedmerges: will merge pinched v%d into v%d to resolve dupridge between f%d and f%d\n",
          bestpinched->id, bestvertex->id, bestmerge->facet1->id, bestmerge->facet2->id));
        qh_appendvertexmerge(bestpinched, bestvertex, MRGsubridge, bestdist, NULL, NULL);
        result= True;
      }
    }
  }
  /* delete MRGdupridge, qh_mark_dupridges is called a second time in qh_premerge */
  while ((merge= (mergeT *)qh_setdellast(qh facet_mergeset)))
    qh_memfree(merge, (int)sizeof(mergeT));
  return result;
}/* getpinchedmerges */

/*---------------------------------

  qh_hasmerge( mergeset, mergetype, facetA, facetB )
    True if mergeset has mergetype for facetA and facetB
*/
boolT   qh_hasmerge(setT *mergeset, mergeType type, facetT *facetA, facetT *facetB) {
  mergeT *merge, **mergep;

  FOREACHmerge_(mergeset) {
    if (merge->mergetype == type) {
      if (merge->facet1 == facetA && merge->facet2 == facetB)
        return True;
      if (merge->facet1 == facetB && merge->facet2 == facetA)
        return True;
    }
  }
  return False;
}/* hasmerge */

/*---------------------------------

  qh_hashridge( hashtable, hashsize, ridge, oldvertex )
    add ridge to hashtable without oldvertex

  notes:
    assumes hashtable is large enough

  design:
    determine hash value for ridge without oldvertex
    find next empty slot for ridge
*/
void qh_hashridge(setT *hashtable, int hashsize, ridgeT *ridge, vertexT *oldvertex) {
  int hash;
  ridgeT *ridgeA;

  hash= qh_gethash(hashsize, ridge->vertices, qh hull_dim-1, 0, oldvertex);
  while (True) {
    if (!(ridgeA= SETelemt_(hashtable, hash, ridgeT))) {
      SETelem_(hashtable, hash)= ridge;
      break;
    }else if (ridgeA == ridge)
      break;
    if (++hash == hashsize)
      hash= 0;
  }
} /* hashridge */


/*---------------------------------

  qh_hashridge_find( hashtable, hashsize, ridge, vertex, oldvertex, hashslot )
    returns matching ridge without oldvertex in hashtable
      for ridge without vertex
    if oldvertex is NULL
      matches with any one skip

  returns:
    matching ridge or NULL
    if no match,
      if ridge already in   table
        hashslot= -1
      else
        hashslot= next NULL index

  notes:
    assumes hashtable is large enough
    can't match ridge to itself

  design:
    get hash value for ridge without vertex
    for each hashslot
      return match if ridge matches ridgeA without oldvertex
*/
ridgeT *qh_hashridge_find(setT *hashtable, int hashsize, ridgeT *ridge,
              vertexT *vertex, vertexT *oldvertex, int *hashslot) {
  int hash;
  ridgeT *ridgeA;

  *hashslot= 0;
  zinc_(Zhashridge);
  hash= qh_gethash(hashsize, ridge->vertices, qh hull_dim-1, 0, vertex);
  while ((ridgeA= SETelemt_(hashtable, hash, ridgeT))) {
    if (ridgeA == ridge)
      *hashslot= -1;
    else {
      zinc_(Zhashridgetest);
      if (qh_setequal_except(ridge->vertices, vertex, ridgeA->vertices, oldvertex))
        return ridgeA;
    }
    if (++hash == hashsize)
      hash= 0;
  }
  if (!*hashslot)
    *hashslot= hash;
  return NULL;
} /* hashridge_find */


/*---------------------------------

  qh_initmergesets( )
    initialize the merge sets
    if 'all', include qh.degen_mergeset

  notes:
    matches qh_freemergesets
*/
void qh_initmergesets(void /* qh.facet_mergeset,degen_mergeset,vertex_mergeset */) {

  if (qh facet_mergeset || qh degen_mergeset || qh vertex_mergeset) {
    qh_fprintf(qh ferr, 6386, "qhull internal error (qh_initmergesets): expecting NULL mergesets.  Got qh.facet_mergeset (0x%x), qh.degen_mergeset (0x%x), qh.vertex_mergeset (0x%x)\n",
      qh facet_mergeset, qh degen_mergeset, qh vertex_mergeset);
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  qh degen_mergeset= qh_settemp(qh TEMPsize);
  qh vertex_mergeset= qh_settemp(qh TEMPsize);
  qh facet_mergeset= qh_settemp(qh TEMPsize); /* last temporary set for qh_forcedmerges */
} /* initmergesets */

/*---------------------------------

  qh_makeridges( facet )
    creates explicit ridges between simplicial facets

  returns:
    facet with ridges and without qh_MERGEridge
    ->simplicial is False
    if facet was tested, new ridges are tested

  notes:
    allows qh_MERGEridge flag
    uses existing ridges
    duplicate neighbors ok if ridges already exist (qh_mergecycle_ridges)

  see:
    qh_mergecycle_ridges()
    qh_rename_adjacentvertex for qh_merge_pinchedvertices

  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 (previously processed by qh_mark_dupridges)
*/
void qh_makeridges(facetT *facet) {
  facetT *neighbor, **neighborp;
  ridgeT *ridge, **ridgep;
  int neighbor_i, neighbor_n;
  boolT toporient, mergeridge= False;

  if (!facet->simplicial)
    return;
  trace4((qh ferr, 4027, "qh_makeridges: make ridges for f%d\n", facet->id));
  facet->simplicial= False;
  FOREACHneighbor_(facet) {
    if (neighbor == qh_MERGEridge)
      mergeridge= True;
    else
      neighbor->seen= False;
  }
  FOREACHridge_(facet->ridges)
    otherfacet_(ridge, facet)->seen= True;
  FOREACHneighbor_i_(facet) {
    if (neighbor == qh_MERGEridge)
      continue;  /* fixed by qh_mark_dupridges */
    else if (!neighbor->seen) {  /* no current ridges */
      ridge= qh_newridge();
      ridge->vertices= qh_setnew_delnthsorted(facet->vertices, qh hull_dim,
                                                          neighbor_i, 0);
      toporient= (boolT)(facet->toporient ^ (neighbor_i & 0x1));
      if (toporient) {
        ridge->top= facet;
        ridge->bottom= neighbor;
        ridge->simplicialtop= True;
        ridge->simplicialbot= neighbor->simplicial;
      }else {
        ridge->top= neighbor;
        ridge->bottom= facet;
        ridge->simplicialtop= neighbor->simplicial;
        ridge->simplicialbot= True;
      }
      if (facet->tested && !mergeridge)
        ridge->tested= True;
#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;
        ridge->simplicialtop= True;
        ridge->simplicialbot= neighbor->simplicial;
      }else {
        ridge->top= facet;
        ridge->bottom= neighbor;
        ridge->simplicialtop= neighbor->simplicial;
        ridge->simplicialbot= True;
      }
#endif
      qh_setappend(&(facet->ridges), ridge);
      trace5((qh ferr, 5005, "makeridges: appended r%d to ridges for f%d.  Next is ridges for neighbor f%d\n",
            ridge->id, facet->id, neighbor->id));
      qh_setappend(&(neighbor->ridges), ridge);
      if (qh ridge_id == qh traceridge_id)
        qh traceridge= ridge;
    }
  }
  if (mergeridge) {
    while (qh_setdel(facet->neighbors, qh_MERGEridge))
      ; /* delete each one */
  }
} /* makeridges */


/*---------------------------------

  qh_mark_dupridges( facetlist, allmerges )
    add duplicated ridges to qh.facet_mergeset
    facet-dupridge is true if it contains a subridge shared by more than one new facet
    for each such facet, one has a neighbor marked qh_MERGEridge
    allmerges is true if merging dupridges
    allmerges is false if merging pinched vertices followed by retry addpoint
      qh_mark_dupridges will be called again if pinched vertices not found

  returns:
    dupridges on qh.facet_mergeset (MRGdupridge)
    f.mergeridge and f.mergeridge2 set for facet
    f.mergeridge set for neighbor
    if allmerges is true
      make ridges for facets with dupridges as marked by qh_MERGEridge and both sides facet->dupridge
      removes qh_MERGEridge from neighbor sets

  notes:
    called by qh_premerge and qh_getpinchedmerges
    dupridges are due to duplicate subridges
        i.e. a subridge occurs in more than two horizon ridges.
        i.e., a ridge has more than two neighboring facets
    dupridges occur in at least two cases
    1) a pinched horizon with nearly adjacent vertices -> merge the vertices (qh_getpinchedmerges)
    2) more than one newfacet for a horizon face -> merge coplanar facets (qh_premerge)
    qh_matchdupridge previously identified the furthest apart pair of facets to retain
       they must have a matching subridge and the same orientation
    only way to set facet->mergeridge and mergeridge2
    uses qh.visit_id

  design:
    for all facets on facetlist
      if facet contains a dupridge
        for each neighbor of facet
          if neighbor marked qh_MERGEridge (one side of the merge)
            set facet->mergeridge
          else
            if neighbor contains a dupridge
            and the back link is qh_MERGEridge
              append dupridge to qh.facet_mergeset
   exit if !allmerges for repeating qh_mark_dupridges later
   for each dupridge
     make ridge sets in preparation for merging
     remove qh_MERGEridge from neighbor set
   for each dupridge
     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, boolT allmerges) {
  facetT *facet, *neighbor, **neighborp;
  int nummerge=0;
  mergeT *merge, **mergep;

  trace4((qh ferr, 4028, "qh_mark_dupridges: identify dupridges in facetlist f%d, allmerges? %d\n",
    facetlist->id, allmerges));
  FORALLfacet_(facetlist) {  /* not necessary for first call */
    facet->mergeridge2= False;
    facet->mergeridge= False;
  }
  FORALLfacet_(facetlist) {
    if (facet->dupridge) {
      FOREACHneighbor_(facet) {
        if (neighbor == qh_MERGEridge) {
          facet->mergeridge= True;
          continue;
        }
        if (neighbor->dupridge) {
          if (!qh_setin(neighbor->neighbors, facet)) { /* i.e., it is qh_MERGEridge, neighbors are distinct */
            qh_appendmergeset(facet, neighbor, MRGdupridge, 0.0, 1.0);
            facet->mergeridge2= True;
            facet->mergeridge= True;
            nummerge++;
          }else if (qh_setequal(facet->vertices, neighbor->vertices)) { /* neighbors are the same except for horizon and qh_MERGEridge, see QH7085 */
            trace3((qh ferr, 3043, "qh_mark_dupridges): dupridge due to duplicate vertices for subridges f%d and f%d\n",
                 facet->id, neighbor->id));
            qh_appendmergeset(facet, neighbor, MRGdupridge, 0.0, 1.0);
            facet->mergeridge2= True;
            facet->mergeridge= True;
            nummerge++;
            break; /* same for all neighbors */
          }
        }
      }
    }
  }
  if (!nummerge)
    return;
  if (!allmerges) {
    trace1((qh ferr, 1012, "qh_mark_dupridges: found %d duplicated ridges (MRGdupridge) for qh_getpinchedmerges\n", nummerge));
    return;
  }
  trace1((qh ferr, 1048, "qh_mark_dupridges: found %d duplicated ridges (MRGdupridge) for qh_premerge.  Prepare facets for merging\n", nummerge));
  /* make ridges in preparation for merging */
  FORALLfacet_(facetlist) {
    if (facet->mergeridge && !facet->mergeridge2)
      qh_makeridges(facet);
  }
  trace3((qh ferr, 3075, "qh_mark_dupridges: restore missing neighbors and ridges due to qh_MERGEridge\n"));
  FOREACHmerge_(qh facet_mergeset) {   /* restore the missing neighbors */
    if (merge->mergetype == MRGdupridge) { /* only between simplicial facets */
      if (merge->facet2->mergeridge2 && qh_setin(merge->facet2->neighbors, merge->facet1)) {
        /* Due to duplicate or multiple subridges, e.g., ../eg/qtest.sh t712682 '200 s W1e-13  C1,1e-13 D5' 'd'
            merge->facet1:    - neighboring facets: f27779 f59186 f59186 f59186 MERGEridge f59186
            merge->facet2:    - neighboring facets: f27779 f59100 f59100 f59100 f59100 f59100
           or, ../eg/qtest.sh 100 '500 s W1e-13 C1,1e-13 D4' 'd'
           both facets will be degenerate after merge, consider for special case handling
        */
        qh_fprintf(qh ferr, 6361, "qhull topological error (qh_mark_dupridges): multiple dupridges for f%d and f%d, including reverse\n",
          merge->facet1->id, merge->facet2->id);
        qh_errexit2(qh_ERRtopology, merge->facet1, merge->facet2);
      }else
        qh_setappend(&merge->facet2->neighbors, merge->facet1);
      qh_makeridges(merge->facet1);   /* and the missing ridges */
    }
  }
} /* mark_dupridges */

/*---------------------------------

  qh_maybe_duplicateridge( ridge )
    add MRGvertices if neighboring facet has another ridge with the same vertices

  returns:
    adds rename requests to qh.vertex_mergeset

  notes:
    called by qh_renamevertex
    nop if 2-D
    expensive test
    Duplicate ridges may lead to new facets with same vertex set (QH7084), will try merging vertices
    same as qh_maybe_duplicateridges

  design:
    for the two neighbors
      if non-simplicial
        for each ridge with the same first and last vertices (max id and min id)
          if the remaining vertices are the same
            get the closest pair of vertices
            add to vertex_mergeset for merging
*/
void qh_maybe_duplicateridge(ridgeT *ridgeA) {
  ridgeT *ridge, **ridgep;
  vertexT *vertex, *pinched;
  facetT *neighbor;
  coordT dist;
  int i, k, last= qh hull_dim-2;

  if (qh hull_dim < 3 )
    return;

  for (neighbor= ridgeA->top, i=0; i<2; neighbor= ridgeA->bottom, i++) {
    if (!neighbor->simplicial && neighbor->nummerge > 0) { /* skip degenerate neighbors with both new and old vertices that will be merged */
      FOREACHridge_(neighbor->ridges) {
        if (ridge != ridgeA && SETfirst_(ridge->vertices) == SETfirst_(ridgeA->vertices)) {
          if (SETelem_(ridge->vertices, last) == SETelem_(ridgeA->vertices, last)) {
            for (k=1; kvertices, k) != SETelem_(ridgeA->vertices, k))
                break;
            }
            if (k == last) {
              vertex= qh_findbest_ridgevertex(ridge, &pinched, &dist);
              trace2((qh ferr, 2069, "qh_maybe_duplicateridge: will merge v%d into v%d (dist %2.2g) due to duplicate ridges r%d/r%d with the same vertices.  mergevertex set\n",
                pinched->id, vertex->id, dist, ridgeA->id, ridge->id, ridgeA->top->id, ridgeA->bottom->id, ridge->top->id, ridge->bottom->id));
              qh_appendvertexmerge(pinched, vertex, MRGvertices, dist, ridgeA, ridge);
              ridge->mergevertex= True; /* disables check for duplicate vertices in qh_checkfacet */
              ridgeA->mergevertex= True;
            }
          }
        }
      }
    }
  }
} /* maybe_duplicateridge */

/*---------------------------------

  qh_maybe_duplicateridges( facet )
    if Q15, add MRGvertices if facet has ridges with the same vertices

  returns:
    adds rename requests to qh.vertex_mergeset

  notes:
    called at end of qh_mergefacet and qh_mergecycle_all
    only enabled if qh.CHECKduplicates ('Q15') and 3-D or more
    expensive test, not worth it
    same as qh_maybe_duplicateridge

  design:
    for all ridge pairs in facet
        if the same first and last vertices (max id and min id)
          if the remaining vertices are the same
            get the closest pair of vertices
            add to vertex_mergeset for merging
*/
void qh_maybe_duplicateridges(facetT *facet) {
  facetT *otherfacet;
  ridgeT *ridge, *ridge2;
  vertexT *vertex, *pinched;
  coordT dist;
  int ridge_i, ridge_n, i, k, last_v= qh hull_dim-2;

  if (qh hull_dim < 3 || !qh CHECKduplicates)
    return;

  FOREACHridge_i_(facet->ridges) {
    otherfacet= otherfacet_(ridge, facet);
    if (otherfacet->degenerate || otherfacet->redundant || otherfacet->dupridge || otherfacet->flipped) /* will merge */
      continue;
    for (i=ridge_i+1; i < ridge_n; i++) {
      ridge2= SETelemt_(facet->ridges, i, ridgeT);
      otherfacet= otherfacet_(ridge2, facet);
      if (otherfacet->degenerate || otherfacet->redundant || otherfacet->dupridge || otherfacet->flipped) /* will merge */
        continue;
      /* optimize qh_setequal(ridge->vertices, ridge2->vertices) */
      if (SETelem_(ridge->vertices, last_v) == SETelem_(ridge2->vertices, last_v)) { /* SETfirst is likely to be the same */
        if (SETfirst_(ridge->vertices) == SETfirst_(ridge2->vertices)) {
          for (k=1; kvertices, k) != SETelem_(ridge2->vertices, k))
              break;
          }
          if (k == last_v) {
            vertex= qh_findbest_ridgevertex(ridge, &pinched, &dist);
            if (ridge->top == ridge2->bottom && ridge->bottom == ridge2->top) {
              /* proof that ridges may have opposite orientation */
              trace2((qh ferr, 2088, "qh_maybe_duplicateridges: will merge v%d into v%d (dist %2.2g) due to opposite oriented ridges r%d/r%d for f%d and f%d\n",
                pinched->id, vertex->id, dist, ridge->id, ridge2->id, ridge->top->id, ridge->bottom->id));
            }else {
              trace2((qh ferr, 2083, "qh_maybe_duplicateridges: will merge v%d into v%d (dist %2.2g) due to duplicate ridges with the same vertices r%d/r%d in merged facet f%d\n",
                pinched->id, vertex->id, dist, ridge->id, ridge2->id, facet->id));
            }
            qh_appendvertexmerge(pinched, vertex, MRGvertices, dist, ridge, ridge2);
            ridge->mergevertex= True; /* disables check for duplicate vertices in qh_checkfacet */
            ridge2->mergevertex= True;
          }
        }
      }
    }
  }
} /* maybe_duplicateridges */

/*---------------------------------

  qh_maydropneighbor( facet )
    drop neighbor relationship if ridge was deleted between a non-simplicial facet and its neighbors

  returns:
    for deleted ridges
      ridges made for simplicial neighbors
      neighbor sets updated
      appends degenerate facets to qh.facet_mergeset

  notes:
    called by qh_renamevertex
    assumes neighbors do not include qh_MERGEridge (qh_makeridges)
    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 non-simplicial 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;
  facetT *neighbor, **neighborp;

  qh visit_id++;
  trace4((qh ferr, 4029, "qh_maydropneighbor: test f%d for no ridges to a neighbor\n",
          facet->id));
  if (facet->simplicial) {
    qh_fprintf(qh ferr, 6278, "qhull internal error (qh_maydropneighbor): not valid for simplicial f%d while adding furthest p%d\n",
      facet->id, qh furthest_id);
    qh_errexit(qh_ERRqhull, facet, NULL);
  }
  FOREACHridge_(facet->ridges) {
    ridge->top->visitid= qh visit_id;
    ridge->bottom->visitid= qh visit_id;
  }
  FOREACHneighbor_(facet) {
    if (neighbor->visible) {
      qh_fprintf(qh ferr, 6358, "qhull internal error (qh_maydropneighbor): facet f%d has deleted neighbor f%d (qh.visible_list)\n",
            facet->id, neighbor->id);
      qh_errexit2(qh_ERRqhull, facet, neighbor);
    }
    if (neighbor->visitid != qh visit_id) {
      trace2((qh ferr, 2104, "qh_maydropneighbor: facets f%d and f%d are no longer neighbors while adding furthest p%d\n",
            facet->id, neighbor->id, qh furthest_id));
      if (neighbor->simplicial) {
        qh_fprintf(qh ferr, 6280, "qhull internal error (qh_maydropneighbor): not valid for simplicial neighbor f%d of f%d while adding furthest p%d\n",
            neighbor->id, facet->id, qh furthest_id);
        qh_errexit2(qh_ERRqhull, neighbor, facet);
      }
      zinc_(Zdropneighbor);
      qh_setdel(neighbor->neighbors, facet);
      if (qh_setsize(neighbor->neighbors) < qh hull_dim) {
        zinc_(Zdropdegen);
        qh_appendmergeset(neighbor, neighbor, MRGdegen, 0.0, qh_ANGLEnone);
        trace2((qh ferr, 2023, "qh_maydropneighbors: f%d is degenerate.\n", neighbor->id));
      }
      qh_setdel(facet->neighbors, neighbor);
      neighborp--;  /* repeat, deleted a neighbor */
    }
  }
  if (qh_setsize(facet->neighbors) < qh hull_dim) {
    zinc_(Zdropdegen);
    qh_appendmergeset(facet, facet, MRGdegen, 0.0, qh_ANGLEnone);
    trace2((qh ferr, 2024, "qh_maydropneighbors: f%d is degenerate.\n", facet->id));
  }
} /* maydropneighbor */


/*---------------------------------

  qh_merge_degenredundant( )
    merge all degenerate and redundant facets
    qh.degen_mergeset contains merges from  qh_test_degen_neighbors, qh_test_redundant_neighbors, and qh_degen_redundant_facet

  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
    check for coplanar and convex neighbors afterwards

  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, *facet3;
  realT dist, mindist, maxdist;
  vertexT *vertex, **vertexp;
  int nummerges= 0;
  mergeType mergetype;
  setT *mergedfacets;

  trace2((qh ferr, 2095, "qh_merge_degenredundant: merge %d degenerate, redundant, and mirror facets\n",
    qh_setsize(qh degen_mergeset)));
  mergedfacets= qh_settemp(qh TEMPsize);
  while ((merge= (mergeT *)qh_setdellast(qh degen_mergeset))) {
    facet1= merge->facet1;
    facet2= merge->facet2;
    mergetype= merge->mergetype;
    qh_memfree(merge, (int)sizeof(mergeT)); /* 'merge' is invalidated */
    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_(Zredundant);
      facet3= qh_getreplacement(facet2); /* the same facet if !facet2.visible */
      if (!facet3) {
          qh_fprintf(qh ferr, 6097, "qhull internal error (qh_merge_degenredunant): f%d is redundant but visible f%d has no replacement\n",
               facet1->id, getid_(facet2));
          qh_errexit2(qh_ERRqhull, facet1, facet2);
      }
      qh_setunique(&mergedfacets, facet3);
      if (facet1 == facet3) {
        continue;
      }
      trace2((qh ferr, 2025, "qh_merge_degenredundant: merge redundant f%d into f%d (arg f%d)\n",
            facet1->id, facet3->id, facet2->id));
      qh_mergefacet(facet1, facet3, mergetype, NULL, NULL, !qh_MERGEapex);
      /* merge distance is already accounted for */
      nummerges++;
    }else {  /* mergetype == MRGdegen or MRGmirror, other merges may have fixed */
      if (!(size= qh_setsize(facet1->neighbors))) {
        zinc_(Zdelfacetdup);
        trace2((qh ferr, 2026, "qh_merge_degenredundant: facet f%d has no neighbors.  Deleted\n", facet1->id));
        qh_willdelete(facet1, NULL);
        FOREACHvertex_(facet1->vertices) {
          qh_setdel(vertex->neighbors, facet1);
          if (!SETfirst_(vertex->neighbors)) {
            zinc_(Zdegenvertex);
            trace2((qh ferr, 2027, "qh_merge_degenredundant: deleted v%d because f%d has no neighbors\n",
                 vertex->id, facet1->id));
            vertex->deleted= True;
            qh_setappend(&qh del_vertices, vertex);
          }
        }
        nummerges++;
      }else if (size < qh hull_dim) {
        bestneighbor= qh_findbestneighbor(facet1, &dist, &mindist, &maxdist);
        trace2((qh ferr, 2028, "qh_merge_degenredundant: facet f%d has %d neighbors, merge into f%d dist %2.2g\n",
              facet1->id, size, bestneighbor->id, dist));
        qh_mergefacet(facet1, bestneighbor, mergetype, &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 */
    }
  }
  qh_settempfree(&mergedfacets);
  return nummerges;
} /* merge_degenredundant */

/*---------------------------------

  qh_merge_nonconvex( facet1, facet2, mergetype )
    remove non-convex ridge between facet1 into facet2
    mergetype gives why the facet's are non-convex

  returns:
    merges one of the facets into the best neighbor

  notes:
    mergetype is MRGcoplanar..MRGconvex

  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, *merging, *merged;
  realT dist, dist2, mindist, mindist2, maxdist, maxdist2;

  if (mergetype < MRGcoplanar || mergetype > MRGconcavecoplanar) {
    qh_fprintf(qh ferr, 6398, "qhull internal error (qh_merge_nonconvex): expecting mergetype MRGcoplanar..MRGconcavecoplanar.  Got merge f%d and f%d type %d\n",
      facet1->id, facet2->id, mergetype);
    qh_errexit2(qh_ERRqhull, facet1, facet2);
  }
  if (qh TRACEmerge-1 == zzval_(Ztotmerge))
    qhmem.IStracing= qh IStracing= qh TRACElevel;
  trace3((qh ferr, 3003, "qh_merge_nonconvex: merge #%d for f%d and f%d type %d\n",
      zzval_(Ztotmerge) + 1, facet1->id, facet2->id, mergetype));
  /* concave or coplanar */
  if (!facet1->newfacet) {
    bestfacet= facet2;   /* avoid merging old facet if new is ok */
    facet2= facet1;
    facet1= bestfacet;
  }else
    bestfacet= facet1;
  bestneighbor= qh_findbestneighbor(bestfacet, &dist, &mindist, &maxdist);
  neighbor= qh_findbestneighbor(facet2, &dist2, &mindist2, &maxdist2);
  if (dist < dist2) {
    merging= bestfacet;
    merged= bestneighbor;
  }else if (qh AVOIDold && !facet2->newfacet
  && ((mindist >= -qh MAXcoplanar && maxdist <= qh max_outside)
       || dist * 1.5 < dist2)) {
    zinc_(Zavoidold);
    wadd_(Wavoidoldtot, dist);
    wmax_(Wavoidoldmax, dist);
    trace2((qh ferr, 2029, "qh_merge_nonconvex: avoid merging old facet f%d dist %2.2g.  Use f%d dist %2.2g instead\n",
           facet2->id, dist2, facet1->id, dist2));
    merging= bestfacet;
    merged= bestneighbor;
  }else {
    merging= facet2;
    merged= neighbor;
    dist= dist2;
    mindist= mindist2;
    maxdist= maxdist2;
  }
  qh_mergefacet(merging, merged, mergetype, &mindist, &maxdist, !qh_MERGEapex);
  /* caller merges qh_degenredundant */
  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 if (mergetype == MRGconcavecoplanar) {
      zinc_(Zconcavecoplanar);
      wadd_(Wconcavecoplanartot, dist);
      wmax_(Wconcavecoplanarmax, dist);
    }else { /* MRGcoplanar */
      zinc_(Zcoplanar);
      wadd_(Wcoplanartot, dist);
      wmax_(Wcoplanarmax, dist);
    }
  }
} /* merge_nonconvex */

/*---------------------------------

  qh_merge_pinchedvertices( apex )
    merge pinched vertices in qh.vertex_mergeset to avoid qh_forcedmerges of dupridges

  notes:
    only called by qh_all_vertexmerges
    hull_dim >= 3

  design:
    make vertex neighbors if necessary
    for each pinched vertex
      determine the ridges for the pinched vertex (make ridges as needed)
      merge the pinched vertex into the horizon vertex
      merge the degenerate and redundant facets that result
    check and resolve new dupridges
*/
void qh_merge_pinchedvertices(int apexpointid /* qh.newfacet_list */) {
  mergeT *merge, *mergeA, **mergeAp;
  vertexT *vertex, *vertex2;
  realT dist;
  boolT firstmerge= True;

  qh_vertexneighbors();
  if (qh visible_list || qh newfacet_list || qh newvertex_list) {
    qh_fprintf(qh ferr, 6402, "qhull internal error (qh_merge_pinchedvertices): qh.visible_list (f%d), newfacet_list (f%d), or newvertex_list (v%d) not empty\n",
      getid_(qh visible_list), getid_(qh newfacet_list), getid_(qh newvertex_list));
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  qh visible_list= qh newfacet_list= qh facet_tail;
  qh newvertex_list= qh vertex_tail;
  qh isRenameVertex= True; /* disable duplicate ridge vertices check in qh_checkfacet */
  while ((merge= qh_next_vertexmerge(/* qh.vertex_mergeset */))) { /* only one at a time from qh_getpinchedmerges */
    if (qh TRACEmerge-1 == zzval_(Ztotmerge))
      qhmem.IStracing= qh IStracing= qh TRACElevel;
    if (merge->mergetype == MRGsubridge) {
      zzinc_(Zpinchedvertex);
      trace1((qh ferr, 1050, "qh_merge_pinchedvertices: merge one of %d pinched vertices before adding apex p%d.  Try to resolve duplicate ridges in newfacets\n",
        qh_setsize(qh vertex_mergeset)+1, apexpointid));
      qh_remove_mergetype(qh vertex_mergeset, MRGsubridge);
    }else {
      zzinc_(Zpinchduplicate);
      if (firstmerge)
        trace1((qh ferr, 1056, "qh_merge_pinchedvertices: merge %d pinched vertices from dupridges in merged facets, apex p%d\n",
           qh_setsize(qh vertex_mergeset)+1, apexpointid));
      firstmerge= False;
    }
    vertex= merge->vertex1;
    vertex2= merge->vertex2;
    dist= merge->distance;
    qh_memfree(merge, (int)sizeof(mergeT)); /* merge is invalidated */
    qh_rename_adjacentvertex(vertex, vertex2, dist);
#ifndef qh_NOtrace
    if (qh IStracing >= 2) {
      FOREACHmergeA_(qh degen_mergeset) {
        if (mergeA->mergetype== MRGdegen) {
          qh_fprintf(qh ferr, 2072, "qh_merge_pinchedvertices: merge degenerate f%d into an adjacent facet\n", mergeA->facet1->id);
        }else {
          qh_fprintf(qh ferr, 2084, "qh_merge_pinchedvertices: merge f%d into f%d mergeType %d\n", mergeA->facet1->id, mergeA->facet2->id, mergeA->mergetype);
        }
      }
    }
#endif
    qh_merge_degenredundant(); /* simplicial facets with both old and new vertices */
  }
  qh isRenameVertex= False;
}/* merge_pinchedvertices */

/*---------------------------------

  qh_merge_twisted( facet1, facet2 )
    remove twisted ridge between facet1 into facet2 or report error

  returns:
    merges one of the facets into the best neighbor

  notes:
    a twisted ridge has opposite vertices that are convex and concave

  design:
    find best neighbors for both facets
    error if wide merge
    merge the nearest facet into its best neighbor
    update statistics
*/
void qh_merge_twisted(facetT *facet1, facetT *facet2) {
  facetT *neighbor2, *neighbor, *merging, *merged;
  vertexT *bestvertex, *bestpinched;
  realT dist, dist2, mindist, mindist2, maxdist, maxdist2, mintwisted, bestdist;

  if (qh TRACEmerge-1 == zzval_(Ztotmerge))
    qhmem.IStracing= qh IStracing= qh TRACElevel;
  trace3((qh ferr, 3050, "qh_merge_twisted: merge #%d for twisted f%d and f%d\n",
      zzval_(Ztotmerge) + 1, facet1->id, facet2->id));
  /* twisted */
  neighbor= qh_findbestneighbor(facet1, &dist, &mindist, &maxdist);
  neighbor2= qh_findbestneighbor(facet2, &dist2, &mindist2, &maxdist2);
  mintwisted= qh_RATIOtwisted * qh ONEmerge;
  maximize_(mintwisted, facet1->maxoutside);
  maximize_(mintwisted, facet2->maxoutside);
  if (dist > mintwisted && dist2 > mintwisted) {
    bestdist= qh_vertex_bestdist2(facet1->vertices, &bestvertex, &bestpinched);
    if (bestdist > mintwisted) {
      qh_fprintf(qh ferr, 6417, "qhull precision error (qh_merge_twisted): twisted facet f%d does not contain pinched vertices.  Too wide to merge into neighbor.  mindist %2.2g maxdist %2.2g vertexdist %2.2g maxpinched %2.2g neighbor f%d mindist %2.2g maxdist %2.2g\n",
        facet1->id, mindist, maxdist, bestdist, mintwisted, facet2->id, mindist2, maxdist2);
    }else {
      qh_fprintf(qh ferr, 6418, "qhull precision error (qh_merge_twisted): twisted facet f%d with pinched vertices.  Could merge vertices, but too wide to merge into neighbor.   mindist %2.2g maxdist %2.2g vertexdist %2.2g neighbor f%d mindist %2.2g maxdist %2.2g\n",
        facet1->id, mindist, maxdist, bestdist, facet2->id, mindist2, maxdist2);
    }
    qh_errexit2(qh_ERRwide, facet1, facet2);
  }
  if (dist < dist2) {
    merging= facet1;
    merged= neighbor;
  }else {
    /* ignores qh.AVOIDold ('Q4') */
    merging= facet2;
    merged= neighbor2;
    dist= dist2;
    mindist= mindist2;
    maxdist= maxdist2;
  }
  qh_mergefacet(merging, merged, MRGtwisted, &mindist, &maxdist, !qh_MERGEapex);
  /* caller merges qh_degenredundant */
  zinc_(Ztwisted);
  wadd_(Wtwistedtot, dist);
  wmax_(Wtwistedmax, dist);
} /* merge_twisted */

/*---------------------------------

  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

  notes:
    only called by qh_mergecycle_all for multiple, same cycle facets
    see qh_mergefacet

  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

  zzinc_(Ztotmerge);
  if (qh REPORTfreq2 && qh POSTmerging) {
    if (zzval_(Ztotmerge) > qh mergereport + qh REPORTfreq2)
      qh_tracemerging();
  }
#ifndef qh_NOtrace
  if (qh TRACEmerge == zzval_(Ztotmerge))
    qhmem.IStracing= qh IStracing= qh TRACElevel;
  trace2((qh ferr, 2030, "qh_mergecycle: merge #%d for facets from cycle f%d into coplanar horizon f%d\n",
        zzval_(Ztotmerge), samecycle->id, newfacet->id));
  if (newfacet == qh tracefacet) {
    tracerestore= qh IStracing;
    qh IStracing= 4;
    qh_fprintf(qh ferr, 8068, "qh_mergecycle: ========= trace merge %d of samecycle %d into trace f%d, furthest is p%d\n",
               zzval_(Ztotmerge), samecycle->id, newfacet->id,  qh furthest_id);
    traceonce= True;
  }
  if (qh IStracing >=4) {
    qh_fprintf(qh ferr, 8069, "  same cycle:");
    FORALLsame_cycle_(samecycle)
      qh_fprintf(qh ferr, 8070, " f%d", same->id);
    qh_fprintf(qh ferr, 8071, "\n");
  }
  if (qh IStracing >=4)
    qh_errprint("MERGING CYCLE", samecycle, newfacet, NULL, NULL);
#endif /* !qh_NOtrace */
  if (newfacet->tricoplanar) {
    if (!qh TRInormals) {
      qh_fprintf(qh ferr, 6224, "qhull internal error (qh_mergecycle): does not work for tricoplanar facets.  Use option 'Q11'\n");
      qh_errexit(qh_ERRqhull, newfacet, NULL);
    }
    newfacet->tricoplanar= False;
    newfacet->keepcentrum= False;
  }
  if (qh CHECKfrequently)
    qh_checkdelridge();
  if (!qh VERTEXneighbors)
    qh_vertexneighbors();
  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, MRGcoplanarhorizon);
  /* check for degen_redundant_neighbors after qh_forcedmerges() */
  if (traceonce) {
    qh_fprintf(qh ferr, 8072, "qh_mergecycle: end of trace facet\n");
    qh IStracing= tracerestore;
  }
} /* mergecycle */

/*---------------------------------

  qh_mergecycle_all( facetlist, wasmerge )
    merge all samecycles of coplanar facets into horizon
    don't merge facets with ->mergeridge (these already have ->normal)
    all facets are simplicial from apex
    all facet->cycledone == False

  returns:
    all newfacets merged into coplanar horizon facets
    deleted vertices on  qh.del_vertices
    sets wasmerge if any merge

  notes:
    called by qh_premerge
    calls qh_mergecycle for multiple, same cycle facets

  design:
    for each facet on facetlist
      skip facets with dupridges 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 dupridges from samecycle
        merge samecycle into horizon (deletes facets from facetlist)
*/
void qh_mergecycle_all(facetT *facetlist, boolT *wasmerge) {
  facetT *facet, *same, *prev, *horizon, *newfacet;
  facetT *samecycle= NULL, *nextfacet, *nextsame;
  vertexT *apex, *vertex, **vertexp;
  int cycles=0, total=0, facets, nummerge, numdegen= 0;

  trace2((qh ferr, 2031, "qh_mergecycle_all: merge new facets into coplanar horizon facets.  Bulk merge a cycle of facets with the same horizon facet\n"));
  for (facet=facetlist; facet && (nextfacet= facet->next); facet= nextfacet) {
    if (facet->normal)
      continue;
    if (!facet->mergehorizon) {
      qh_fprintf(qh ferr, 6225, "qhull internal error (qh_mergecycle_all): f%d without normal\n", facet->id);
      qh_errexit(qh_ERRqhull, facet, NULL);
    }
    horizon= SETfirstt_(facet->neighbors, facetT);
    if (facet->f.samecycle == facet) {
      if (qh TRACEmerge-1 == zzval_(Ztotmerge))
        qhmem.IStracing= qh IStracing= qh TRACElevel;
      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, MRGcoplanarhorizon, NULL, NULL, qh_MERGEapex);
    }else {
      samecycle= facet;
      facets= 0;
      prev= facet;
      for (same= facet->f.samecycle; same;  /* FORALLsame_cycle_(facet) */
           same= (same == facet ? NULL :nextsame)) { /* ends at facet */
        nextsame= same->f.samecycle;
        if (same->cycledone || same->visible)
          qh_infiniteloop(same);
        same->cycledone= True;
        if (same->normal) {
          prev->f.samecycle= same->f.samecycle; /* unlink ->mergeridge */
          same->f.samecycle= NULL;
        }else {
          prev= same;
          facets++;
        }
      }
      while (nextfacet && nextfacet->cycledone)  /* will delete samecycle */
        nextfacet= nextfacet->next;
      horizon->f.newcycle= NULL;
      qh_mergecycle(samecycle, horizon);
      nummerge= horizon->nummerge + facets;
      if (nummerge > qh_MAXnummerge)
        horizon->nummerge= qh_MAXnummerge;
      else
        horizon->nummerge= (short unsigned int)nummerge; /* limited to 9 bits by qh_MAXnummerge, -Wconversion */
      zzinc_(Zcyclehorizon);
      total += facets;
      zzadd_(Zcyclefacettot, facets);
      zmax_(Zcyclefacetmax, facets);
    }
    cycles++;
  }
  if (cycles) {
    FORALLnew_facets {
      /* qh_maybe_duplicateridges postponed since qh_mergecycle_ridges deletes ridges without calling qh_delridge_merge */
      if (newfacet->coplanarhorizon) {
        qh_test_redundant_neighbors(newfacet);
        qh_maybe_duplicateridges(newfacet);
        newfacet->coplanarhorizon= False;
      }
    }
    numdegen += qh_merge_degenredundant();
    *wasmerge= True;
    trace1((qh ferr, 1013, "qh_mergecycle_all: merged %d same cycles or facets into coplanar horizons and %d degenredundant facets\n",
      cycles, numdegen));
  }
} /* mergecycle_all */

/*---------------------------------

  qh_mergecycle_facets( samecycle, newfacet )
    finish merge of samecycle into newfacet

  returns:
    samecycle prepended to visible_list for later deletion and partitioning
      each facet->f.replace == newfacet

    newfacet moved to end of qh.facet_list
      makes newfacet a newfacet (get's facet1->id if it was old)
      sets newfacet->newmerge
      clears newfacet->center (unless merging into a large facet)
      clears newfacet->tested and ridge->tested for facet1

    adds neighboring facets to facet_mergeset if redundant or degenerate

  design:
    make newfacet a new facet and set its flags
    move samecycle facets to qh.visible_list for later deletion
    unless newfacet is large
      remove its centrum
*/
void qh_mergecycle_facets(facetT *samecycle, facetT *newfacet) {
  facetT *same, *next;

  trace4((qh ferr, 4030, "qh_mergecycle_facets: make newfacet new and samecycle deleted\n"));
  qh_removefacet(newfacet);  /* append as a newfacet to end of qh facet_list */
  qh_appendfacet(newfacet);
  newfacet->newfacet= True;
  newfacet->simplicial= False;
  newfacet->newmerge= True;

  for (same= samecycle->f.samecycle; same; same= (same == samecycle ?  NULL : next)) {
    next= same->f.samecycle;  /* reused by willdelete */
    qh_willdelete(same, newfacet);
  }
  if (newfacet->center
      && qh_setsize(newfacet->vertices) <= qh hull_dim + qh_MAXnewcentrum) {
    qh_memfree(newfacet->center, qh normal_size);
    newfacet->center= NULL;
  }
  trace3((qh ferr, 3004, "qh_mergecycle_facets: merged facets from cycle f%d into f%d\n",
             samecycle->id, newfacet->id));
} /* mergecycle_facets */

/*---------------------------------

  qh_mergecycle_neighbors( samecycle, newfacet )
    add neighbors for samecycle facets to newfacet

  returns:
    newfacet with updated neighbors and vice-versa
    newfacet has ridges
    all neighbors of newfacet marked with qh.visit_id
    samecycle facets marked with qh.visit_id-1
    ridges updated for simplicial neighbors of samecycle with a ridge

  notes:
    assumes newfacet not in samecycle
    usually, samecycle facets are new, simplicial facets without internal ridges
      not so if horizon facet is coplanar to two different samecycles

  see:
    qh_mergeneighbors()

  design:
    check samecycle
    delete neighbors from newfacet that are also in samecycle
    for each neighbor of a facet in samecycle
      if neighbor is simplicial
        if first visit
          move the neighbor relation to newfacet
          update facet links for its ridges
        else
          make ridges for neighbor
          remove samecycle reference
      else
        update neighbor sets
*/
void qh_mergecycle_neighbors(facetT *samecycle, facetT *newfacet) {
  facetT *same, *neighbor, **neighborp;
  int delneighbors= 0, newneighbors= 0;
  unsigned int samevisitid;
  ridgeT *ridge, **ridgep;

  samevisitid= ++qh visit_id;
  FORALLsame_cycle_(samecycle) {
    if (same->visitid == samevisitid || same->visible)
      qh_infiniteloop(samecycle);
    same->visitid= samevisitid;
  }
  newfacet->visitid= ++qh visit_id;
  trace4((qh ferr, 4031, "qh_mergecycle_neighbors: delete shared neighbors from newfacet\n"));
  FOREACHneighbor_(newfacet) {
    if (neighbor->visitid == samevisitid) {
      SETref_(neighbor)= NULL;  /* samecycle neighbors deleted */
      delneighbors++;
    }else
      neighbor->visitid= qh visit_id;
  }
  qh_setcompact(newfacet->neighbors);

  trace4((qh ferr, 4032, "qh_mergecycle_neighbors: update neighbors\n"));
  FORALLsame_cycle_(samecycle) {
    FOREACHneighbor_(same) {
      if (neighbor->visitid == samevisitid)
        continue;
      if (neighbor->simplicial) {
        if (neighbor->visitid != qh visit_id) {
          qh_setappend(&newfacet->neighbors, neighbor);
          qh_setreplace(neighbor->neighbors, same, newfacet);
          newneighbors++;
          neighbor->visitid= qh visit_id;
          FOREACHridge_(neighbor->ridges) { /* update ridge in case of qh_makeridges */
            if (ridge->top == same) {
              ridge->top= newfacet;
              break;
            }else if (ridge->bottom == same) {
              ridge->bottom= newfacet;
              break;
            }
          }
        }else {
          qh_makeridges(neighbor);
          qh_setdel(neighbor->neighbors, same);
          /* same can't be horizon facet for neighbor */
        }
      }else { /* non-simplicial neighbor */
        qh_setdel(neighbor->neighbors, same);
        if (neighbor->visitid != qh visit_id) {
          qh_setappend(&neighbor->neighbors, newfacet);
          qh_setappend(&newfacet->neighbors, neighbor);
          neighbor->visitid= qh visit_id;
          newneighbors++;
        }
      }
    }
  }
  trace2((qh ferr, 2032, "qh_mergecycle_neighbors: deleted %d neighbors and added %d\n",
             delneighbors, newneighbors));
} /* mergecycle_neighbors */

/*---------------------------------

  qh_mergecycle_ridges( samecycle, newfacet )
    add ridges/neighbors for facets in samecycle to newfacet
    all new/old neighbors of newfacet marked with qh.visit_id
    facets in samecycle marked with qh.visit_id-1
    newfacet marked with qh.visit_id

  returns:
    newfacet has merged ridges

  notes:
    ridge already updated for simplicial neighbors of samecycle with a ridge
    qh_checkdelridge called by qh_mergecycle

  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 simplicial 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 if !qh_NOmem by qh_memfree_() */

  trace4((qh ferr, 4033, "qh_mergecycle_ridges: delete shared ridges from newfacet\n"));
  samevisitid= qh visit_id -1;
  FOREACHridge_(newfacet->ridges) {
    neighbor= otherfacet_(ridge, newfacet);
    if (neighbor->visitid == samevisitid)
      SETref_(ridge)= NULL; /* ridge free'd below */
  }
  qh_setcompact(newfacet->ridges);

  trace4((qh ferr, 4034, "qh_mergecycle_ridges: add ridges to newfacet\n"));
  FORALLsame_cycle_(samecycle) {
    FOREACHridge_(same->ridges) {
      if (ridge->top == same) {
        ridge->top= newfacet;
        neighbor= ridge->bottom;
      }else if (ridge->bottom == same) {
        ridge->bottom= newfacet;
        neighbor= ridge->top;
      }else if (ridge->top == newfacet || ridge->bottom == newfacet) {
        qh_setappend(&newfacet->ridges, ridge);
        numold++;  /* already set by qh_mergecycle_neighbors */
        continue;
      }else {
        qh_fprintf(qh ferr, 6098, "qhull internal error (qh_mergecycle_ridges): bad ridge r%d\n", ridge->id);
        qh_errexit(qh_ERRqhull, NULL, ridge);
      }
      if (neighbor == newfacet) {
        if (qh traceridge == ridge)
          qh traceridge= NULL;
        qh_setfree(&(ridge->vertices));
        qh_memfree_(ridge, (int)sizeof(ridgeT), freelistp);
        numold++;
      }else if (neighbor->visitid == samevisitid) {
        qh_setdel(neighbor->ridges, ridge);
        if (qh traceridge == ridge)
          qh traceridge= NULL;
        qh_setfree(&(ridge->vertices));
        qh_memfree_(ridge, (int)sizeof(ridgeT), freelistp);
        numold++;
      }else {
        qh_setappend(&newfacet->ridges, ridge);
        numold++;
      }
    }
    if (same->ridges)
      qh_settruncate(same->ridges, 0);
    if (!same->simplicial)
      continue;
    FOREACHneighbor_i_(same) {       /* note: !newfact->simplicial */
      if (neighbor->visitid != samevisitid && neighbor->simplicial) {
        ridge= qh_newridge();
        ridge->vertices= qh_setnew_delnthsorted(same->vertices, qh hull_dim,
                                                          neighbor_i, 0);
        toporient= (boolT)(same->toporient ^ (neighbor_i & 0x1));
        if (toporient) {
          ridge->top= newfacet;
          ridge->bottom= neighbor;
          ridge->simplicialbot= True;
        }else {
          ridge->top= neighbor;
          ridge->bottom= newfacet;
          ridge->simplicialtop= True;
        }
        qh_setappend(&(newfacet->ridges), ridge);
        qh_setappend(&(neighbor->ridges), ridge);
        if (qh ridge_id == qh traceridge_id)
          qh traceridge= ridge;
        numnew++;
      }
    }
  }

  trace2((qh ferr, 2033, "qh_mergecycle_ridges: found %d old ridges and %d new ones\n",
             numold, numnew));
} /* mergecycle_ridges */

/*---------------------------------

  qh_mergecycle_vneighbors( samecycle, newfacet )
    create vertex neighbors for newfacet from vertices of facets in samecycle
    samecycle marked with visitid == qh.visit_id - 1

  returns:
    newfacet vertices with updated neighbors
    marks newfacet with qh.visit_id-1
    deletes vertices that are merged away
    sets delridge on all vertices (faster here than in mergecycle_ridges)

  see:
    qh_mergevertex_neighbors()

  design:
    for each vertex of samecycle facet
      set vertex->delridge
      delete samecycle facets from vertex neighbors
      append newfacet to vertex neighbors
      if vertex only in newfacet
        delete it from newfacet
        add it to qh.del_vertices for later deletion
*/
void qh_mergecycle_vneighbors(facetT *samecycle, facetT *newfacet) {
  facetT *neighbor, **neighborp;
  unsigned int mergeid;
  vertexT *vertex, **vertexp, *apex;
  setT *vertices;

  trace4((qh ferr, 4035, "qh_mergecycle_vneighbors: update vertex neighbors for newfacet\n"));
  mergeid= qh visit_id - 1;
  newfacet->visitid= mergeid;
  vertices= qh_basevertices(samecycle); /* temp */
  apex= SETfirstt_(samecycle->vertices, vertexT);
  qh_setappend(&vertices, apex);
  FOREACHvertex_(vertices) {
    vertex->delridge= True;
    FOREACHneighbor_(vertex) {
      if (neighbor->visitid == mergeid)
        SETref_(neighbor)= NULL;
    }
    qh_setcompact(vertex->neighbors);
    qh_setappend(&vertex->neighbors, newfacet);
    if (!SETsecond_(vertex->neighbors)) {
      zinc_(Zcyclevertex);
      trace2((qh ferr, 2034, "qh_mergecycle_vneighbors: deleted v%d when merging cycle f%d into f%d\n",
        vertex->id, samecycle->id, newfacet->id));
      qh_setdelsorted(newfacet->vertices, vertex);
      vertex->deleted= True;
      qh_setappend(&qh del_vertices, vertex);
    }
  }
  qh_settempfree(&vertices);
  trace3((qh ferr, 3005, "qh_mergecycle_vneighbors: merged vertices from cycle f%d into f%d\n",
             samecycle->id, newfacet->id));
} /* mergecycle_vneighbors */

/*---------------------------------

  qh_mergefacet( facet1, facet2, mergetype, mindist, maxdist, mergeapex )
    merges facet1 into facet2
    mergeapex==qh_MERGEapex if merging new facet into coplanar horizon (optimizes qh_mergesimplex)

  returns:
    qh.max_outside and qh.min_vertex updated
    initializes vertex neighbors on first merge

  note:
    mergetype only used for logging and error reporting

  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:
    when done, tests facet1 and facet2 for degenerate or redundant neighbors and dupridges
    mindist/maxdist may be NULL (only if both NULL)
    traces merge if fmax_(maxdist,-mindist) > TRACEdist

  see:
    qh_mergecycle()

  design:
    trace merge and check for degenerate simplex
    make ridges for both facets
    update qh.max_outside, qh.max_vertex, qh.min_vertex
    update facet2->maxoutside and keepcentrum
    update facet2->nummerge
    update tested flags for facet2
    if facet1 is simplicial
      merge facet1 into facet2
    else
      merge facet1's neighbors into facet2
      merge facet1's ridges into facet2
      merge facet1's vertices into facet2
      merge facet1's vertex neighbors into facet2
      add facet2's vertices to qh.new_vertexlist
    move facet2 to end of qh.newfacet_list
    unless MRGcoplanarhorizon
      test facet2 for redundant neighbors
      test facet1 for degenerate neighbors
      test for redundant facet2
      maybe test for duplicate ridges ('Q15')
    move facet1 to qh.visible_list for later deletion
*/
void qh_mergefacet(facetT *facet1, facetT *facet2, mergeType mergetype, realT *mindist, realT *maxdist, boolT mergeapex) {
  boolT traceonce= False;
  vertexT *vertex, **vertexp;
  realT mintwisted, vertexdist;
  realT onemerge;
  int tracerestore=0, nummerge;
  const char *mergename;

  if(mergetype > 0 && mergetype < sizeof(mergetypes)/sizeof(char *))
    mergename= mergetypes[mergetype];
  else
    mergename= mergetypes[MRGnone];
  if (facet1->tricoplanar || facet2->tricoplanar) {
    if (!qh TRInormals) {
      qh_fprintf(qh ferr, 6226, "qhull internal error (qh_mergefacet): merge f%d into f%d for mergetype %d (%s) does not work for tricoplanar facets.  Use option 'Q11'\n",
        facet1->id, facet2->id, mergetype, mergename);
      qh_errexit2(qh_ERRqhull, facet1, facet2);
    }
    if (facet2->tricoplanar) {
      facet2->tricoplanar= False;
      facet2->keepcentrum= False;
    }
  }
  zzinc_(Ztotmerge);
  if (qh REPORTfreq2 && qh POSTmerging) {
    if (zzval_(Ztotmerge) > qh mergereport + qh REPORTfreq2)
      qh_tracemerging();
  }
#ifndef qh_NOtrace
  if (qh build_cnt >= qh RERUN) {
    if (mindist && (-*mindist > qh TRACEdist || *maxdist > qh TRACEdist)) {
      tracerestore= 0;
      qh IStracing= qh TRACElevel;
      traceonce= True;
      qh_fprintf(qh ferr, 8075, "qh_mergefacet: ========= trace wide merge #%d(%2.2g) for f%d into f%d for mergetype %d (%s), last point was p%d\n",
          zzval_(Ztotmerge), fmax_(-*mindist, *maxdist), facet1->id, facet2->id, mergetype, mergename, qh furthest_id);
    }else if (facet1 == qh tracefacet || facet2 == qh tracefacet) {
      tracerestore= qh IStracing;
      qh IStracing= 4;
      traceonce= True;
      qh_fprintf(qh ferr, 8076, "qh_mergefacet: ========= trace merge #%d for f%d into f%d for mergetype %d (%s), furthest is p%d\n",
                 zzval_(Ztotmerge), facet1->id, facet2->id, mergetype, mergename, qh furthest_id);
    }
  }
  if (qh IStracing >= 2) {
    realT mergemin= -2;
    realT mergemax= -2;

    if (mindist) {
      mergemin= *mindist;
      mergemax= *maxdist;
    }
    qh_fprintf(qh ferr, 2081, "qh_mergefacet: #%d merge f%d into f%d for merge for mergetype %d (%s), mindist= %2.2g, maxdist= %2.2g, max_outside %2.2g\n",
    zzval_(Ztotmerge), facet1->id, facet2->id, mergetype, mergename, mergemin, mergemax, qh max_outside);
  }
#endif /* !qh_NOtrace */
  if(!qh ALLOWwide && mindist) {
    mintwisted= qh_WIDEmaxoutside * qh ONEmerge;  /* same as qh_merge_twisted and qh_check_maxout (poly2) */
    maximize_(mintwisted, facet1->maxoutside);
    maximize_(mintwisted, facet2->maxoutside);
    if (*maxdist > mintwisted || -*mindist > mintwisted) {
      vertexdist= qh_vertex_bestdist(facet1->vertices);
      onemerge= qh ONEmerge + qh DISTround;
      if (vertexdist > mintwisted) {
        qh_fprintf(qh ferr, 6347, "qhull precision error (qh_mergefacet): wide merge for facet f%d into f%d for mergetype %d (%s).  maxdist %2.2g (%.1fx) mindist %2.2g (%.1fx) vertexdist %2.2g  Allow with 'Q12' (allow-wide)\n",
          facet1->id, facet2->id, mergetype, mergename, *maxdist, *maxdist/onemerge, *mindist, -*mindist/onemerge, vertexdist);
      }else {
        qh_fprintf(qh ferr, 6348, "qhull precision error (qh_mergefacet): wide merge for pinched facet f%d into f%d for mergetype %d (%s).  maxdist %2.2g (%.fx) mindist %2.2g (%.1fx) vertexdist %2.2g  Allow with 'Q12' (allow-wide)\n",
          facet1->id, facet2->id, mergetype, mergename, *maxdist, *maxdist/onemerge, *mindist, -*mindist/onemerge, vertexdist);
      }
      qh_errexit2(qh_ERRwide, facet1, facet2);
    }
  }
  if (facet1 == facet2 || facet1->visible || facet2->visible) {
    qh_fprintf(qh ferr, 6099, "qhull internal error (qh_mergefacet): either f%d and f%d are the same or one is a visible facet, mergetype %d (%s)\n",
             facet1->id, facet2->id, mergetype, mergename);
    qh_errexit2(qh_ERRqhull, facet1, facet2);
  }
  if (qh num_facets - qh num_visible <= qh hull_dim + 1) {
    qh_fprintf(qh ferr, 6227, "qhull topology error: Only %d facets remain.  The input is too degenerate or the convexity constraints are too strong.\n", 
          qh hull_dim+1);
    if (qh hull_dim >= 5 && !qh MERGEexact)
      qh_fprintf(qh ferr, 8079, "    Option 'Qx' may avoid this problem.\n");
    qh_errexit(qh_ERRtopology, NULL, NULL);
  }
  if (!qh VERTEXneighbors)
    qh_vertexneighbors();
  qh_makeridges(facet1);
  qh_makeridges(facet2);
  if (qh IStracing >=4)
    qh_errprint("MERGING", facet1, facet2, NULL, NULL);
  if (mindist) {
    maximize_(qh max_outside, *maxdist);
    maximize_(qh max_vertex, *maxdist);
#if qh_MAXoutside
    maximize_(facet2->maxoutside, *maxdist);
#endif
    minimize_(qh min_vertex, *mindist);
    if (!facet2->keepcentrum
    && (*maxdist > qh WIDEfacet || *mindist < -qh WIDEfacet)) {
      facet2->keepcentrum= True;
      zinc_(Zwidefacet);
    }
  }
  nummerge= facet1->nummerge + facet2->nummerge + 1;
  if (nummerge >= qh_MAXnummerge)
    facet2->nummerge= qh_MAXnummerge;
  else
    facet2->nummerge= (short unsigned int)nummerge; /* limited to 9 bits by qh_MAXnummerge, -Wconversion */
  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 (facet2->coplanarhorizon) {
    zinc_(Zmergeintocoplanar);
  }else if (!facet2->newfacet) {
    zinc_(Zmergeintohorizon);
  }else if (!facet1->newfacet && facet2->newfacet) {
    zinc_(Zmergehorizon);
  }else {
    zinc_(Zmergenew);
  }
  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, mergetype);
  if (traceonce) {
    qh_fprintf(qh ferr, 8080, "qh_mergefacet: end of wide tracing\n");
    qh IStracing= tracerestore;
  }
  if (mergetype != MRGcoplanarhorizon) {
    trace3((qh ferr, 3076, "qh_mergefacet: check f%d and f%d for redundant and degenerate neighbors\n",
        facet1->id, facet2->id));
    qh_test_redundant_neighbors(facet2);
    qh_test_degen_neighbors(facet1);  /* after qh_test_redundant_neighbors since MRGdegen more difficult than MRGredundant
                                             and before qh_willdelete which clears facet1.neighbors */
    qh_degen_redundant_facet(facet2); /* may occur in qh_merge_pinchedvertices, e.g., rbox 175 C3,2e-13 D4 t1545228104 | qhull d */
    qh_maybe_duplicateridges(facet2);
  }
  qh_willdelete(facet1, facet2);
} /* mergefacet */


/*---------------------------------

  qh_mergefacet2d( facet1, facet2 )
    in 2d, merges neighbors and vertices of facet1 into facet2

  returns:
    build ridges for neighbors if necessary
    facet2 looks like a simplicial facet except for centrum, ridges
      neighbors are opposite the corresponding vertex
      maintains orientation of facet2

  notes:
    qh_mergefacet() retains non-simplicial structures
      they are not needed in 2d, but later routines may use them
    preserves qh.vertex_visit for qh_mergevertex_neighbors()

  design:
    get vertices and neighbors
    determine new vertices and neighbors
    set new vertices and neighbors and adjust orientation
    make ridges for new neighbor if needed
*/
void qh_mergefacet2d(facetT *facet1, facetT *facet2) {
  vertexT *vertex1A, *vertex1B, *vertex2A, *vertex2B, *vertexA, *vertexB;
  facetT *neighbor1A, *neighbor1B, *neighbor2A, *neighbor2B, *neighborA, *neighborB;

  vertex1A= SETfirstt_(facet1->vertices, vertexT);
  vertex1B= SETsecondt_(facet1->vertices, vertexT);
  vertex2A= SETfirstt_(facet2->vertices, vertexT);
  vertex2B= SETsecondt_(facet2->vertices, vertexT);
  neighbor1A= SETfirstt_(facet1->neighbors, facetT);
  neighbor1B= SETsecondt_(facet1->neighbors, facetT);
  neighbor2A= SETfirstt_(facet2->neighbors, facetT);
  neighbor2B= SETsecondt_(facet2->neighbors, facetT);
  if (vertex1A == vertex2A) {
    vertexA= vertex1B;
    vertexB= vertex2B;
    neighborA= neighbor2A;
    neighborB= neighbor1A;
  }else if (vertex1A == vertex2B) {
    vertexA= vertex1B;
    vertexB= vertex2A;
    neighborA= neighbor2B;
    neighborB= neighbor1A;
  }else if (vertex1B == vertex2A) {
    vertexA= vertex1A;
    vertexB= vertex2B;
    neighborA= neighbor2A;
    neighborB= neighbor1B;
  }else { /* 1B == 2B */
    vertexA= vertex1A;
    vertexB= vertex2A;
    neighborA= neighbor2B;
    neighborB= neighbor1B;
  }
  /* vertexB always from facet2, neighborB always from facet1 */
  if (vertexA->id > vertexB->id) {
    SETfirst_(facet2->vertices)= vertexA;
    SETsecond_(facet2->vertices)= vertexB;
    if (vertexB == vertex2A)
      facet2->toporient= !facet2->toporient;
    SETfirst_(facet2->neighbors)= neighborA;
    SETsecond_(facet2->neighbors)= neighborB;
  }else {
    SETfirst_(facet2->vertices)= vertexB;
    SETsecond_(facet2->vertices)= vertexA;
    if (vertexB == vertex2B)
      facet2->toporient= !facet2->toporient;
    SETfirst_(facet2->neighbors)= neighborB;
    SETsecond_(facet2->neighbors)= neighborA;
  }
  /* qh_makeridges not needed since neighborB is not degenerate */
  qh_setreplace(neighborB->neighbors, facet1, facet2);
  trace4((qh ferr, 4036, "qh_mergefacet2d: merged v%d and neighbor f%d of f%d into f%d\n",
       vertexA->id, neighborB->id, facet1->id, facet2->id));
} /* mergefacet2d */


/*---------------------------------

  qh_mergeneighbors( facet1, facet2 )
    merges the neighbors of facet1 into facet2

  notes:
    only called by qh_mergefacet
    qh.hull_dim >= 3
    see qh_mergecycle_neighbors

  design:
    for each neighbor of facet1
      if neighbor is also a neighbor of facet2
        if neighbor is simplicial
          make ridges for later deletion as a degenerate facet
        update its neighbor set
      else
        move the neighbor relation to facet2
    remove the neighbor relation for facet1 and facet2
*/
void qh_mergeneighbors(facetT *facet1, facetT *facet2) {
  facetT *neighbor, **neighborp;

  trace4((qh ferr, 4037, "qh_mergeneighbors: merge neighbors of f%d and f%d\n",
          facet1->id, facet2->id));
  qh visit_id++;
  FOREACHneighbor_(facet2) {
    neighbor->visitid= qh visit_id;
  }
  FOREACHneighbor_(facet1) {
    if (neighbor->visitid == qh visit_id) {
      if (neighbor->simplicial)    /* is degen, needs ridges */
        qh_makeridges(neighbor);
      if (SETfirstt_(neighbor->neighbors, facetT) != facet1) /*keep newfacet->horizon*/
        qh_setdel(neighbor->neighbors, facet1);
      else {
        qh_setdel(neighbor->neighbors, facet2);
        qh_setreplace(neighbor->neighbors, facet1, facet2);
      }
    }else if (neighbor != facet2) {
      qh_setappend(&(facet2->neighbors), neighbor);
      qh_setreplace(neighbor->neighbors, facet1, facet2);
    }
  }
  qh_setdel(facet1->neighbors, facet2);  /* here for makeridges */
  qh_setdel(facet2->neighbors, facet1);
} /* mergeneighbors */


/*---------------------------------

  qh_mergeridges( facet1, facet2 )
    merges the ridge set of facet1 into facet2

  returns:
    may delete all ridges for a vertex
    sets vertex->delridge on deleted ridges

  see:
    qh_mergecycle_ridges()

  design:
    delete ridges between facet1 and facet2
      mark (delridge) vertices on these ridges for later testing
    for each remaining ridge
      rename facet1 to facet2
*/
void qh_mergeridges(facetT *facet1, facetT *facet2) {
  ridgeT *ridge, **ridgep;

  trace4((qh ferr, 4038, "qh_mergeridges: merge ridges of f%d into f%d\n",
          facet1->id, facet2->id));
  FOREACHridge_(facet2->ridges) {
    if ((ridge->top == facet1) || (ridge->bottom == facet1)) {
      /* ridge.nonconvex is irrelevant due to merge */
      qh_delridge_merge(ridge);  /* expensive in high-d, could rebuild */
      ridgep--; /* deleted this ridge, repeat with next ridge*/
    }
  }
  FOREACHridge_(facet1->ridges) {
    if (ridge->top == facet1) {
      ridge->top= facet2;
      ridge->simplicialtop= False;
    }else { /* ridge.bottom is facet1 */
      ridge->bottom= facet2;
      ridge->simplicialbot= False;
    }
    qh_setappend(&(facet2->ridges), ridge);
  }
} /* mergeridges */


/*---------------------------------

  qh_mergesimplex( facet1, facet2, mergeapex )
    merge simplicial facet1 into facet2
    mergeapex==qh_MERGEapex if merging samecycle into horizon facet
      vertex id is latest (most recently created)
    facet1 may be contained in facet2
    ridges exist for both facets

  returns:
    facet2 with updated vertices, ridges, neighbors
    updated neighbors for facet1's vertices
    facet1 not deleted
    sets vertex->delridge on deleted ridges

  notes:
    special case code since this is the most common merge
    called from qh_mergefacet()

  design:
    if qh_MERGEapex
      add vertices of facet2 to qh.new_vertexlist if necessary
      add apex to facet2
    else
      for each ridge between facet1 and facet2
        set vertex->delridge
      determine the apex for facet1 (i.e., vertex to be merged)
      unless apex already in facet2
        insert apex into vertices for facet2
      add vertices of facet2 to qh.new_vertexlist if necessary
      add apex to qh.new_vertexlist if necessary
      for each vertex of facet1
        if apex
          rename facet1 to facet2 in its vertex neighbors
        else
          delete facet1 from vertex neighbors
          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, *opposite;
  ridgeT *ridge, **ridgep;
  boolT isnew= False;
  facetT *neighbor, **neighborp, *otherfacet;

  if (mergeapex) {
    opposite= SETfirstt_(facet1->vertices, vertexT); /* apex is opposite facet2.  It has the last vertex id */
    trace4((qh ferr, 4086, "qh_mergesimplex: merge apex v%d of f%d into facet f%d\n",
      opposite->id, facet1->id, facet2->id));
    if (!facet2->newfacet)
      qh_newvertices(facet2->vertices);  /* apex, the first vertex, is already new */
    if (SETfirstt_(facet2->vertices, vertexT) != opposite) {
      qh_setaddnth(&facet2->vertices, 0, opposite);
      isnew= 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 */
    }
    opposite= vertex;
    trace4((qh ferr, 4039, "qh_mergesimplex: merge opposite v%d of f%d into facet f%d\n",
          opposite->id, facet1->id, facet2->id));
    isnew= qh_addfacetvertex(facet2, opposite);
    if (!facet2->newfacet)
      qh_newvertices(facet2->vertices);
    else if (!opposite->newfacet) {
      qh_removevertex(opposite);
      qh_appendvertex(opposite);
    }
  }
  trace4((qh ferr, 4040, "qh_mergesimplex: update vertex neighbors of f%d\n",
          facet1->id));
  FOREACHvertex_(facet1->vertices) {
    if (vertex == opposite && isnew)
      qh_setreplace(vertex->neighbors, facet1, facet2);
    else {
      qh_setdel(vertex->neighbors, facet1);
      if (!SETsecond_(vertex->neighbors))
        qh_mergevertex_del(vertex, facet1, facet2);
    }
  }
  trace4((qh ferr, 4041, "qh_mergesimplex: merge ridges and neighbors of f%d into f%d\n",
          facet1->id, facet2->id));
  qh visit_id++;
  FOREACHneighbor_(facet2)
    neighbor->visitid= qh visit_id;
  FOREACHridge_(facet1->ridges) {
    otherfacet= otherfacet_(ridge, facet1);
    if (otherfacet == facet2) {
      /* ridge.nonconvex is irrelevant due to merge */
      qh_delridge_merge(ridge);  /* expensive in high-d, could rebuild */
      ridgep--; /* deleted this ridge, repeat with next ridge*/
      qh_setdel(facet2->neighbors, facet1); /* a simplicial facet may have duplicate neighbors, need to delete each one */
    }else if (otherfacet->dupridge && !qh_setin(otherfacet->neighbors, facet1)) {
      qh_fprintf(qh ferr, 6356, "qhull topology error (qh_mergesimplex): f%d is a dupridge of f%d, cannot merge f%d into f%d\n",
        facet1->id, otherfacet->id, facet1->id, facet2->id);
      qh_errexit2(qh_ERRqhull, facet1, otherfacet);
    }else {
      trace4((qh ferr, 4059, "qh_mergesimplex: move r%d with f%d to f%d, new neighbor? %d, maybe horizon? %d\n",
        ridge->id, otherfacet->id, facet2->id, (otherfacet->visitid != qh visit_id), (SETfirstt_(otherfacet->neighbors, facetT) == facet1)));
      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) {
          /* keep new, otherfacet->neighbors->horizon */
          qh_setdel(otherfacet->neighbors, facet2);
          qh_setreplace(otherfacet->neighbors, facet1, facet2);
        }else {
          /* facet2 is already a neighbor of otherfacet, by f.visitid */
          qh_setdel(otherfacet->neighbors, facet1);
        }
      }
      if (ridge->top == facet1) { /* wait until after qh_makeridges */
        ridge->top= facet2;
        ridge->simplicialtop= False;
      }else {
        ridge->bottom= facet2;
        ridge->simplicialbot= False;
      }
    }
  }
  trace3((qh ferr, 3006, "qh_mergesimplex: merged simplex f%d v%d into facet f%d\n",
          facet1->id, opposite->id, facet2->id));
} /* mergesimplex */

/*---------------------------------

  qh_mergevertex_del( vertex, facet1, facet2 )
    delete a vertex because of merging facet1 into facet2

  returns:
    deletes vertex from facet2
    adds vertex to qh.del_vertices for later deletion
*/
void qh_mergevertex_del(vertexT *vertex, facetT *facet1, facetT *facet2) {

  zinc_(Zmergevertex);
  trace2((qh ferr, 2035, "qh_mergevertex_del: deleted v%d when merging f%d into f%d\n",
          vertex->id, facet1->id, facet2->id));
  qh_setdelsorted(facet2->vertices, vertex);
  vertex->deleted= True;
  qh_setappend(&qh del_vertices, vertex);
} /* mergevertex_del */

/*---------------------------------

  qh_mergevertex_neighbors( facet1, facet2 )
    merge the vertex neighbors of facet1 to facet2

  returns:
    if vertex is current qh.vertex_visit
      deletes facet1 from vertex->neighbors
    else
      renames facet1 to facet2 in vertex->neighbors
    deletes vertices if only one neighbor

  notes:
    assumes vertex neighbor sets are good
*/
void qh_mergevertex_neighbors(facetT *facet1, facetT *facet2) {
  vertexT *vertex, **vertexp;

  trace4((qh ferr, 4042, "qh_mergevertex_neighbors: merge vertex neighborset for f%d into f%d\n",
          facet1->id, facet2->id));
  if (qh tracevertex) {
    qh_fprintf(qh ferr, 8081, "qh_mergevertex_neighbors: of f%d into f%d at furthest p%d f0= %p\n",
             facet1->id, facet2->id, qh furthest_id, qh tracevertex->neighbors->e[0].p);
    qh_errprint("TRACE", NULL, NULL, NULL, qh tracevertex);
  }
  FOREACHvertex_(facet1->vertices) {
    if (vertex->visitid != qh vertex_visit)
      qh_setreplace(vertex->neighbors, facet1, facet2);
    else {
      qh_setdel(vertex->neighbors, facet1);
      if (!SETsecond_(vertex->neighbors))
        qh_mergevertex_del(vertex, facet1, facet2);
    }
  }
  if (qh tracevertex)
    qh_errprint("TRACE", NULL, NULL, NULL, qh tracevertex);
} /* mergevertex_neighbors */


/*---------------------------------

  qh_mergevertices( vertices1, vertices2 )
    merges the vertex set of facet1 into facet2

  returns:
    replaces vertices2 with merged set
    preserves vertex_visit for qh_mergevertex_neighbors
    updates qh.newvertex_list

  design:
    create a merged set of both vertices (in inverse id order)
*/
void qh_mergevertices(setT *vertices1, setT **vertices2) {
  int newsize= qh_setsize(vertices1)+qh_setsize(*vertices2) - qh hull_dim + 1;
  setT *mergedvertices;
  vertexT *vertex, **vertexp, **vertex2= SETaddr_(*vertices2, vertexT);

  mergedvertices= qh_settemp(newsize);
  FOREACHvertex_(vertices1) {
    if (!*vertex2 || vertex->id > (*vertex2)->id)
      qh_setappend(&mergedvertices, vertex);
    else {
      while (*vertex2 && (*vertex2)->id > vertex->id)
        qh_setappend(&mergedvertices, *vertex2++);
      if (!*vertex2 || (*vertex2)->id < vertex->id)
        qh_setappend(&mergedvertices, vertex);
      else
        qh_setappend(&mergedvertices, *vertex2++);
    }
  }
  while (*vertex2)
    qh_setappend(&mergedvertices, *vertex2++);
  if (newsize < qh_setsize(mergedvertices)) {
    qh_fprintf(qh ferr, 6100, "qhull internal error (qh_mergevertices): facets did not share a ridge\n");
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  qh_setfree(vertices2);
  *vertices2= mergedvertices;
  qh_settemppop();
} /* mergevertices */


/*---------------------------------

  qh_neighbor_intersections( vertex )
    return intersection of all vertices in vertex->neighbors except for vertex

  returns:
    returns temporary set of vertices
    does not include vertex
    NULL if a neighbor is simplicial
    NULL if empty set

  notes:
    only called by qh_redundant_vertex for qh_reducevertices
      so f.vertices does not contain extraneous vertices that are not in f.ridges
    used for renaming vertices

  design:
    initialize the intersection set with vertices of the first two neighbors
    delete vertex from the intersection
    for each remaining neighbor
      intersect its vertex set with the intersection set
      return NULL if empty
    return the intersection set
*/
setT *qh_neighbor_intersections(vertexT *vertex) {
  facetT *neighbor, **neighborp, *neighborA, *neighborB;
  setT *intersect;
  int neighbor_i, neighbor_n;

  FOREACHneighbor_(vertex) {
    if (neighbor->simplicial)
      return NULL;
  }
  neighborA= SETfirstt_(vertex->neighbors, facetT);
  neighborB= SETsecondt_(vertex->neighbors, facetT);
  zinc_(Zintersectnum);
  if (!neighborA)
    return NULL;
  if (!neighborB)
    intersect= qh_setcopy(neighborA->vertices, 0);
  else
    intersect= qh_vertexintersect_new(neighborA->vertices, neighborB->vertices);
  qh_settemppush(intersect);
  qh_setdelsorted(intersect, vertex);
  FOREACHneighbor_i_(vertex) {
    if (neighbor_i >= 2) {
      zinc_(Zintersectnum);
      qh_vertexintersect(&intersect, neighbor->vertices);
      if (!SETfirst_(intersect)) {
        zinc_(Zintersectfail);
        qh_settempfree(&intersect);
        return NULL;
      }
    }
  }
  trace3((qh ferr, 3007, "qh_neighbor_intersections: %d vertices in neighbor intersection of v%d\n",
          qh_setsize(intersect), vertex->id));
  return intersect;
} /* neighbor_intersections */

/*---------------------------------

  qh_neighbor_vertices( vertex )
    return neighboring vertices for a vertex (not in subridge)
    assumes vertices have full vertex->neighbors

  returns:
    temporary set of vertices

  notes:
    updates qh.visit_id and qh.vertex_visit
    similar to qh_vertexridges

*/
setT *qh_neighbor_vertices(vertexT *vertexA, setT *subridge) {
  facetT *neighbor, **neighborp;
  vertexT *vertex, **vertexp;
  setT *vertices= qh_settemp(qh TEMPsize);

  qh visit_id++;
  FOREACHneighbor_(vertexA)
    neighbor->visitid= qh visit_id;
  qh vertex_visit++;
  vertexA->visitid= qh vertex_visit;
  FOREACHvertex_(subridge) {
    vertex->visitid= qh vertex_visit;
  }
  FOREACHneighbor_(vertexA) {
    if (*neighborp)   /* no new ridges in last neighbor */
      qh_neighbor_vertices_facet(vertexA, neighbor, &vertices);
  }
  trace3((qh ferr, 3035, "qh_neighbor_vertices: %d non-subridge, vertex neighbors for v%d\n",
    qh_setsize(vertices), vertexA->id));
  return vertices;
} /* neighbor_vertices */

/*---------------------------------

  qh_neighbor_vertices_facet( vertex, facet, vertices )
    add neighboring vertices on ridges for vertex in facet
    neighbor->visitid==qh.visit_id if it hasn't been visited
    v.visitid==qh.vertex_visit if it is already in vertices

  returns:
    vertices updated
    sets facet->visitid to qh.visit_id-1

  notes:
    only called by qh_neighbor_vertices
    similar to qh_vertexridges_facet

  design:
    for each ridge of facet
      if ridge of visited neighbor (i.e., unprocessed)
        if vertex in ridge
          append unprocessed vertices of ridge
    mark facet processed
*/
void qh_neighbor_vertices_facet(vertexT *vertexA, facetT *facet, setT **vertices) {
  ridgeT *ridge, **ridgep;
  facetT *neighbor;
  vertexT *second, *last, *vertex, **vertexp;
  int last_i= qh hull_dim-2, count= 0;
  boolT isridge;

  if (facet->simplicial) {
    FOREACHvertex_(facet->vertices) {
      if (vertex->visitid != qh vertex_visit) {
        vertex->visitid= qh vertex_visit;
        qh_setappend(vertices, vertex);
        count++;
      }
    }
  }else {
    FOREACHridge_(facet->ridges) {
      neighbor= otherfacet_(ridge, facet);
      if (neighbor->visitid == qh visit_id) {
        isridge= False;
        if (SETfirst_(ridge->vertices) == vertexA) {
          isridge= True;
        }else if (last_i > 2) {
          second= SETsecondt_(ridge->vertices, vertexT);
          last= SETelemt_(ridge->vertices, last_i, vertexT);
          if (second->id >= vertexA->id && last->id <= vertexA->id) { /* vertices inverse sorted by id */
            if (second == vertexA || last == vertexA)
              isridge= True;
            else if (qh_setin(ridge->vertices, vertexA))
              isridge= True;
          }
        }else if (SETelem_(ridge->vertices, last_i) == vertexA) {
          isridge= True;
        }else if (last_i > 1 && SETsecond_(ridge->vertices) == vertexA) {
          isridge= True;
        }
        if (isridge) {
          FOREACHvertex_(ridge->vertices) {
            if (vertex->visitid != qh vertex_visit) {
              vertex->visitid= qh vertex_visit;
              qh_setappend(vertices, vertex);
              count++;
            }
          }
        }
      }
    }
  }
  facet->visitid= qh visit_id-1;
  if (count) {
    trace4((qh ferr, 4079, "qh_neighbor_vertices_facet: found %d vertex neighbors for v%d in f%d (simplicial? %d)\n",
      count, vertexA->id, facet->id, facet->simplicial));
  }
} /* neighbor_vertices_facet */


/*---------------------------------

  qh_newvertices( vertices )
    add vertices to end of qh.vertex_list (marks as new vertices)

  returns:
    vertices on qh.newvertex_list
    vertex->newfacet set
*/
void qh_newvertices(setT *vertices) {
  vertexT *vertex, **vertexp;

  FOREACHvertex_(vertices) {
    if (!vertex->newfacet) {
      qh_removevertex(vertex);
      qh_appendvertex(vertex);
    }
  }
} /* newvertices */

/*---------------------------------

  qh_next_vertexmerge( )
    return next vertex merge from qh.vertex_mergeset

  returns:
    vertex merge either MRGvertices or MRGsubridge
    drops merges of deleted vertices

  notes:
    called from qh_merge_pinchedvertices
*/
mergeT *qh_next_vertexmerge(void /* qh.vertex_mergeset */) {
  mergeT *merge;
  int merge_i, merge_n, best_i= -1;
  realT bestdist= REALmax;

  FOREACHmerge_i_(qh vertex_mergeset) {
    if (!merge->vertex1 || !merge->vertex2) {
      qh_fprintf(qh ferr, 6299, "qhull internal error (qh_next_vertexmerge): expecting two vertices for vertex merge.  Got v%d v%d and optional f%d\n",
        getid_(merge->vertex1), getid_(merge->vertex2), getid_(merge->facet1));
      qh_errexit(qh_ERRqhull, merge->facet1, NULL);
    }
    if (merge->vertex1->deleted || merge->vertex2->deleted) {
      trace3((qh ferr, 3030, "qh_next_vertexmerge: drop merge of v%d (del? %d) into v%d (del? %d) due to deleted vertex of r%d and r%d\n",
        merge->vertex1->id, merge->vertex1->deleted, merge->vertex2->id, merge->vertex2->deleted, getid_(merge->ridge1), getid_(merge->ridge2)));
      qh_drop_mergevertex(merge);
      qh_setdelnth(qh vertex_mergeset, merge_i);
      merge_i--; merge_n--;
      qh_memfree(merge, (int)sizeof(mergeT));
    }else if (merge->distance < bestdist) {
      bestdist= merge->distance;
      best_i= merge_i;
    }
  }
  merge= NULL;
  if (best_i >= 0) {
    merge= SETelemt_(qh vertex_mergeset, best_i, mergeT);
    if (bestdist/qh ONEmerge > qh_WIDEpinched) {
      if (merge->mergetype==MRGvertices) {
        if (merge->ridge1->top == merge->ridge2->bottom && merge->ridge1->bottom == merge->ridge2->top)
          qh_fprintf(qh ferr, 6391, "qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve opposite oriented ridges r%d and r%d in f%d and f%d.  Nearest v%d and v%d dist %2.2g (%.1fx)\n",
            merge->ridge1->id, merge->ridge2->id, merge->ridge1->top->id, merge->ridge1->bottom->id, merge->vertex1->id, merge->vertex2->id, bestdist, bestdist/qh ONEmerge);
        else
          qh_fprintf(qh ferr, 6381, "qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r%d and r%d.  Nearest v%d and v%d dist %2.2g (%.1fx)\n",
            merge->ridge1->id, merge->ridge2->id, merge->vertex1->id, merge->vertex2->id, bestdist, bestdist/qh ONEmerge);
      }else {
        qh_fprintf(qh ferr, 6208, "qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve dupridge.  Nearest v%d and v%d dist %2.2g (%.1fx)\n",
          merge->vertex1->id, merge->vertex2->id, bestdist, bestdist/qh ONEmerge);
      }
      /* it may be possible to find a different vertex, after other vertex merges have occurred */
      qh_errexit(qh_ERRtopology, NULL, merge->ridge1);
    }
    qh_setdelnth(qh vertex_mergeset, best_i);
  }
  return merge;
} /* next_vertexmerge */

/*---------------------------------

  qh_opposite_horizonfacet( merge, opposite )
    return horizon facet for one of the merge facets, and its opposite vertex across the ridge
    assumes either facet1 or facet2 of merge is 'mergehorizon'
    assumes both facets are simplicial facets on qh.new_facetlist

  returns:
    horizon facet and opposite vertex

  notes:
    called by qh_getpinchedmerges
*/
facetT *qh_opposite_horizonfacet(mergeT *merge, vertexT **opposite) {
  facetT *facet, *horizon, *otherfacet;
  int neighbor_i;

  if (!merge->facet1->simplicial || !merge->facet2->simplicial || (!merge->facet1->mergehorizon && !merge->facet2->mergehorizon)) {
    qh_fprintf(qh ferr, 6273, "qhull internal error (qh_opposite_horizonfacet): expecting merge of simplicial facets, at least one of which is mergehorizon.  Either simplicial or mergehorizon is wrong\n");
    qh_errexit2(qh_ERRqhull, merge->facet1, merge->facet2);
  }
  if (merge->facet1->mergehorizon) {
    facet= merge->facet1;
    otherfacet= merge->facet2;
  }else {
    facet= merge->facet2;
    otherfacet= merge->facet1;
  }
  horizon= SETfirstt_(facet->neighbors, facetT);
  neighbor_i= qh_setindex(otherfacet->neighbors, facet);
  if (neighbor_i==-1)
    neighbor_i= qh_setindex(otherfacet->neighbors, qh_MERGEridge);
  if (neighbor_i==-1) {
    qh_fprintf(qh ferr, 6238, "qhull internal error (qh_opposite_horizonfacet): merge facet f%d not connected to mergehorizon f%d\n",
      otherfacet->id, facet->id);
    qh_errexit2(qh_ERRqhull, otherfacet, facet);
  }
  *opposite= SETelemt_(otherfacet->vertices, neighbor_i, vertexT);
  return horizon;
} /* opposite_horizonfacet */


/*---------------------------------

  qh_reducevertices( )
    reduce extra vertices, shared vertices, and redundant vertices
    facet->newmerge is set if merged since last call
    vertex->delridge is set if vertex was on a deleted ridge
    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:
    called by qh_all_merges and qh_postmerge
    ignored if 2-d

  design:
    merge any degenerate or redundant facets
    repeat until no more 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
        for each new, undeleted vertex
          remove delridge flag
          if vertex is redundant
            merge degenerate or redundant facets
*/
boolT qh_reducevertices(void) {
  int numshare=0, numrename= 0;
  boolT degenredun= False;
  facetT *newfacet;
  vertexT *vertex, **vertexp;

  if (qh hull_dim == 2)
    return False;
  trace2((qh ferr, 2101, "qh_reducevertices: reduce extra vertices, shared vertices, and redundant vertices\n"));
  if (qh_merge_degenredundant())
    degenredun= True;
LABELrestart:
  FORALLnew_facets {
    if (newfacet->newmerge) {
      if (!qh MERGEvertices)
        newfacet->newmerge= False;
      if (qh_remove_extravertices(newfacet)) {
        qh_degen_redundant_facet(newfacet);
        if (qh_merge_degenredundant()) {
          degenredun= True;
          goto LABELrestart;
        }
      }
    }
  }
  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++;
            if (qh_merge_degenredundant()) {
              degenredun= True;
              goto LABELrestart;
            }
            vertexp--; /* repeat since deleted vertex */
          }
        }
      }
    }
  }
  FORALLvertex_(qh newvertex_list) {
    if (vertex->delridge && !vertex->deleted) {
      vertex->delridge= False;
      if (qh hull_dim >= 4 && qh_redundant_vertex(vertex)) {
        numrename++;
        if (qh_merge_degenredundant()) {
          degenredun= True;
          goto LABELrestart;
        }
      }
    }
  }
  trace1((qh ferr, 1014, "qh_reducevertices: renamed %d shared vertices and %d redundant vertices. Degen? %d\n",
          numshare, numrename, degenredun));
  return degenredun;
} /* reducevertices */

/*---------------------------------

  qh_redundant_vertex( vertex )
    rename a redundant vertex if qh_find_newvertex succeeds
    assumes vertices have full vertex->neighbors

  returns:
    if find a replacement vertex
      returns new vertex
      qh_renamevertex sets vertex->deleted for redundant vertex

  notes:
    only called by qh_reducevertices for 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 among these ridges and vertices
      rename vertex to the new vertex
*/
vertexT *qh_redundant_vertex(vertexT *vertex) {
  vertexT *newvertex= NULL;
  setT *vertices, *ridges;

  trace3((qh ferr, 3008, "qh_redundant_vertex: check if v%d from a deleted ridge can be renamed\n", vertex->id));
  if ((vertices= qh_neighbor_intersections(vertex))) {
    ridges= qh_vertexridges(vertex, !qh_ALL);
    if ((newvertex= qh_find_newvertex(vertex, vertices, ridges))) {
      zinc_(Zrenameall);
      qh_renamevertex(vertex, newvertex, ridges, NULL, NULL); /* ridges invalidated */
    }
    qh_settempfree(&ridges);
    qh_settempfree(&vertices);
  }
  return newvertex;
} /* redundant_vertex */

/*---------------------------------

  qh_remove_extravertices( facet )
    remove extra vertices from non-simplicial facets

  returns:
    returns True if it finds them
      deletes facet from vertex neighbors
      facet may be redundant (test with qh_degen_redundant)

  notes:
    called by qh_renamevertex and qh_reducevertices
    a merge (qh_reducevertices) or qh_renamevertex may drop all ridges for a vertex in a facet

  design:
    for each vertex in facet
      if vertex not in a ridge (i.e., no longer used)
        delete vertex from facet
        delete facet from vertex'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;

  if (facet->simplicial) {
    return False;
  }
  trace4((qh ferr, 4043, "qh_remove_extravertices: test non-simplicial f%d for extra vertices\n",
          facet->id));
  FOREACHvertex_(facet->vertices)
    vertex->seen= False;
  FOREACHridge_(facet->ridges) {
    FOREACHvertex_(ridge->vertices)
      vertex->seen= True;
  }
  FOREACHvertex_(facet->vertices) {
    if (!vertex->seen) {
      foundrem= True;
      zinc_(Zremvertex);
      qh_setdelsorted(facet->vertices, vertex);
      qh_setdel(vertex->neighbors, facet);
      if (!qh_setsize(vertex->neighbors)) {
        vertex->deleted= True;
        qh_setappend(&qh del_vertices, vertex);
        zinc_(Zremvertexdel);
        trace2((qh ferr, 2036, "qh_remove_extravertices: v%d deleted because it's lost all ridges\n", vertex->id));
      }else
        trace3((qh ferr, 3009, "qh_remove_extravertices: v%d removed from f%d because it's lost all ridges\n", vertex->id, facet->id));
      vertexp--; /*repeat*/
    }
  }
  return foundrem;
} /* remove_extravertices */

/*---------------------------------

  qh_remove_mergetype( mergeset, mergetype )
    Remove mergetype merges from mergeset

  notes:
    Does not preserve order
*/
void qh_remove_mergetype(setT *mergeset, mergeType type) {
  mergeT *merge;
  int merge_i, merge_n;

  FOREACHmerge_i_(mergeset) {
    if (merge->mergetype == type) {
        trace3((qh ferr, 3037, "qh_remove_mergetype: remove merge f%d f%d v%d v%d r%d r%d dist %2.2g type %d",
            getid_(merge->facet1), getid_(merge->facet2), getid_(merge->vertex1), getid_(merge->vertex2), getid_(merge->ridge1), getid_(merge->ridge2), merge->distance, type));
        qh_setdelnth(mergeset, merge_i);
        merge_i--; merge_n--;  /* repeat with next merge */
    }
  }
} /* remove_mergetype */

/*---------------------------------

  qh_rename_adjacentvertex( oldvertex, newvertex )
    renames oldvertex as newvertex.  Must be adjacent (i.e., in the same subridge)
    no-op if either vertex is deleted

  notes:
    called from qh_merge_pinchedvertices

  design:
    for all neighbors of oldvertex
      if simplicial, rename oldvertex to newvertex and drop if degenerate
      if needed, add oldvertex neighbor to newvertex
    determine ridges for oldvertex
    rename oldvertex as newvertex in ridges (qh_renamevertex)
*/
void qh_rename_adjacentvertex(vertexT *oldvertex, vertexT *newvertex, realT dist) {
  setT *ridges;
  facetT *neighbor, **neighborp, *maxfacet= NULL;
  ridgeT *ridge, **ridgep;
  boolT istrace= False;
  int oldsize= qh_setsize(oldvertex->neighbors);
  int newsize= qh_setsize(newvertex->neighbors);
  coordT maxdist2= -REALmax, dist2;

  if (qh IStracing >= 4 || oldvertex->id == qh tracevertex_id || newvertex->id == qh tracevertex_id) {
    istrace= True;
  }
  zzinc_(Ztotmerge);
  if (istrace) {
    qh_fprintf(qh ferr, 2071, "qh_rename_adjacentvertex: merge #%d rename v%d (%d neighbors) to v%d (%d neighbors) dist %2.2g\n",
      zzval_(Ztotmerge), oldvertex->id, oldsize, newvertex->id, newsize, dist);
  }
  if (oldvertex->deleted || newvertex->deleted) {
    if (istrace || qh IStracing >= 2) {
      qh_fprintf(qh ferr, 2072, "qh_rename_adjacentvertex: ignore rename.  Either v%d (%d) or v%d (%d) is deleted\n",
        oldvertex->id, oldvertex->deleted, newvertex->id, newvertex->deleted);
    }
    return;
  }
  if (oldsize == 0 || newsize == 0) {
    qh_fprintf(qh ferr, 2072, "qhull internal error (qh_rename_adjacentvertex): expecting neighbor facets for v%d and v%d.  Got %d and %d neighbors resp.\n",
      oldvertex->id, newvertex->id, oldsize, newsize);
      qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  FOREACHneighbor_(oldvertex) {
    if (neighbor->simplicial) {
      if (qh_setin(neighbor->vertices, newvertex)) {
        if (istrace || qh IStracing >= 2) {
          qh_fprintf(qh ferr, 2070, "qh_rename_adjacentvertex: simplicial f%d contains old v%d and new v%d.  Will be marked degenerate by qh_renamevertex\n",
            neighbor->id, oldvertex->id, newvertex->id);
        }
        qh_makeridges(neighbor); /* no longer simplicial, nummerge==0, skipped by qh_maybe_duplicateridge */
      }else {
        qh_replacefacetvertex(neighbor, oldvertex, newvertex);
        qh_setunique(&newvertex->neighbors, neighbor);
        qh_newvertices(neighbor->vertices);  /* for qh_update_vertexneighbors of vertex neighbors */
      }
    }
  }
  ridges= qh_vertexridges(oldvertex, qh_ALL);
  if (istrace) {
    FOREACHridge_(ridges) {
      qh_printridge(qh ferr, ridge);
    }
  }
  FOREACHneighbor_(oldvertex) {
    if (!neighbor->simplicial){
      qh_addfacetvertex(neighbor, newvertex);
      qh_setunique(&newvertex->neighbors, neighbor);
      qh_newvertices(neighbor->vertices);  /* for qh_update_vertexneighbors of vertex neighbors */
      if (qh newfacet_list == qh facet_tail) {
        qh_removefacet(neighbor);  /* add a neighbor to newfacet_list so that qh_partitionvisible has a newfacet */
        qh_appendfacet(neighbor);
        neighbor->newfacet= True;
      }
    }
  }
  qh_renamevertex(oldvertex, newvertex, ridges, NULL, NULL);  /* ridges invalidated */
  if (oldvertex->deleted && !oldvertex->partitioned) {
    FOREACHneighbor_(newvertex) {
      if (!neighbor->visible) {
        qh_distplane(oldvertex->point, neighbor, &dist2);
        if (dist2>maxdist2) {
          maxdist2= dist2;
          maxfacet= neighbor;
        }
      }
    }
    trace2((qh ferr, 2096, "qh_rename_adjacentvertex: partition old p%d(v%d) as a coplanar point for furthest f%d dist %2.2g.  Maybe repartition later (QH0031)\n",
      qh_pointid(oldvertex->point), oldvertex->id, maxfacet->id, maxdist2))
    qh_partitioncoplanar(oldvertex->point, maxfacet, NULL, !qh_ALL);  /* faster with maxdist2, otherwise duplicates distance tests from maxdist2/dist2 */
    oldvertex->partitioned= True;
  }
  qh_settempfree(&ridges);
} /* rename_adjacentvertex */

/*---------------------------------

  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:
    only called by qh_reducevertices after qh_remove_extravertices
       so f.vertices does not contain extraneous vertices
    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= NULL;

  if (qh_setsize(vertex->neighbors) == 2) {
    neighborA= SETfirstt_(vertex->neighbors, facetT);
    if (neighborA == facet)
      neighborA= SETsecondt_(vertex->neighbors, facetT);
  }else if (qh hull_dim == 3)
    return NULL;
  else {
    qh visit_id++;
    FOREACHneighbor_(facet)
      neighbor->visitid= qh visit_id;
    FOREACHneighbor_(vertex) {
      if (neighbor->visitid == qh visit_id) {
        if (neighborA)
          return NULL;
        neighborA= neighbor;
      }
    }
  }
  if (!neighborA) {
    qh_fprintf(qh ferr, 6101, "qhull internal error (qh_rename_sharedvertex): v%d's neighbors not in f%d\n",
        vertex->id, facet->id);
    qh_errprint("ERRONEOUS", facet, NULL, NULL, vertex);
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  if (neighborA) { /* avoid warning */
    /* the vertex is shared by facet and neighborA */
    ridges= qh_settemp(qh TEMPsize);
    neighborA->visitid= ++qh visit_id;
    qh_vertexridges_facet(vertex, facet, &ridges);
    trace2((qh ferr, 2037, "qh_rename_sharedvertex: p%d(v%d) is shared by f%d(%d ridges) and f%d\n",
      qh_pointid(vertex->point), vertex->id, facet->id, qh_setsize(ridges), neighborA->id));
    zinc_(Zintersectnum);
    vertices= qh_vertexintersect_new(facet->vertices, neighborA->vertices);
    qh_setdel(vertices, vertex);
    qh_settemppush(vertices);
    if ((newvertex= qh_find_newvertex(vertex, vertices, ridges)))
      qh_renamevertex(vertex, newvertex, ridges, facet, neighborA);  /* ridges invalidated */
    qh_settempfree(&vertices);
    qh_settempfree(&ridges);
  }
  return newvertex;
} /* rename_sharedvertex */

/*---------------------------------

  qh_renameridgevertex( ridge, oldvertex, newvertex )
    renames oldvertex as newvertex in ridge

  returns:
    True if renames oldvertex
    False if deleted the ridge

  notes:
    called by qh_renamevertex
    caller sets newvertex->delridge for deleted ridges (qh_reducevertices)

  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
*/
boolT qh_renameridgevertex(ridgeT *ridge, vertexT *oldvertex, vertexT *newvertex) {
  int nth= 0, oldnth;
  facetT *temp;
  vertexT *vertex, **vertexp;

  oldnth= qh_setindex(ridge->vertices, oldvertex);
  if (oldnth < 0) {
    qh_fprintf(qh ferr, 6424, "qhull internal error (qh_renameridgevertex): oldvertex v%d not found in r%d.  Cannot rename to v%d\n",
        oldvertex->id, ridge->id, newvertex->id);
    qh_errexit(qh_ERRqhull, NULL, ridge);
  }
  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);
      trace2((qh ferr, 2038, "qh_renameridgevertex: ridge r%d deleted.  It contained both v%d and v%d\n",
        ridge->id, oldvertex->id, newvertex->id));
      qh_delridge_merge(ridge); /* ridge.vertices deleted */
      return False;
    }
    if (vertex->id < newvertex->id)
      break;
    nth++;
  }
  qh_setaddnth(&ridge->vertices, nth, newvertex);
  ridge->simplicialtop= False;
  ridge->simplicialbot= False;
  if (abs(oldnth - nth)%2) {
    trace3((qh ferr, 3010, "qh_renameridgevertex: swapped the top and bottom of ridge r%d\n",
            ridge->id));
    temp= ridge->top;
    ridge->top= ridge->bottom;
    ridge->bottom= temp;
  }
  return True;
} /* renameridgevertex */


/*---------------------------------

  qh_renamevertex( oldvertex, newvertex, ridges, oldfacet, neighborA )
    renames oldvertex as newvertex in ridges of non-simplicial neighbors
    set oldfacet/neighborA if oldvertex is shared between two facets (qh_rename_sharedvertex)
    otherwise qh_redundant_vertex or qh_rename_adjacentvertex

  returns:
    if oldfacet and multiple neighbors, oldvertex may still exist afterwards
    otherwise sets oldvertex->deleted for later deletion
    one or more ridges maybe deleted
    ridges is invalidated
    merges may be added to degen_mergeset via qh_maydropneighbor or qh_degen_redundant_facet

  notes:
    qh_rename_sharedvertex can not change neighbors of newvertex (since it's a subset)
    qh_redundant_vertex due to vertex->delridge for qh_reducevertices
    qh_rename_adjacentvertex for complete renames

  design:
    for each ridge in ridges
      rename oldvertex to newvertex and delete degenerate ridges
    if oldfacet not defined
      for each non-simplicial 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 old vertex'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;
  int topsize, bottomsize;
  boolT istrace= False;

#ifndef qh_NOtrace
  if (qh IStracing >= 2 || oldvertex->id == qh tracevertex_id ||
        newvertex->id == qh tracevertex_id) {
    istrace= True;
    qh_fprintf(qh ferr, 2086, "qh_renamevertex: rename v%d to v%d in %d ridges with old f%d and neighbor f%d\n",
      oldvertex->id, newvertex->id, qh_setsize(ridges), getid_(oldfacet), getid_(neighborA));
  }
#endif
  FOREACHridge_(ridges) {
    if (qh_renameridgevertex(ridge, oldvertex, newvertex)) { /* ridge is deleted if False, invalidating ridges */
      topsize= qh_setsize(ridge->top->vertices);
      bottomsize= qh_setsize(ridge->bottom->vertices);
      if (topsize < qh hull_dim || (topsize == qh hull_dim && !ridge->top->simplicial && qh_setin(ridge->top->vertices, newvertex))) {
        trace4((qh ferr, 4070, "qh_renamevertex: ignore duplicate check for r%d.  top f%d (size %d) will be degenerate after rename v%d to v%d\n",
          ridge->id, ridge->top->id, topsize, oldvertex->id, newvertex->id));
      }else if (bottomsize < qh hull_dim || (bottomsize == qh hull_dim && !ridge->bottom->simplicial && qh_setin(ridge->bottom->vertices, newvertex))) {
        trace4((qh ferr, 4071, "qh_renamevertex: ignore duplicate check for r%d.  bottom f%d (size %d) will be degenerate after rename v%d to v%d\n",
          ridge->id, ridge->bottom->id, bottomsize, oldvertex->id, newvertex->id));
      }else
        qh_maybe_duplicateridge(ridge);
    }
  }
  if (!oldfacet) {
    /* stat Zrenameall or Zpinchduplicate */
    if (istrace)
      qh_fprintf(qh ferr, 2087, "qh_renamevertex: renaming v%d to v%d in several facets for qh_redundant_vertex or MRGsubridge\n",
               oldvertex->id, newvertex->id);
    FOREACHneighbor_(oldvertex) {
      if (neighbor->simplicial) {
        qh_degen_redundant_facet(neighbor); /* e.g., rbox 175 C3,2e-13 D4 t1545235541 | qhull d */
      }else {
        if (istrace)
          qh_fprintf(qh ferr, 4080, "qh_renamevertex: rename vertices in non-simplicial neighbor f%d of v%d\n", neighbor->id, oldvertex->id);
        qh_maydropneighbor(neighbor);
        qh_setdelsorted(neighbor->vertices, oldvertex); /* if degenerate, qh_degen_redundant_facet will add to mergeset */
        if (qh_remove_extravertices(neighbor))
          neighborp--; /* neighbor deleted from oldvertex neighborset */
        qh_degen_redundant_facet(neighbor); /* either direction may be redundant, faster if combine? */
        qh_test_redundant_neighbors(neighbor);
        qh_test_degen_neighbors(neighbor);
      }
    }
    if (!oldvertex->deleted) {
      oldvertex->deleted= True;
      qh_setappend(&qh del_vertices, oldvertex);
    }
  }else if (qh_setsize(oldvertex->neighbors) == 2) {
    zinc_(Zrenameshare);
    if (istrace)
      qh_fprintf(qh ferr, 3039, "qh_renamevertex: renaming v%d to v%d in oldfacet f%d for qh_rename_sharedvertex\n",
               oldvertex->id, newvertex->id, oldfacet->id);
    FOREACHneighbor_(oldvertex) {
      qh_setdelsorted(neighbor->vertices, oldvertex);
      qh_degen_redundant_facet(neighbor);
    }
    oldvertex->deleted= True;
    qh_setappend(&qh del_vertices, oldvertex);
  }else {
    zinc_(Zrenamepinch);
    if (istrace || qh IStracing >= 1)
      qh_fprintf(qh ferr, 3040, "qh_renamevertex: renaming 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);
    if (qh_remove_extravertices(neighborA))
      qh_degen_redundant_facet(neighborA);
  }
  if (oldfacet)
    qh_degen_redundant_facet(oldfacet);
} /* renamevertex */

/*---------------------------------

  qh_test_appendmerge( facet, neighbor, simplicial )
    test convexity and append to qh.facet_mergeset if non-convex
    if pre-merging,
      no-op if qh.SKIPconvex, or qh.MERGEexact and coplanar
    if simplicial, assumes centrum test is valid (e.g., adjacent, simplicial new facets)

  returns:
    true if appends facet/neighbor to qh.facet_mergeset
    sets facet->center as needed
    does not change facet->seen

  notes:
    called from qh_getmergeset_initial, qh_getmergeset, and qh_test_vneighbors
    must be at least as strong as qh_checkconvex (poly2.c)
    assumes !f.flipped

  design:
    exit if qh.SKIPconvex ('Q0') and !qh.POSTmerging
    if qh.cos_max ('An') is defined and merging coplanars
      if the angle between facet normals is too shallow
        append an angle-coplanar merge to qh.mergeset
        return True
    test convexity of facet and neighbor
*/
boolT qh_test_appendmerge(facetT *facet, facetT *neighbor, boolT simplicial) {
  realT angle= -REALmax;
  boolT okangle= False;

  if (qh SKIPconvex && !qh POSTmerging)
    return False;
  if (qh cos_max < REALmax/2 && (!qh MERGEexact || qh POSTmerging)) {
    angle= qh_getangle(facet->normal, neighbor->normal);
    okangle= True;
    zinc_(Zangletests);
    if (angle > qh cos_max) {
      zinc_(Zcoplanarangle);
      qh_appendmergeset(facet, neighbor, MRGanglecoplanar, 0.0, angle);
      trace2((qh ferr, 2039, "qh_test_appendmerge: coplanar angle %4.4g between f%d and f%d\n",
         angle, facet->id, neighbor->id));
      return True;
    }
  }
  if (simplicial || qh hull_dim <= 3)
    return qh_test_centrum_merge(facet, neighbor, angle, okangle);
  else
    return qh_test_nonsimplicial_merge(facet, neighbor, angle, okangle);
} /* test_appendmerge */

/*---------------------------------

  qh_test_centrum_merge( facet, neighbor, angle, okangle )
    test centrum convexity and append non-convex facets to qh.facet_mergeset
    'angle' is angle between facets if okangle is true, otherwise use 0.0

  returns:
    true if append facet/neighbor to qh.facet_mergeset
    sets facet->center as needed
    does not change facet->seen

  notes:
    called from test_appendmerge if adjacent simplicial facets or 2-d/3-d
    at least as strict as qh_checkconvex, including qh.DISTround ('En' and 'Rn')

  design:
    make facet's centrum if needed
    if facet's centrum is above the neighbor (qh.centrum_radius)
      set isconcave

    if facet's centrum is not below the neighbor (-qh.centrum_radius)
      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 and merging coplanars
      get angle if needed (qh.ANGLEmerge 'An')
      append concave-coplanar, concave ,or coplanar merge to qh.mergeset
*/
boolT qh_test_centrum_merge(facetT *facet, facetT *neighbor, realT angle, boolT okangle) {
  coordT dist, dist2, mergedist;
  boolT isconcave= False, iscoplanar= False;

  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 && iscoplanar) {
    zinc_(Zconcavecoplanarridge);
    if (dist > dist2)
      qh_appendmergeset(facet, neighbor, MRGconcavecoplanar, dist, angle);
    else
      qh_appendmergeset(neighbor, facet, MRGconcavecoplanar, dist2, angle);
    trace0((qh ferr, 36, "qh_test_centrum_merge: concave f%d to coplanar 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 if (isconcave) {
    mergedist= fmax_(dist, dist2);
    zinc_(Zconcaveridge);
    qh_appendmergeset(facet, neighbor, MRGconcave, mergedist, angle);
    trace0((qh ferr, 37, "qh_test_centrum_merge: 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 */ {
    mergedist= fmin_(fabs_(dist), fabs_(dist2));
    zinc_(Zcoplanarcentrum);
    qh_appendmergeset(facet, neighbor, MRGcoplanar, mergedist, angle);
    trace2((qh ferr, 2097, "qh_test_centrum_merge: 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_centrum_merge */

/*---------------------------------

  qh_test_degen_neighbors( facet )
    append degenerate neighbors to qh.degen_mergeset

  notes:
  called at end of qh_mergefacet() and qh_renamevertex()
  call after test_redundant_facet() since MRGredundant is less expensive then MRGdegen
    a degenerate facet has fewer than hull_dim neighbors
    see: qh_merge_degenredundant()

*/
void qh_test_degen_neighbors(facetT *facet) {
  facetT *neighbor, **neighborp;
  int size;

  trace4((qh ferr, 4073, "qh_test_degen_neighbors: test for degenerate neighbors of f%d\n", facet->id));
  FOREACHneighbor_(facet) {
    if (neighbor->visible) {
      qh_fprintf(qh ferr, 6359, "qhull internal error (qh_test_degen_neighbors): facet f%d has deleted neighbor f%d (qh.visible_list)\n",
        facet->id, neighbor->id);
      qh_errexit2(qh_ERRqhull, facet, neighbor);
    }
    if (neighbor->degenerate || neighbor->redundant || neighbor->dupridge) /* will merge or delete */
      continue;
    /* merge flipped-degenerate facet before flipped facets */
    if ((size= qh_setsize(neighbor->neighbors)) < qh hull_dim) {
      qh_appendmergeset(neighbor, neighbor, MRGdegen, 0.0, 1.0);
      trace2((qh ferr, 2019, "qh_test_degen_neighbors: f%d is degenerate with %d neighbors.  Neighbor of f%d.\n", neighbor->id, size, facet->id));
    }
  }
} /* test_degen_neighbors */


/*---------------------------------

  qh_test_nonsimplicial_merge( facet, neighbor, angle, okangle )
    test centrum and vertex convexity and append non-convex or redundant facets to qh.facet_mergeset
    'angle' is angle between facets if okangle is true, otherwise use 0.0
    skips coplanar merges if pre-merging with qh.MERGEexact ('Qx')

  returns:
    true if appends facet/neighbor to qh.facet_mergeset
    sets facet->center as needed
    does not change facet->seen

  notes:
    only called from test_appendmerge if a non-simplicial facet and at least 4-d
    at least as strict as qh_checkconvex, including qh.DISTround ('En' and 'Rn')
      centrums must be < -qh.centrum_radius
    tests vertices as well as centrums since a facet may be twisted relative to its neighbor

  design:
    set precision constants for maxoutside, clearlyconcave, minvertex, and coplanarcentrum
      use maxoutside for coplanarcentrum if premerging with 'Qx' and qh_MAXcoplanarcentrum merges
      otherwise use qh.centrum_radious for coplanarcentrum
    make facet and neighbor centrums if needed
    isconcave if a centrum is above neighbor (coplanarcentrum)
    iscoplanar if a centrum is not below neighbor (-qh.centrum_radius)
    maybeconvex if a centrum is clearly below neighbor (-clearyconvex)
    return False if both centrums clearly below neighbor (-clearyconvex)
    return MRGconcave if isconcave

    facets are neither clearly convex nor clearly concave
    test vertices as well as centrums
    if maybeconvex
      determine mindist and maxdist for vertices of the other facet
      maybe MRGredundant
    otherwise
      determine mindist and maxdist for vertices of either facet
      maybe MRGredundant
      maybeconvex if a vertex is clearly below neighbor (-clearconvex)

    vertices are concave if dist > clearlyconcave
    vertices are twisted if dist > maxoutside (isconcave and maybeconvex)
    return False if not concave and pre-merge of 'Qx' (qh.MERGEexact)
    vertices are coplanar if dist in -minvertex..maxoutside
    if !isconcave, vertices are coplanar if dist >= -qh.MAXcoplanar (n*qh.premerge_centrum)

    return False if neither concave nor coplanar
    return MRGtwisted if isconcave and maybeconvex
    return MRGconcavecoplanar if isconcave and isconvex
    return MRGconcave if isconcave
    return MRGcoplanar if iscoplanar
*/
boolT qh_test_nonsimplicial_merge(facetT *facet, facetT *neighbor, realT angle, boolT okangle) {
  coordT dist, mindist, maxdist, mindist2, maxdist2, dist2, maxoutside, clearlyconcave, minvertex, clearlyconvex, mergedist, coplanarcentrum;
  boolT isconcave= False, iscoplanar= False, maybeconvex= False, isredundant= False;
  vertexT *maxvertex= NULL, *maxvertex2= NULL;

  maxoutside= fmax_(neighbor->maxoutside, qh ONEmerge + qh DISTround);
  maxoutside= fmax_(maxoutside, facet->maxoutside);
  clearlyconcave= qh_RATIOconcavehorizon * maxoutside;
  minvertex= fmax_(-qh min_vertex, qh MAXcoplanar); /* non-negative, not available per facet, not used for iscoplanar */
  clearlyconvex= qh_RATIOconvexmerge * minvertex; /* must be convex for MRGtwisted */
  if (qh MERGEexact && !qh POSTmerging && (facet->nummerge > qh_MAXcoplanarcentrum || neighbor->nummerge > qh_MAXcoplanarcentrum))
    coplanarcentrum= maxoutside;
  else
    coplanarcentrum= qh centrum_radius;

  if (!facet->center)
    facet->center= qh_getcentrum(facet);
  zzinc_(Zcentrumtests);
  qh_distplane(facet->center, neighbor, &dist);
  if (dist > coplanarcentrum)
    isconcave= True;
  else if (dist >= -qh centrum_radius)
    iscoplanar= True;
  else if (dist < -clearlyconvex)
    maybeconvex= True;
  if (!neighbor->center)
    neighbor->center= qh_getcentrum(neighbor);
  zzinc_(Zcentrumtests);
  qh_distplane(neighbor->center, facet, &dist2);
  if (dist2 > coplanarcentrum)
    isconcave= True;
  else if (dist2 >= -qh centrum_radius)
    iscoplanar= True;
  else if (dist2 < -clearlyconvex) {
    if (maybeconvex)
      return False; /* both centrums clearly convex */
    maybeconvex= True;
  }
  if (isconcave) {
    if (!okangle && qh ANGLEmerge) {
      angle= qh_getangle(facet->normal, neighbor->normal);
      zinc_(Zangletests);
    }
    mergedist= fmax_(dist, dist2);
    zinc_(Zconcaveridge);
    qh_appendmergeset(facet, neighbor, MRGconcave, mergedist, angle);
    trace0((qh ferr, 18, "qh_test_nonsimplicial_merge: concave centrum for f%d or 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));
    return True;
  }
  /* neither clearly convex nor clearly concave, test vertices as well as centrums */
  if (maybeconvex) {
    if (dist < -clearlyconvex) {
      maxdist= dist;  /* facet centrum clearly convex, no need to test its vertex distance */
      mindist= dist;
      maxvertex2= qh_furthestvertex(neighbor, facet, &maxdist2, &mindist2);
      if (!maxvertex2) {
        qh_appendmergeset(neighbor, facet, MRGredundant, maxdist2, qh_ANGLEnone);
        isredundant= True;
      }
    }else { /* dist2 < -clearlyconvex */
      maxdist2= dist2;   /* neighbor centrum clearly convex, no need to test its vertex distance */
      mindist2= dist2;
      maxvertex= qh_furthestvertex(facet, neighbor, &maxdist, &mindist);
      if (!maxvertex) {
        qh_appendmergeset(facet, neighbor, MRGredundant, maxdist, qh_ANGLEnone);
        isredundant= True;
      }
    }
  }else {
    maxvertex= qh_furthestvertex(facet, neighbor, &maxdist, &mindist);
    if (maxvertex) {
      maxvertex2= qh_furthestvertex(neighbor, facet, &maxdist2, &mindist2);
      if (!maxvertex2) {
        qh_appendmergeset(neighbor, facet, MRGredundant, maxdist2, qh_ANGLEnone);
        isredundant= True;
      }else if (mindist < -clearlyconvex || mindist2 < -clearlyconvex)
        maybeconvex= True;
    }else { /* !maxvertex */
      qh_appendmergeset(facet, neighbor, MRGredundant, maxdist, qh_ANGLEnone);
      isredundant= True;
    }
  }
  if (isredundant) {
    zinc_(Zredundantmerge);
    return True;
  }

  if (maxdist > clearlyconcave || maxdist2 > clearlyconcave)
    isconcave= True;
  else if (maybeconvex) {
    if (maxdist > maxoutside || maxdist2 > maxoutside)
      isconcave= True;  /* MRGtwisted */
  }
  if (!isconcave && qh MERGEexact && !qh POSTmerging)
    return False;
  if (isconcave && !iscoplanar) {
    if (maxdist < maxoutside && (-qh MAXcoplanar || (maxdist2 < maxoutside && mindist2 >= -qh MAXcoplanar)))
      iscoplanar= True; /* MRGconcavecoplanar */
  }else if (!iscoplanar) {
    if (mindist >= -qh MAXcoplanar || mindist2 >= -qh MAXcoplanar)
      iscoplanar= True;  /* MRGcoplanar */
  }
  if (!isconcave && !iscoplanar)
    return False;
  if (!okangle && qh ANGLEmerge) {
    angle= qh_getangle(facet->normal, neighbor->normal);
    zinc_(Zangletests);
  }
  if (isconcave && maybeconvex) {
    zinc_(Ztwistedridge);
    if (maxdist > maxdist2)
      qh_appendmergeset(facet, neighbor, MRGtwisted, maxdist, angle);
    else
      qh_appendmergeset(neighbor, facet, MRGtwisted, maxdist2, angle);
    trace0((qh ferr, 27, "qh_test_nonsimplicial_merge: twisted concave f%d v%d to f%d v%d, dist %4.4g and reverse dist %4.4g, angle %4.4g during p%d\n",
           facet->id, getid_(maxvertex), neighbor->id, getid_(maxvertex2), maxdist, maxdist2, angle, qh furthest_id));
  }else if (isconcave && iscoplanar) {
    zinc_(Zconcavecoplanarridge);
    if (maxdist > maxdist2)
      qh_appendmergeset(facet, neighbor, MRGconcavecoplanar, maxdist, angle);
    else
      qh_appendmergeset(neighbor, facet, MRGconcavecoplanar, maxdist2, angle);
    trace0((qh ferr, 28, "qh_test_nonsimplicial_merge: concave coplanar f%d v%d to f%d v%d, dist %4.4g and reverse dist %4.4g, angle %4.4g during p%d\n",
      facet->id, getid_(maxvertex), neighbor->id, getid_(maxvertex2), maxdist, maxdist2, angle, qh furthest_id));
  }else if (isconcave) {
    mergedist= fmax_(maxdist, maxdist2);
    zinc_(Zconcaveridge);
    qh_appendmergeset(facet, neighbor, MRGconcave, mergedist, angle);
    trace0((qh ferr, 29, "qh_test_nonsimplicial_merge: concave f%d v%d to f%d v%d, dist %4.4g and reverse dist %4.4g, angle %4.4g during p%d\n",
      facet->id, getid_(maxvertex), neighbor->id, getid_(maxvertex2), maxdist, maxdist2, angle, qh furthest_id));
  }else /* iscoplanar */ {
    mergedist= fmax_(fmax_(maxdist, maxdist2), fmax_(-mindist, -mindist2));
    zinc_(Zcoplanarcentrum);
    qh_appendmergeset(facet, neighbor, MRGcoplanar, mergedist, angle);
    trace2((qh ferr, 2099, "qh_test_nonsimplicial_merge: coplanar f%d v%d to f%d v%d, dist %4.4g and reverse dist %4.4g, angle %4.4g during p%d\n",
      facet->id, getid_(maxvertex), neighbor->id, getid_(maxvertex2), maxdist, maxdist2, angle, qh furthest_id));
  }
  return True;
} /* test_nonsimplicial_merge */

/*---------------------------------

  qh_test_redundant_neighbors( facet )
    append degenerate facet or its redundant neighbors to qh.degen_mergeset

  returns:
    bumps vertex_visit

  notes:
    called at end of qh_mergefacet(), qh_mergecycle_all(), and qh_renamevertex
    call before qh_test_degen_neighbors (MRGdegen are more likely to cause problems)
    a redundant neighbor's vertices is a subset of the facet's vertices
    with pinched and flipped facets, a redundant neighbor may have a wildly different normal

    see qh_merge_degenredundant() and qh_-_facet()

  design:
    if facet is degenerate
       appends facet to degen_mergeset
    else
       appends redundant neighbors of facet to degen_mergeset
*/
void qh_test_redundant_neighbors(facetT *facet) {
  vertexT *vertex, **vertexp;
  facetT *neighbor, **neighborp;
  int size;

  trace4((qh ferr, 4022, "qh_test_redundant_neighbors: test neighbors of f%d vertex_visit %d\n",
          facet->id, qh vertex_visit+1));
  if ((size= qh_setsize(facet->neighbors)) < qh hull_dim) {
    qh_appendmergeset(facet, facet, MRGdegen, 0.0, 1.0);
    trace2((qh ferr, 2017, "qh_test_redundant_neighbors: f%d is degenerate with %d neighbors.\n", facet->id, size));
  }else {
    qh vertex_visit++;
    FOREACHvertex_(facet->vertices)
      vertex->visitid= qh vertex_visit;
    FOREACHneighbor_(facet) {
      if (neighbor->visible) {
        qh_fprintf(qh ferr, 6360, "qhull internal error (qh_test_redundant_neighbors): facet f%d has deleted neighbor f%d (qh.visible_list)\n",
          facet->id, neighbor->id);
        qh_errexit2(qh_ERRqhull, facet, neighbor);
      }
      if (neighbor->degenerate || neighbor->redundant || neighbor->dupridge) /* will merge or delete */
        continue;
      if (facet->flipped && !neighbor->flipped) /* do not merge non-flipped into flipped */
        continue;
      /* merge redundant-flipped facet first */
      /* uses early out instead of checking vertex count */
      FOREACHvertex_(neighbor->vertices) {
        if (vertex->visitid != qh vertex_visit)
          break;
      }
      if (!vertex) {
        qh_appendmergeset(neighbor, facet, MRGredundant, 0.0, 1.0);
        trace2((qh ferr, 2018, "qh_test_redundant_neighbors: f%d is contained in f%d.  merge\n", neighbor->id, facet->id));
      }
    }
  }
} /* test_redundant_neighbors */

/*---------------------------------

  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:
    called by qh_all_merges from qh_postmerge if qh.TESTvneighbors ('Qv')
    assumes all facet neighbors have been tested
    this can be expensive
    this does not guarantee that a centrum is below all facets
      but it is unlikely
    uses qh.visit_id

  design:
    build vertex neighbors if necessary
    for all new facets
      for all vertices
        for each unvisited facet neighbor of the vertex
          test new facet and neighbor for convexity
*/
boolT qh_test_vneighbors(void /* qh.newfacet_list */) {
  facetT *newfacet, *neighbor, **neighborp;
  vertexT *vertex, **vertexp;
  int nummerges= 0;

  trace1((qh ferr, 1015, "qh_test_vneighbors: testing vertex neighbors for convexity\n"));
  if (!qh VERTEXneighbors)
    qh_vertexneighbors();
  FORALLnew_facets
    newfacet->seen= False;
  FORALLnew_facets {
    newfacet->seen= True;
    newfacet->visitid= qh visit_id++;
    FOREACHneighbor_(newfacet)
      newfacet->visitid= qh visit_id;
    FOREACHvertex_(newfacet->vertices) {
      FOREACHneighbor_(vertex) {
        if (neighbor->seen || neighbor->visitid == qh visit_id)
          continue;
        if (qh_test_appendmerge(newfacet, neighbor, False)) /* ignores optimization for simplicial ridges */
          nummerges++;
      }
    }
  }
  zadd_(Ztestvneighbor, nummerges);
  trace1((qh ferr, 1016, "qh_test_vneighbors: found %d non-convex, vertex neighbors\n",
           nummerges));
  return (nummerges > 0);
} /* test_vneighbors */

/*---------------------------------

  qh_tracemerge( facet1, facet2 )
    print trace message after merge
*/
void qh_tracemerge(facetT *facet1, facetT *facet2, mergeType mergetype) {
  boolT waserror= False;
  const char *mergename;

#ifndef qh_NOtrace
  if(mergetype > 0 && mergetype < sizeof(mergetypes)/sizeof(char *))
    mergename= mergetypes[mergetype];
  else
    mergename= mergetypes[MRGnone];
  if (qh IStracing >= 4)
    qh_errprint("MERGED", facet2, NULL, NULL, NULL);
  if (facet2 == qh tracefacet || (qh tracevertex && qh tracevertex->newfacet)) {
    qh_fprintf(qh ferr, 8085, "qh_tracemerge: trace facet and vertex after merge of f%d into f%d type %d (%s), furthest p%d\n",
      facet1->id, facet2->id, mergetype, mergename, qh furthest_id);
    if (facet2 != qh tracefacet)
      qh_errprint("TRACE", qh tracefacet,
        (qh tracevertex && qh tracevertex->neighbors) ?
           SETfirstt_(qh tracevertex->neighbors, facetT) : NULL,
        NULL, qh tracevertex);
  }
  if (qh tracevertex) {
    if (qh tracevertex->deleted)
      qh_fprintf(qh ferr, 8086, "qh_tracemerge: trace vertex deleted at furthest p%d\n",
            qh furthest_id);
    else
      qh_checkvertex(qh tracevertex, qh_ALL, &waserror);
  }
  if (qh tracefacet && qh tracefacet->normal && !qh tracefacet->visible)
    qh_checkfacet(qh tracefacet, True /* newmerge */, &waserror);
#endif /* !qh_NOtrace */
  if (qh CHECKfrequently || qh IStracing >= 4) { /* can't check polygon here */
    if (qh IStracing >= 4 && qh num_facets < 500) {
      qh_printlists();
    }
    qh_checkfacet(facet2, True /* newmerge */, &waserror);
  }
  if (waserror)
    qh_errexit(qh_ERRqhull, NULL, NULL); /* erroneous facet logged by qh_checkfacet */
} /* tracemerge */

/*---------------------------------

  qh_tracemerging( )
    print trace message during POSTmerging

  returns:
    updates qh.mergereport

  notes:
    called from qh_mergecycle() and qh_mergefacet()

  see:
    qh_buildtracing()
*/
void qh_tracemerging(void) {
  realT cpu;
  int total;
  time_t timedata;
  struct tm *tp;

  qh mergereport= zzval_(Ztotmerge);
  time(&timedata);
  tp= localtime(&timedata);
  cpu= qh_CPUclock;
  cpu /= qh_SECticks;
  total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
  qh_fprintf(qh ferr, 8087, "\n\
At %d:%d:%d & %2.5g CPU secs, qhull has merged %d facets with max_outside %2.2g, min_vertex %2.2g.\n\
  The hull contains %d facets and %d vertices.\n",
      tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, total, qh max_outside, qh min_vertex,
      qh num_facets - qh num_visible,
      qh num_vertices-qh_setsize(qh del_vertices));
} /* tracemerging */

/*---------------------------------

  qh_updatetested( facet1, facet2 )
    clear facet2->tested and facet1->ridge->tested for merge

  returns:
    deletes facet2->center unless it's already large
      if so, clears facet2->ridge->tested

  notes:
    only called by qh_mergefacet

  design:
    clear facet2->tested
    clear ridge->tested for facet1's ridges
    if facet2 has a centrum
      if facet2 is large
        set facet2->keepcentrum
      else if facet2 has 3 vertices due to many merges, or not large and post merging
        clear facet2->keepcentrum
      unless facet2->keepcentrum
        clear facet2->center to recompute centrum later
        clear ridge->tested for facet2's ridges
*/
void qh_updatetested(facetT *facet1, facetT *facet2) {
  ridgeT *ridge, **ridgep;
  int size;

  facet2->tested= False;
  FOREACHridge_(facet1->ridges)
    ridge->tested= False;
  if (!facet2->center)
    return;
  size= qh_setsize(facet2->vertices);
  if (!facet2->keepcentrum) {
    if (size > qh hull_dim + qh_MAXnewcentrum) {
      facet2->keepcentrum= True;
      zinc_(Zwidevertices);
    }
  }else if (size <= qh hull_dim + qh_MAXnewcentrum) {
    /* center and keepcentrum was set */
    if (size == qh hull_dim || qh POSTmerging)
      facet2->keepcentrum= False; /* if many merges need to recompute centrum */
  }
  if (!facet2->keepcentrum) {
    qh_memfree(facet2->center, qh normal_size);
    facet2->center= NULL;
    FOREACHridge_(facet2->ridges)
      ridge->tested= False;
  }
} /* updatetested */

/*---------------------------------

  qh_vertexridges( vertex, allneighbors )
    return temporary set of ridges adjacent to a vertex
    vertex->neighbors defined (qh_vertexneighbors)

  notes:
    uses qh.visit_id
    does not include implicit ridges for simplicial facets
    skips last neighbor, unless allneighbors.  For new facets, the last neighbor shares ridges with adjacent neighbors
    if the last neighbor is not simplicial, it will have ridges for its simplicial neighbors
    Use allneighbors when a new cone is attached to an existing convex hull
    similar to qh_neighbor_vertices

  design:
    for each neighbor of vertex
      add ridges that include the vertex to ridges
*/
setT *qh_vertexridges(vertexT *vertex, boolT allneighbors) {
  facetT *neighbor, **neighborp;
  setT *ridges= qh_settemp(qh TEMPsize);
  int size;

  qh visit_id += 2;  /* visit_id for vertex neighbors, visit_id-1 for facets of visited ridges */
  FOREACHneighbor_(vertex)
    neighbor->visitid= qh visit_id;
  FOREACHneighbor_(vertex) {
    if (*neighborp || allneighbors)   /* no new ridges in last neighbor */
      qh_vertexridges_facet(vertex, neighbor, &ridges);
  }
  if (qh PRINTstatistics || qh IStracing) {
    size= qh_setsize(ridges);
    zinc_(Zvertexridge);
    zadd_(Zvertexridgetot, size);
    zmax_(Zvertexridgemax, size);
    trace3((qh ferr, 3011, "qh_vertexridges: found %d ridges for v%d\n",
             size, vertex->id));
  }
  return ridges;
} /* vertexridges */

/*---------------------------------

  qh_vertexridges_facet( vertex, facet, ridges )
    add adjacent ridges for vertex in facet
    neighbor->visitid==qh.visit_id if it hasn't been visited

  returns:
    ridges updated
    sets facet->visitid to qh.visit_id-1

  design:
    for each ridge of facet
      if ridge of visited neighbor (i.e., unprocessed)
        if vertex in ridge
          append ridge
    mark facet processed
*/
void qh_vertexridges_facet(vertexT *vertex, facetT *facet, setT **ridges) {
  ridgeT *ridge, **ridgep;
  facetT *neighbor;
  int last_i= qh hull_dim-2;
  vertexT *second, *last;

  FOREACHridge_(facet->ridges) {
    neighbor= otherfacet_(ridge, facet);
    if (neighbor->visitid == qh visit_id) {
      if (SETfirst_(ridge->vertices) == vertex) {
        qh_setappend(ridges, ridge);
      }else if (last_i > 2) {
        second= SETsecondt_(ridge->vertices, vertexT);
        last= SETelemt_(ridge->vertices, last_i, vertexT);
        if (second->id >= vertex->id && last->id <= vertex->id) { /* vertices inverse sorted by id */
          if (second == vertex || last == vertex)
            qh_setappend(ridges, ridge);
          else if (qh_setin(ridge->vertices, vertex))
            qh_setappend(ridges, ridge);
        }
      }else if (SETelem_(ridge->vertices, last_i) == vertex
          || (last_i > 1 && SETsecond_(ridge->vertices) == vertex)) {
        qh_setappend(ridges, ridge);
      }
    }
  }
  facet->visitid= qh visit_id-1;
} /* vertexridges_facet */

/*---------------------------------

  qh_willdelete( facet, replace )
    moves facet to visible list for qh_deletevisible
    sets facet->f.replace to replace (may be NULL)
    clears f.ridges and f.neighbors -- no longer valid

  returns:
    bumps qh.num_visible
*/
void qh_willdelete(facetT *facet, facetT *replace) {

  trace4((qh ferr, 4081, "qh_willdelete: move f%d to visible list, set its replacement as f%d, and clear f.neighbors and f.ridges\n", facet->id, getid_(replace)));
  if (!qh visible_list && qh newfacet_list) {
    qh_fprintf(qh ferr, 6378, "qhull internal error (qh_willdelete): expecting qh.visible_list at before qh.newfacet_list f%d.   Got NULL\n",
        qh newfacet_list->id);
    qh_errexit2(qh_ERRqhull, NULL, NULL);
  }
  qh_removefacet(facet);
  qh_prependfacet(facet, &qh visible_list);
  qh num_visible++;
  facet->visible= True;
  facet->f.replace= replace;
  if (facet->ridges)
    SETfirst_(facet->ridges)= NULL;
  if (facet->neighbors)
    SETfirst_(facet->neighbors)= NULL;
} /* willdelete */

#else /* qh_NOmerge */

void qh_all_vertexmerges(int apexpointid, facetT *facet, facetT **retryfacet) {
  QHULL_UNUSED(apexpointid)
  QHULL_UNUSED(facet)
  QHULL_UNUSED(retryfacet)
}
void qh_premerge(int apexpointid, realT maxcentrum, realT maxangle) {
  QHULL_UNUSED(apexpointid)
  QHULL_UNUSED(maxcentrum)
  QHULL_UNUSED(maxangle)
}
void qh_postmerge(const char *reason, realT maxcentrum, realT maxangle,
                      boolT vneighbors) {
  QHULL_UNUSED(reason)
  QHULL_UNUSED(maxcentrum)
  QHULL_UNUSED(maxangle)
  QHULL_UNUSED(vneighbors)
}
void qh_checkdelfacet(facetT *facet, setT *mergeset) {
  QHULL_UNUSED(facet)
  QHULL_UNUSED(mergeset)
}
void qh_checkdelridge(void /* qh.visible_facets, vertex_mergeset */) {
}
boolT qh_checkzero(boolT testall) {
  QHULL_UNUSED(testall)
    
  return True;
}
void qh_freemergesets(void) {
}
void qh_initmergesets(void) {
}
void qh_merge_pinchedvertices(int apexpointid /* qh.newfacet_list */) {
  QHULL_UNUSED(apexpointid)
}
#endif /* qh_NOmerge */

qhull-2020.2/src/libqhull/merge.h0000644060175106010010000002614213661631132015050 0ustar  bbarber/*
  ---------------------------------

   merge.h
   header file for merge.c

   see qh-merge.htm and merge.c

   Copyright (c) 1993-2020 C.B. Barber.
   $Id: //main/2019/qhull/src/libqhull/merge.h#3 $$Change: 2953 $
   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
*/

#ifndef qhDEFmerge
#define qhDEFmerge 1

#include "libqhull.h"


/*============ -constants- ==============*/

/*----------------------------------

  qh_ANGLEnone
    indicates missing angle for mergeT->angle
*/
#define qh_ANGLEnone 2.0

/*----------------------------------

  MRG... (mergeType)
    indicates the type of a merge (mergeT->type)
    MRGcoplanar...MRGtwisted set by qh_test_centrum_merge, qh_test_nonsimplicial_merge
*/
typedef enum {  /* must match mergetypes[] */
  MRGnone= 0,
                  /* MRGcoplanar..MRGtwisted go into qh.facet_mergeset for qh_all_merges 
                     qh_compare_facetmerge selects lower mergetypes for merging first */
  MRGcoplanar,          /* (1) centrum coplanar if centrum ('Cn') or vertex not clearly above or below neighbor */
  MRGanglecoplanar,     /* (2) angle coplanar if angle ('An') is coplanar */
  MRGconcave,           /* (3) concave ridge */
  MRGconcavecoplanar,   /* (4) concave and coplanar ridge, one side concave, other side coplanar */
  MRGtwisted,           /* (5) twisted ridge, both concave and convex, facet1 is wider */
                  /* MRGflip go into qh.facet_mergeset for qh_flipped_merges */
  MRGflip,              /* (6) flipped facet if qh.interior_point is above facet, w/ facet1 == facet2 */
                  /* MRGdupridge go into qh.facet_mergeset for qh_forcedmerges */
  MRGdupridge,          /* (7) dupridge if more than two neighbors.  Set by qh_mark_dupridges for qh_MERGEridge */
                  /* MRGsubridge and MRGvertices go into vertex_mergeset */
  MRGsubridge,          /* (8) merge pinched vertex to remove the subridge of a MRGdupridge */
  MRGvertices,          /* (9) merge pinched vertex to remove a facet's ridges with the same vertices */
                  /* MRGdegen, MRGredundant, and MRGmirror go into qh.degen_mergeset */
  MRGdegen,             /* (10) degenerate facet (!enough neighbors) facet1 == facet2 */
  MRGredundant,         /* (11) redundant facet (vertex subset) */
                        /* merge_degenredundant assumes degen < redundant */
  MRGmirror,            /* (12) mirror facets: same vertices due to null facets in qh_triangulate 
                           f.redundant for both facets*/
                  /* MRGcoplanarhorizon for qh_mergecycle_all only */
  MRGcoplanarhorizon,   /* (13) new facet coplanar with the horizon (qh_mergecycle_all) */
  ENDmrg
} mergeType;

/*----------------------------------

  qh_MERGEapex
    flag for qh_mergefacet() to indicate an apex merge
*/
#define qh_MERGEapex     True

/*============ -structures- ====================*/

/*----------------------------------

  mergeT
    structure used to merge facets
*/

typedef struct mergeT mergeT;
struct mergeT {         /* initialize in qh_appendmergeset */
  realT   angle;        /* cosine of angle between normals of facet1 and facet2, 
                           null value and right angle is 0.0, coplanar is 1.0, narrow is -1.0 */
  realT   distance;     /* absolute value of distance between vertices, centrum and facet, or vertex and facet */
  facetT *facet1;       /* will merge facet1 into facet2 */
  facetT *facet2;
  vertexT *vertex1;     /* will merge vertext1 into vertex2 for MRGsubridge or MRGvertices */
  vertexT *vertex2;
  ridgeT  *ridge1;      /* the duplicate ridges resolved by MRGvertices */
  ridgeT  *ridge2;      /* merge is deleted if either ridge is deleted (qh_delridge) */
  mergeType mergetype;
};


/*=========== -macros- =========================*/

/*----------------------------------

  FOREACHmerge_( merges ) {...}
    assign 'merge' to each merge in merges

  notes:
    uses 'mergeT *merge, **mergep;'
    if qh_mergefacet(),
      restart or use qh_setdellast() since qh.facet_mergeset may change
    see FOREACHsetelement_
*/
#define FOREACHmerge_(merges) FOREACHsetelement_(mergeT, merges, merge)

/*----------------------------------

  FOREACHmergeA_( vertices ) { ... }
    assign 'mergeA' to each merge in merges

  notes:
    uses 'mergeT *mergeA, *mergeAp;'
    see FOREACHsetelement_
*/
#define FOREACHmergeA_(merges) FOREACHsetelement_(mergeT, merges, mergeA)

/*----------------------------------

  FOREACHmerge_i_( vertices ) { ... }
    assign 'merge' and 'merge_i' for each merge in mergeset

  declare:
    mergeT *merge;
    int     merge_n, merge_i;

  see:
    FOREACHsetelement_i_
*/
#define FOREACHmerge_i_(mergeset) FOREACHsetelement_i_(mergeT, mergeset, merge)

/*============ prototypes in alphabetical order after pre/postmerge =======*/

void    qh_premerge(int apexpointid, realT maxcentrum, realT maxangle);
void    qh_postmerge(const char *reason, realT maxcentrum, realT maxangle,
             boolT vneighbors);
void    qh_all_merges(boolT othermerge, boolT vneighbors);
void    qh_all_vertexmerges(int apexpointid, facetT *facet, facetT **retryfacet);
void    qh_appendmergeset(facetT *facet, facetT *neighbor, mergeType mergetype, coordT dist, realT angle);
void    qh_appendvertexmerge(vertexT *vertex, vertexT *destination, mergeType mergetype, realT distance, ridgeT *ridge1, ridgeT *ridge2);
setT   *qh_basevertices(facetT *samecycle);
void    qh_check_dupridge(facetT *facet1, realT dist1, facetT *facet2, realT dist2);
void    qh_checkconnect(void /* qh.new_facets */);
void    qh_checkdelfacet(facetT *facet, setT *mergeset);
void    qh_checkdelridge(void /* qh.visible_facets, vertex_mergeset */);
boolT   qh_checkzero(boolT testall);
int     qh_compare_anglemerge(const void *p1, const void *p2);
int     qh_compare_facetmerge(const void *p1, const void *p2);
int     qh_comparevisit(const void *p1, const void *p2);
void    qh_copynonconvex(ridgeT *atridge);
void    qh_degen_redundant_facet(facetT *facet);
void    qh_drop_mergevertex(mergeT *merge);
void    qh_delridge_merge(ridgeT *ridge);
vertexT *qh_find_newvertex(vertexT *oldvertex, setT *vertices, setT *ridges);
vertexT *qh_findbest_pinchedvertex(mergeT *merge, vertexT *apex, vertexT **pinchedp, realT *distp /* qh.newfacet_list */);
vertexT *qh_findbest_ridgevertex(ridgeT *ridge, vertexT **pinchedp, coordT *distp);
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_freemergesets(void);
void    qh_getmergeset(facetT *facetlist);
void    qh_getmergeset_initial(facetT *facetlist);
boolT   qh_getpinchedmerges(vertexT *apex, coordT maxdupdist, boolT *iscoplanar /* qh.newfacet_list, vertex_mergeset */);
boolT   qh_hasmerge(setT *mergeset, mergeType type, facetT *facetA, facetT *facetB);
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_initmergesets(void);
void    qh_makeridges(facetT *facet);
void    qh_mark_dupridges(facetT *facetlist, boolT allmerges);
void    qh_maybe_duplicateridge(ridgeT *ridge);
void    qh_maybe_duplicateridges(facetT *facet);
void    qh_maydropneighbor(facetT *facet);
int     qh_merge_degenredundant(void);
void    qh_merge_nonconvex(facetT *facet1, facetT *facet2, mergeType mergetype);
void    qh_merge_pinchedvertices(int apexpointid /* qh.newfacet_list */);
void    qh_merge_twisted(facetT *facet1, facetT *facet2);
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, mergeType mergetype, 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);
setT   *qh_neighbor_vertices(vertexT *vertex, setT *subridge);
void    qh_neighbor_vertices_facet(vertexT *vertexA, facetT *facet, setT **vertices);
void    qh_newvertices(setT *vertices);
mergeT *qh_next_vertexmerge(void);
facetT *qh_opposite_horizonfacet(mergeT *merge, vertexT **vertex);
boolT   qh_reducevertices(void);
vertexT *qh_redundant_vertex(vertexT *vertex);
boolT   qh_remove_extravertices(facetT *facet);
void    qh_remove_mergetype(setT *mergeset, mergeType type);
void    qh_rename_adjacentvertex(vertexT *oldvertex, vertexT *newvertex, realT dist);
vertexT *qh_rename_sharedvertex(vertexT *vertex, facetT *facet);
boolT   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 simplicial);
void    qh_test_degen_neighbors(facetT *facet);
boolT   qh_test_centrum_merge(facetT *facet, facetT *neighbor, realT angle, boolT okangle);
boolT   qh_test_nonsimplicial_merge(facetT *facet, facetT *neighbor, realT angle, boolT okangle);
void    qh_test_redundant_neighbors(facetT *facet);
boolT   qh_test_vneighbors(void /* qh.newfacet_list */);
void    qh_tracemerge(facetT *facet1, facetT *facet2, mergeType mergetype);
void    qh_tracemerging(void);
void    qh_undo_newfacets(void);
void    qh_updatetested(facetT *facet1, facetT *facet2);
setT   *qh_vertexridges(vertexT *vertex, boolT allneighbors);
void    qh_vertexridges_facet(vertexT *vertex, facetT *facet, setT **ridges);
void    qh_willdelete(facetT *facet, facetT *replace);

#endif /* qhDEFmerge */
qhull-2020.2/src/libqhull/poly.c0000644060175106010010000014640113661631132014730 0ustar  bbarber/*
  ---------------------------------

   poly.c
   implements polygons and simplices

   see qh-poly.htm, poly.h and libqhull.h

   infrequent code is in poly2.c
   (all but top 50 and their callers 12/3/95)

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull/poly.c#7 $$Change: 2953 $
   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
*/

#include "qhull_a.h"

/*======== functions in alphabetical order ==========*/

/*---------------------------------

  qh_appendfacet( facet )
    appends facet to end of qh.facet_list,

  returns:
    updates qh.newfacet_list, facet_next, facet_list
    increments qh.numfacets

  notes:
    assumes qh.facet_list/facet_tail is defined (createsimplex)

  see:
    qh_removefacet()

*/
void qh_appendfacet(facetT *facet) {
  facetT *tail= qh facet_tail;

  if (tail == qh newfacet_list) {
    qh newfacet_list= facet;
    if (tail == qh visible_list) /* visible_list is at or before newfacet_list */
      qh visible_list= facet;
  }
  if (tail == qh facet_next)
    qh facet_next= facet;
  facet->previous= tail->previous;
  facet->next= tail;
  if (tail->previous)
    tail->previous->next= facet;
  else
    qh facet_list= facet;
  tail->previous= facet;
  qh num_facets++;
  trace4((qh ferr, 4044, "qh_appendfacet: append f%d to facet_list\n", facet->id));
} /* appendfacet */


/*---------------------------------

  qh_appendvertex( vertex )
    appends vertex to end of qh.vertex_list,

  returns:
    sets vertex->newfacet
    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->newfacet= True;
  vertex->previous= tail->previous;
  vertex->next= tail;
  if (tail->previous)
    tail->previous->next= vertex;
  else
    qh vertex_list= vertex;
  tail->previous= vertex;
  qh num_vertices++;
  trace4((qh ferr, 4045, "qh_appendvertex: append v%d to qh.newvertex_list and set v.newfacet\n", vertex->id));
} /* appendvertex */


/*---------------------------------

  qh_attachnewfacets( )
    attach horizon facets to new facets in qh.newfacet_list
    newfacets have neighbor and ridge links to horizon but not vice versa

  returns:
    clears qh.NEWtentative
    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)

  notes:
    used for qh.NEWtentative, otherwise see qh_makenew_nonsimplicial and qh_makenew_simplicial
    qh_delridge_merge not needed (as tested by qh_checkdelridge)

  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 is non-simplicial
          for all visible neighbors of the horizon facet
            link visible neighbor to new facet
            delete visible neighbor from horizon facet
          append new facet to horizon's neighbors
          the first ridge of the new facet is the horizon ridge
          link the new facet into the horizon ridge
*/
void qh_attachnewfacets(void /* qh.visible_list, qh.newfacet_list */) {
  facetT *newfacet= NULL, *neighbor, **neighborp, *horizon, *visible;
  ridgeT *ridge, **ridgep;

  trace3((qh ferr, 3012, "qh_attachnewfacets: delete interior ridges\n"));
  if (qh CHECKfrequently) {
    qh_checkdelridge();
  }
  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_delridge(ridge); /* delete on second visit */
        }
      }
    }
  }
  trace1((qh ferr, 1017, "qh_attachnewfacets: attach horizon facets to new facets\n"));
  FORALLnew_facets {
    horizon= SETfirstt_(newfacet->neighbors, facetT);
    if (horizon->simplicial) {
      visible= NULL;
      FOREACHneighbor_(horizon) {   /* may have more than one horizon ridge */
        if (neighbor->visible) {
          if (visible) {
            if (qh_setequal_skip(newfacet->vertices, 0, horizon->vertices,
                                  SETindex_(horizon->neighbors, neighbor))) {
              visible= neighbor;
              break;
            }
          }else
            visible= neighbor;
        }
      }
      if (visible) {
        visible->f.replace= newfacet;
        qh_setreplace(horizon->neighbors, visible, newfacet);
      }else {
        qh_fprintf(qh ferr, 6102, "qhull internal error (qh_attachnewfacets): could not 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;
        ridge->simplicialbot= True;
      }else {
        ridge->top= newfacet;
        ridge->simplicialtop= True;
      }
    }
  } /* newfacets */
  trace4((qh ferr, 4094, "qh_attachnewfacets: clear f.ridges and f.neighbors for visible facets, may become invalid before qh_deletevisible\n"));
  FORALLvisible_facets {
    if (visible->ridges)
      SETfirst_(visible->ridges)= NULL; 
    SETfirst_(visible->neighbors)= NULL;
  }
  qh NEWtentative= False;
  qh NEWfacets= True;
  if (qh PRINTstatistics) {
    FORALLvisible_facets {
      if (!visible->f.replace)
        zinc_(Zinsidevisible);
    }
  }
} /* attachnewfacets */

/*---------------------------------

  qh_checkflipped( facet, dist, allerror )
    checks facet orientation to interior point

    if allerror set,
      tests against -qh.DISTround
    else
      tests against 0.0 since tested against -qh.DISTround before

  returns:
    False if it flipped orientation (sets facet->flipped)
    distance if non-NULL

  notes:
    called by qh_setfacetplane, qh_initialhull, and qh_checkflipped_all
*/
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;
    trace0((qh ferr, 19, "qh_checkflipped: facet f%d flipped, allerror? %d, distance= %6.12g during p%d\n",
              facet->id, allerror, dist, qh furthest_id));
    if (qh num_facets > qh hull_dim+1) { /* qh_initialhull reverses orientation if !qh_checkflipped */
      zzinc_(Zflippedfacets);
      qh_joggle_restart("flipped facet");
    }
    return False;
  }
  return True;
} /* checkflipped */

/*---------------------------------

  qh_delfacet( facet )
    removes facet from facet_list and frees up its memory

  notes:
    assumes vertices and ridges already freed or referenced elsewhere
*/
void qh_delfacet(facetT *facet) {
  void **freelistp; /* used if !qh_NOmem by qh_memfree_() */

  trace3((qh ferr, 3057, "qh_delfacet: delete f%d\n", facet->id));
  if (qh CHECKfrequently || qh VERIFYoutput) { 
    if (!qh NOerrexit) {
      qh_checkdelfacet(facet, qh facet_mergeset);
      qh_checkdelfacet(facet, qh degen_mergeset);
      qh_checkdelfacet(facet, qh vertex_mergeset);
    }
  }
  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) {   /* braces for macro calls */
      qh_memfree_(facet->center, qh center_size, freelistp);
    }else /* AScentrum */ {
      qh_memfree_(facet->center, qh normal_size, freelistp);
    }
  }
  qh_setfree(&(facet->neighbors));
  if (facet->ridges)
    qh_setfree(&(facet->ridges));
  qh_setfree(&(facet->vertices));
  if (facet->outsideset)
    qh_setfree(&(facet->outsideset));
  if (facet->coplanarset)
    qh_setfree(&(facet->coplanarset));
  qh_memfree_(facet, (int)sizeof(facetT), freelistp);
} /* delfacet */


/*---------------------------------

  qh_deletevisible()
    delete visible facets and vertices

  returns:
    deletes each facet and removes from facetlist
    deletes vertices on qh.del_vertices and ridges in qh.del_ridges
    at exit, qh.visible_list empty (== qh.newfacet_list)

  notes:
    called by qh_all_vertexmerges, qh_addpoint, and qh_qhull
    ridges already deleted or moved elsewhere
    deleted vertices on qh.del_vertices
    horizon facets do not reference facets on qh.visible_list
    new facets in qh.newfacet_list
    uses   qh.visit_id;
*/
void qh_deletevisible(void /* qh.visible_list */) {
  facetT *visible, *nextfacet;
  vertexT *vertex, **vertexp;
  int numvisible= 0, numdel= qh_setsize(qh del_vertices);

  trace1((qh ferr, 1018, "qh_deletevisible: delete %d visible facets and %d vertices\n",
         qh num_visible, numdel));
  for (visible=qh visible_list; visible && visible->visible;
                visible= nextfacet) { /* deleting current */
    nextfacet= visible->next;
    numvisible++;
    qh_delfacet(visible);  /* f.ridges deleted or moved elsewhere, deleted f.vertices on qh.del_vertices */
  }
  if (numvisible != qh num_visible) {
    qh_fprintf(qh ferr, 6103, "qhull internal error (qh_deletevisible): qh num_visible %d is not number of visible facets %d\n",
             qh num_visible, numvisible);
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  qh num_visible= 0;
  zadd_(Zvisfacettot, numvisible);
  zmax_(Zvisfacetmax, numvisible);
  zzadd_(Zdelvertextot, numdel);
  zmax_(Zdelvertexmax, numdel);
  FOREACHvertex_(qh del_vertices)
    qh_delvertex(vertex);
  qh_settruncate(qh del_vertices, 0);
} /* deletevisible */

/*---------------------------------

  qh_facetintersect( facetA, facetB, skipa, skipB, prepend )
    return vertices for intersection of two simplicial facets
    may include 1 prepended entry (if more, need to settemppush)

  returns:
    returns set of qh.hull_dim-1 + prepend vertices
    returns skipped index for each test and checks for exactly one

  notes:
    does not need settemp since set in quick memory

  see also:
    qh_vertexintersect and qh_vertexintersect_new
    use qh_setnew_delnthsorted to get nth ridge (no skip information)

  design:
    locate skipped vertex by scanning facet A's neighbors
    locate skipped vertex by scanning facet B's neighbors
    intersect the vertex sets
*/
setT *qh_facetintersect(facetT *facetA, facetT *facetB,
                         int *skipA,int *skipB, int prepend) {
  setT *intersect;
  int dim= qh hull_dim, i, j;
  facetT **neighborsA, **neighborsB;

  neighborsA= SETaddr_(facetA->neighbors, facetT);
  neighborsB= SETaddr_(facetB->neighbors, facetT);
  i= j= 0;
  if (facetB == *neighborsA++)
    *skipA= 0;
  else if (facetB == *neighborsA++)
    *skipA= 1;
  else if (facetB == *neighborsA++)
    *skipA= 2;
  else {
    for (i=3; i < dim; i++) {
      if (facetB == *neighborsA++) {
        *skipA= i;
        break;
      }
    }
  }
  if (facetA == *neighborsB++)
    *skipB= 0;
  else if (facetA == *neighborsB++)
    *skipB= 1;
  else if (facetA == *neighborsB++)
    *skipB= 2;
  else {
    for (j=3; j < dim; j++) {
      if (facetA == *neighborsB++) {
        *skipB= j;
        break;
      }
    }
  }
  if (i >= dim || j >= dim) {
    qh_fprintf(qh ferr, 6104, "qhull internal error (qh_facetintersect): f%d or f%d not in other's neighbors\n",
            facetA->id, facetB->id);
    qh_errexit2(qh_ERRqhull, facetA, facetB);
  }
  intersect= qh_setnew_delnthsorted(facetA->vertices, qh hull_dim, *skipA, prepend);
  trace4((qh ferr, 4047, "qh_facetintersect: f%d skip %d matches f%d skip %d\n",
          facetA->id, *skipA, facetB->id, *skipB));
  return(intersect);
} /* facetintersect */

/*---------------------------------

  qh_gethash( hashsize, set, size, firstindex, skipelem )
    return hashvalue for a set with firstindex and skipelem

  notes:
    returned hash is in [0,hashsize)
    assumes at least firstindex+1 elements
    assumes skipelem is NULL, in set, or part of hash

    hashes memory addresses which may change over different runs of the same data
    using sum for hash does badly in high d
*/
int qh_gethash(int hashsize, setT *set, int size, int firstindex, void *skipelem) {
  void **elemp= SETelemaddr_(set, firstindex, void);
  ptr_intT hash= 0, elem;
  unsigned int uresult;
  int i;
#ifdef _MSC_VER                   /* Microsoft Visual C++ -- warn about 64-bit issues */
#pragma warning( push)            /* WARN64 -- ptr_intT holds a 64-bit pointer */
#pragma warning( disable : 4311)  /* 'type cast': pointer truncation from 'void*' to 'ptr_intT' */
#endif

  switch (size-firstindex) {
  case 1:
    hash= (ptr_intT)(*elemp) - (ptr_intT) skipelem;
    break;
  case 2:
    hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] - (ptr_intT) skipelem;
    break;
  case 3:
    hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
      - (ptr_intT) skipelem;
    break;
  case 4:
    hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
      + (ptr_intT)elemp[3] - (ptr_intT) skipelem;
    break;
  case 5:
    hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
      + (ptr_intT)elemp[3] + (ptr_intT)elemp[4] - (ptr_intT) skipelem;
    break;
  case 6:
    hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
      + (ptr_intT)elemp[3] + (ptr_intT)elemp[4]+ (ptr_intT)elemp[5]
      - (ptr_intT) skipelem;
    break;
  default:
    hash= 0;
    i= 3;
    do {     /* this is about 10% in 10-d */
      if ((elem= (ptr_intT)*elemp++) != (ptr_intT)skipelem) {
        hash ^= (elem << i) + (elem >> (32-i));
        i += 3;
        if (i >= 32)
          i -= 32;
      }
    }while (*elemp);
    break;
  }
  if (hashsize<0) {
    qh_fprintf(qh ferr, 6202, "qhull internal error: negative hashsize %d passed to qh_gethash [poly.c]\n", hashsize);
    qh_errexit2(qh_ERRqhull, NULL, NULL);
  }
  uresult= (unsigned int)hash;
  uresult %= (unsigned int)hashsize;
  /* result= 0; for debugging */
  return (int)uresult;
#ifdef _MSC_VER
#pragma warning( pop)
#endif
} /* gethash */

/*---------------------------------

  qh_getreplacement( visible )
    get replacement for visible facet

  returns:
    valid facet from visible.replace (may be chained)
*/
facetT *qh_getreplacement(facetT *visible) {
  unsigned int count= 0;

  facetT *result= visible;
  while (result && result->visible) {
    result= result->f.replace;
    if (count++ > qh facet_id)
      qh_infiniteloop(visible);
  }
  return result;
}

/*---------------------------------

  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->newfacet) {
      qh_removevertex(vertex);
      qh_appendvertex(vertex);
    }
  }
  newfacet= qh_newfacet();
  newfacet->vertices= vertices;
  if (toporient)
    newfacet->toporient= True;
  if (horizon)
    qh_setappend(&(newfacet->neighbors), horizon);
  qh_appendfacet(newfacet);
  return(newfacet);
} /* makenewfacet */


/*---------------------------------

  qh_makenewplanes()
    make new hyperplanes for facets on qh.newfacet_list

  returns:
    all facets have hyperplanes or are marked for   merging
    doesn't create hyperplane if horizon is coplanar (will merge)
    updates qh.min_vertex if qh.JOGGLEmax

  notes:
    facet->f.samecycle is defined for facet->mergehorizon facets
*/
void qh_makenewplanes(void /* qh.newfacet_list */) {
  facetT *newfacet;

  trace4((qh ferr, 4074, "qh_makenewplanes: make new hyperplanes for facets on qh.newfacet_list f%d\n",
    qh newfacet_list->id));
  FORALLnew_facets {
    if (!newfacet->mergehorizon)
      qh_setfacetplane(newfacet); /* updates Wnewvertexmax */
  }
  if (qh JOGGLEmax < REALmax/2)
    minimize_(qh min_vertex, -wwval_(Wnewvertexmax));
} /* makenewplanes */

#ifndef qh_NOmerge
/*---------------------------------

  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 NEWtentative
    marks ridge neighbors for simplicial visible
    if (qh.NEWtentative)
      ridges on newfacet, horizon, and visible
    else
      ridge and neighbors between newfacet and horizon
      visible facet's ridges are deleted
      visible facet's f.neighbors is empty

  notes:
    called by qh_makenewfacets and qh_triangulatefacet
    qh.visit_id if visible has already been processed
    sets neighbor->seen for building f.samecycle
      assumes all 'seen' flags initially false
    qh_delridge_merge not needed (as tested by qh_checkdelridge in qh_makenewfacets)

  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)

*/
facetT *qh_makenew_nonsimplicial(facetT *visible, vertexT *apex, int *numnew) {
  void **freelistp; /* used if !qh_NOmem by qh_memfree_() */
  ridgeT *ridge, **ridgep;
  facetT *neighbor, *newfacet= NULL, *samecycle;
  setT *vertices;
  boolT toporient;
  unsigned int ridgeid;

  FOREACHridge_(visible->ridges) {
    ridgeid= ridge->id;
    neighbor= otherfacet_(ridge, visible);
    if (neighbor->visible) {
      if (!qh NEWtentative) {
        if (neighbor->visitid == qh visit_id) {
          if (qh traceridge == ridge)
            qh traceridge= NULL;
          qh_setfree(&(ridge->vertices));  /* delete on 2nd visit */
          qh_memfree_(ridge, (int)sizeof(ridgeT), freelistp);
        }
      }
    }else {  /* neighbor is an horizon facet */
      toporient= (ridge->top == visible);
      vertices= qh_setnew(qh hull_dim); /* makes sure this is quick */
      qh_setappend(&vertices, apex);
      qh_setappend_set(&vertices, ridge->vertices);
      newfacet= qh_makenewfacet(vertices, toporient, neighbor);
      (*numnew)++;
      if (neighbor->coplanarhorizon) {
        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 NEWtentative) {
        if (!neighbor->simplicial)
          qh_setappend(&(newfacet->ridges), ridge);
      }else {  /* qh_attachnewfacets */
        if (neighbor->seen) {
          if (neighbor->simplicial) {
            qh_fprintf(qh ferr, 6105, "qhull internal error (qh_makenew_nonsimplicial): simplicial f%d sharing two ridges with f%d\n",
                   neighbor->id, visible->id);
            qh_errexit2(qh_ERRqhull, neighbor, visible);
          }
          qh_setappend(&(neighbor->neighbors), newfacet);
        }else
          qh_setreplace(neighbor->neighbors, visible, newfacet);
        if (neighbor->simplicial) {
          qh_setdel(neighbor->ridges, ridge);
          qh_delridge(ridge);
        }else {
          qh_setappend(&(newfacet->ridges), ridge);
          if (toporient) {
            ridge->top= newfacet;
            ridge->simplicialtop= True;
          }else {
            ridge->bottom= newfacet;
            ridge->simplicialbot= True;
          }
        }
      }
      trace4((qh ferr, 4048, "qh_makenew_nonsimplicial: created facet f%d from v%d and r%d of horizon f%d\n",
          newfacet->id, apex->id, ridgeid, neighbor->id));
    }
    neighbor->seen= True;
  } /* for each ridge */
  return newfacet;
} /* makenew_nonsimplicial */

#else /* qh_NOmerge */
facetT *qh_makenew_nonsimplicial(facetT *visible, vertexT *apex, int *numnew) {
  QHULL_UNUSED(visible)
  QHULL_UNUSED(apex)
  QHULL_UNUSED(numnew)

  return NULL;
}
#endif /* qh_NOmerge */

/*---------------------------------

  qh_makenew_simplicial( visible, apex, numnew )
    make new facets for simplicial visible facet and apex

  returns:
    attaches new facets if !qh.NEWtentative
      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= 0, visibleskip= 0;

  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->coplanarhorizon && (qh PREmerge || qh MERGEexact)) {
#ifndef qh_NOmerge
        newfacet->f.samecycle= newfacet;
        newfacet->mergehorizon= True;
#endif
      }
      if (!qh NEWtentative)
        SETelem_(neighbor->neighbors, horizonskip)= newfacet;
      trace4((qh ferr, 4049, "qh_makenew_simplicial: create facet f%d top %d from v%d and horizon f%d skip %d top %d and visible f%d skip %d, flip? %d\n",
            newfacet->id, toporient, apex->id, neighbor->id, horizonskip,
              neighbor->toporient, visible->id, visibleskip, flip));
    }
  }
  return newfacet;
} /* makenew_simplicial */

/*---------------------------------

  qh_matchneighbor( newfacet, newskip, hashsize, hashcount )
    either match subridge of newfacet with neighbor or add to hash_table

  returns:
    matched ridges of newfacet, except for duplicate ridges
    duplicate ridges marked by qh_DUPLICATEridge for qh_matchdupridge

  notes:
    called by qh_matchnewfacets
    assumes newfacet is simplicial
    ridge is newfacet->vertices w/o newskip vertex
    do not allocate memory (need to free hash_table cleanly)
    uses linear hash chains
    see qh_matchdupridge (poly2.c)

  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
          note: dupridge detected when a match 'f&d skip %d' has already been seen 
                need to mark all of the dupridges for qh_matchdupridge
          indicate a duplicate ridge by qh_DUPLICATEridge and f.dupridge
          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

  state at "indicate a duplicate ridge":
    newfacet@newskip= the argument
    facet= the hashed facet@skip that has the same vertices as newfacet@newskip
    same= true if matched vertices have the same orientation
    matchfacet= neighbor at facet@skip
    matchfacet=qh_DUPLICATEridge, matchfacet was previously detected as a dupridge of facet@skip
    ismatch if 'vertex orientation (same) matches facet/newfacet orientation (toporient)
    unknown facet will match later

  details at "indicate a duplicate ridge":
    if !ismatch and matchfacet,
      dupridge is between hashed facet@skip/matchfacet@matchskip and arg newfacet@newskip/unknown 
      set newfacet@newskip, facet@skip, and matchfacet@matchskip to qh_DUPLICATEridge
      add newfacet and matchfacet to hash_table
      if ismatch and matchfacet, 
        same as !ismatch and matchfacet -- it matches facet instead of matchfacet
      if !ismatch and !matchfacet
        dupridge between hashed facet@skip/unknown and arg newfacet@newskip/unknown 
        set newfacet@newskip and facet@skip to qh_DUPLICATEridge
        add newfacet to hash_table
      if ismatch and matchfacet==qh_DUPLICATEridge
        dupridge with already duplicated hashed facet@skip and arg newfacet@newskip/unknown
        set newfacet@newskip to qh_DUPLICATEridge
        add newfacet to hash_table
        facet's hyperplane already set
*/
void qh_matchneighbor(facetT *newfacet, int newskip, int hashsize, int *hashcount) {
  boolT newfound= False;   /* True, if new facet is already in hash chain */
  boolT same, ismatch;
  int hash, scan;
  facetT *facet, *matchfacet;
  int skip, matchskip;

  hash= qh_gethash(hashsize, newfacet->vertices, qh hull_dim, 1,
                     SETelem_(newfacet->vertices, newskip));
  trace4((qh ferr, 4050, "qh_matchneighbor: newfacet f%d skip %d hash %d hashcount %d\n",
          newfacet->id, newskip, hash, *hashcount));
  zinc_(Zhashlookup);
  for (scan=hash; (facet= SETelemt_(qh hash_table, scan, facetT));
       scan= (++scan >= hashsize ? 0 : scan)) {
    if (facet == newfacet) {
      newfound= True;
      continue;
    }
    zinc_(Zhashtests);
    if (qh_matchvertices(1, newfacet->vertices, newskip, facet->vertices, &skip, &same)) {
      if (SETelem_(newfacet->vertices, newskip) == SETelem_(facet->vertices, skip)) {
        qh_joggle_restart("two new facets with the same vertices");
        /* duplicated for multiple skips, not easily avoided */
        qh_fprintf(qh ferr, 7084, "qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f%d and f%d have the same vertices (skip %d, skip %d) and same horizon ridges to f%d and f%d\n",
          facet->id, newfacet->id, skip, newskip, SETfirstt_(facet->neighbors, facetT)->id, SETfirstt_(newfacet->neighbors, facetT)->id);
        /* will rename a vertex (QH3053).  The fault was duplicate ridges (same vertices) in different facets due to a previous rename.  Expensive to detect beforehand */
      }
      ismatch= (same == (boolT)((newfacet->toporient ^ facet->toporient)));
      matchfacet= SETelemt_(facet->neighbors, skip, facetT);
      if (ismatch && !matchfacet) {
        SETelem_(facet->neighbors, skip)= newfacet;
        SETelem_(newfacet->neighbors, newskip)= facet;
        (*hashcount)--;
        trace4((qh ferr, 4051, "qh_matchneighbor: f%d skip %d matched with new f%d skip %d\n",
           facet->id, skip, newfacet->id, newskip));
        return;
      }
      if (!qh PREmerge && !qh MERGEexact) {
        qh_joggle_restart("a ridge with more than two neighbors");
        qh_fprintf(qh ferr, 6107, "qhull topology error: facets f%d, f%d and f%d meet at a ridge with more than 2 neighbors.  Can not continue due to no qh.PREmerge and no 'Qx' (MERGEexact)\n",
                 facet->id, newfacet->id, getid_(matchfacet));
        qh_errexit2(qh_ERRtopology, facet, newfacet);
      }
      SETelem_(newfacet->neighbors, newskip)= qh_DUPLICATEridge;
      newfacet->dupridge= True;
      qh_addhash(newfacet, qh hash_table, hashsize, hash);
      (*hashcount)++;
      if (matchfacet != qh_DUPLICATEridge) {
        SETelem_(facet->neighbors, skip)= qh_DUPLICATEridge;
        facet->dupridge= True;
        if (matchfacet) {
          matchskip= qh_setindex(matchfacet->neighbors, facet);
          if (matchskip<0) {
              qh_fprintf(qh ferr, 6260, "qhull topology error (qh_matchneighbor): matchfacet f%d is in f%d neighbors but not vice versa.  Can not continue.\n",
                  matchfacet->id, facet->id);
              qh_errexit2(qh_ERRtopology, matchfacet, facet);
          }
          SETelem_(matchfacet->neighbors, matchskip)= qh_DUPLICATEridge; /* matchskip>=0 by QH6260 */
          matchfacet->dupridge= True;
          qh_addhash(matchfacet, qh hash_table, hashsize, hash);
          *hashcount += 2;
        }
      }
      trace4((qh ferr, 4052, "qh_matchneighbor: new f%d skip %d duplicates ridge for f%d skip %d matching f%d ismatch %d at hash %d\n",
           newfacet->id, newskip, facet->id, skip,
           (matchfacet == qh_DUPLICATEridge ? -2 : getid_(matchfacet)),
           ismatch, hash));
      return; /* end of duplicate ridge */
    }
  }
  if (!newfound)
    SETelem_(qh hash_table, scan)= newfacet;  /* same as qh_addhash */
  (*hashcount)++;
  trace4((qh ferr, 4053, "qh_matchneighbor: no match for f%d skip %d at hash %d\n",
           newfacet->id, newskip, hash));
} /* matchneighbor */


/*---------------------------------

  qh_matchnewfacets( )
    match new facets in qh.newfacet_list to their newfacet neighbors
    all facets are simplicial

  returns:
    if dupridges and merging 
      returns maxdupdist (>=0.0) from vertex to opposite facet
      sets facet->dupridge
      missing neighbor links identify dupridges to be merged (qh_DUPLICATEridge)
    else  
      qh.newfacet_list with full neighbor sets
        vertices for the nth neighbor match all but the nth vertex
    if not merging and qh.FORCEoutput
      for facets with normals (i.e., with dupridges)
      sets facet->flippped for flipped normals, also prevents point partitioning

  notes:
    called by qh_buildcone* and qh_triangulate_facet
    neighbor[0] of new facets is the horizon facet
    if NEWtentative, new facets not attached to the horizon
    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:
    truncate neighbor sets to horizon facet 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
        try to match facets with the same coplanar horizon
    if not all matched
      for each new facet with a duplicate ridge
        match it with a coplanar facet, or identify a pinched vertex
    if not merging and qh.FORCEoutput
      check for flipped facets
*/
coordT qh_matchnewfacets(void /* qh.newfacet_list */) {
  int numnew=0, hashcount=0, newskip;
  facetT *newfacet, *neighbor;
  coordT maxdupdist= 0.0, maxdist2;
  int dim= qh hull_dim, hashsize, neighbor_i, neighbor_n;
  setT *neighbors;
#ifndef qh_NOtrace
  int facet_i, facet_n, numunused= 0;
  facetT *facet;
#endif

  trace1((qh ferr, 1019, "qh_matchnewfacets: match neighbors for new facets.\n"));
  FORALLnew_facets {
    numnew++;
    {  /* inline qh_setzero(newfacet->neighbors, 1, qh hull_dim); */
      neighbors= newfacet->neighbors;
      neighbors->e[neighbors->maxsize].i= dim+1; /*may be overwritten*/
      memset((char *)SETelemaddr_(neighbors, 1, void), 0, (size_t)(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 {
    if (!newfacet->simplicial) {
      qh_fprintf(qh ferr, 6377, "qhull internal error (qh_matchnewfacets): expecting simplicial facets on qh.newfacet_list f%d for qh_matchneighbors, qh_matchneighbor, and qh_matchdupridge.  Got non-simplicial f%d\n",
        qh newfacet_list->id, newfacet->id);
      qh_errexit2(qh_ERRqhull, newfacet, qh newfacet_list);
    }
    for (newskip=1; newskip0 because hull_dim>1 and numnew>0 */
      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) {
        qh_fprintf(qh ferr, 6266, "qhull error (qh_matchnewfacets): after adding facet %d, hashcount %d != count %d\n",
                 newfacet->id, hashcount, count);
        qh_errexit(qh_ERRdebug, newfacet, NULL);
      }
    }
#endif  /* end of trap code */
  } /* end FORALLnew_facets */
  if (hashcount) { /* all neighbors matched, except for qh_DUPLICATEridge neighbors */
    qh_joggle_restart("ridge with multiple neighbors");
    if (hashcount) {
      FORALLnew_facets {
        if (newfacet->dupridge) {
          FOREACHneighbor_i_(newfacet) {
            if (neighbor == qh_DUPLICATEridge) {
              maxdist2= qh_matchdupridge(newfacet, neighbor_i, hashsize, &hashcount);
              maximize_(maxdupdist, maxdist2);
            }
          }
        }
      }
    }
  }
  if (hashcount) {
    qh_fprintf(qh ferr, 6108, "qhull internal error (qh_matchnewfacets): %d neighbors did not match up\n",
        hashcount);
    qh_printhashtable(qh ferr);
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
#ifndef qh_NOtrace
  if (qh IStracing >= 3) {
    FOREACHfacet_i_(qh hash_table) {
      if (!facet)
        numunused++;
    }
    qh_fprintf(qh ferr, 3063, "qh_matchnewfacets: maxdupdist %2.2g, new facets %d, unused hash entries %d, hashsize %d\n",
             maxdupdist, numnew, numunused, 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);
  }
  return maxdupdist;
} /* matchnewfacets */


/*---------------------------------

  qh_matchvertices( firstindex, verticesA, skipA, verticesB, skipB, same )
    tests whether vertices match with a single skip
    starts match at firstindex since all new facets have a common vertex

  returns:
    true if matched vertices
    skip index for skipB
    sets same iff vertices have the same orientation

  notes:
    called by qh_matchneighbor and qh_matchdupridge
    assumes skipA is in A and both sets are the same size

  design:
    set up pointers
    scan both sets checking for a match
    test orientation
*/
boolT qh_matchvertices(int firstindex, setT *verticesA, int skipA,
       setT *verticesB, int *skipB, boolT *same) {
  vertexT **elemAp, **elemBp, **skipBp=NULL, **skipAp;

  elemAp= SETelemaddr_(verticesA, firstindex, vertexT);
  elemBp= SETelemaddr_(verticesB, firstindex, vertexT);
  skipAp= SETelemaddr_(verticesA, skipA, vertexT);
  do if (elemAp != skipAp) {
    while (*elemAp != *elemBp++) {
      if (skipBp)
        return False;
      skipBp= elemBp;  /* one extra like FOREACH */
    }
  }while (*(++elemAp));
  if (!skipBp)
    skipBp= ++elemBp;
  *skipB= SETindex_(verticesB, skipB); /* i.e., skipBp - verticesB
                                       verticesA and verticesB are the same size, otherwise trace4 may segfault */
  *same= !((skipA & 0x1) ^ (*skipB & 0x1)); /* result is 0 or 1 */
  trace4((qh ferr, 4054, "qh_matchvertices: matched by skip %d(v%d) and skip %d(v%d) same? %d\n",
          skipA, (*skipAp)->id, *skipB, (*(skipBp-1))->id, *same));
  return(True);
} /* matchvertices */

/*---------------------------------

  qh_newfacet( )
    return a new facet

  returns:
    all fields initialized or cleared   (NULL)
    preallocates neighbors set
*/
facetT *qh_newfacet(void) {
  facetT *facet;
  void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */

  qh_memalloc_((int)sizeof(facetT), freelistp, facet, facetT);
  memset((char *)facet, (size_t)0, sizeof(facetT));
  if (qh facet_id == qh tracefacet_id)
    qh tracefacet= facet;
  facet->id= qh facet_id++;
  facet->neighbors= qh_setnew(qh hull_dim);
#if !qh_COMPUTEfurthest
  facet->furthestdist= 0.0;
#endif
#if qh_MAXoutside
  if (qh FORCEoutput && qh APPROXhull)
    facet->maxoutside= qh MINoutside;
  else
    facet->maxoutside= qh DISTround; /* same value as test for QH7082 */
#endif
  facet->simplicial= True;
  facet->good= True;
  facet->newfacet= True;
  trace4((qh ferr, 4055, "qh_newfacet: created facet f%d\n", facet->id));
  return(facet);
} /* newfacet */


/*---------------------------------

  qh_newridge()
    return a new ridge
  notes:
    caller sets qh.traceridge
*/
ridgeT *qh_newridge(void) {
  ridgeT *ridge;
  void **freelistp;   /* used if !qh_NOmem by qh_memalloc_() */

  qh_memalloc_((int)sizeof(ridgeT), freelistp, ridge, ridgeT);
  memset((char *)ridge, (size_t)0, sizeof(ridgeT));
  zinc_(Ztotridges);
  if (qh ridge_id == UINT_MAX) {
    qh_fprintf(qh ferr, 7074, "qhull warning: more than 2^32 ridges.  Qhull results are OK.  Since the ridge ID wraps around to 0, two ridges may have the same identifier.\n");
  }
  ridge->id= qh ridge_id++;
  trace4((qh ferr, 4056, "qh_newridge: created ridge r%d\n", ridge->id));
  return(ridge);
} /* newridge */


/*---------------------------------

  qh_pointid( point )
    return id for a point,
    returns qh_IDnone(-3) if null, qh_IDinterior(-2) if interior, or qh_IDunknown(-1) if not known

  alternative code if point is in qh.first_point...
    unsigned long id;
    id= ((unsigned long)point - (unsigned long)qh.first_point)/qh.normal_size;

  notes:
    Valid points are non-negative
    WARN64 -- id truncated to 32-bits, at most 2G points
    NOerrors returned (QhullPoint::id)
    if point not in point array
      the code does a comparison of unrelated pointers.
*/
int qh_pointid(pointT *point) {
  ptr_intT offset, id;

  if (!point)
    return qh_IDnone;
  else if (point == qh interior_point)
    return qh_IDinterior;
  else if (point >= qh first_point
  && point < qh first_point + qh num_points * qh hull_dim) {
    offset= (ptr_intT)(point - qh first_point);
    id= offset / qh hull_dim;
  }else if ((id= qh_setindex(qh other_points, point)) != -1)
    id += qh num_points;
  else
    return qh_IDunknown;
  return (int)id;
} /* pointid */

/*---------------------------------

  qh_removefacet( facet )
    unlinks facet from qh.facet_list,

  returns:
    updates qh.facet_list .newfacet_list .facet_next visible_list
    decrements qh.num_facets

  see:
    qh_appendfacet
*/
void qh_removefacet(facetT *facet) {
  facetT *next= facet->next, *previous= facet->previous; /* next is always defined */

  if (facet == qh newfacet_list)
    qh newfacet_list= next;
  if (facet == qh facet_next)
    qh facet_next= next;
  if (facet == qh visible_list)
    qh visible_list= next;
  if (previous) {
    previous->next= next;
    next->previous= previous;
  }else {  /* 1st facet in qh facet_list */
    qh facet_list= next;
    qh facet_list->previous= NULL;
  }
  qh num_facets--;
  trace4((qh ferr, 4057, "qh_removefacet: removed f%d from facet_list, newfacet_list, and visible_list\n", facet->id));
} /* removefacet */


/*---------------------------------

  qh_removevertex( vertex )
    unlinks vertex from qh.vertex_list,

  returns:
    updates qh.vertex_list .newvertex_list
    decrements qh.num_vertices
*/
void qh_removevertex(vertexT *vertex) {
  vertexT *next= vertex->next, *previous= vertex->previous; /* next is always defined */

  trace4((qh ferr, 4058, "qh_removevertex: remove v%d from qh.vertex_list\n", vertex->id));
  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= next;
    qh vertex_list->previous= NULL;
  }
  qh num_vertices--;
} /* removevertex */


/*---------------------------------

  qh_update_vertexneighbors( )
    update vertex neighbors and delete interior vertices

  returns:
    if qh.VERTEXneighbors, 
      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 as coplanar points
    if not qh.VERTEXneighbors (not merging)
      interior vertices of visible facets added to qh.del_vertices for later partitioning as coplanar points
  
  notes
    [jan'19] split off qh_update_vertexneighbors_cone.  Optimize the remaining cases in a future release
    called by qh_triangulate_facet after triangulating a non-simplicial facet, followed by reset_lists
    called by qh_triangulate after triangulating null and mirror facets
    called by qh_all_vertexmerges after calling qh_merge_pinchedvertices

  design:
    if qh.VERTEXneighbors
      for each vertex on newvertex_list (i.e., new vertices and vertices of new facets)
        delete visible facets from vertex neighbors
      for each new facet on newfacet_list
        for each vertex of facet
          append facet to vertex neighbors
      for each visible facet on qh.visible_list
        for each vertex of facet
          if the vertex is not on a new facet and not itself deleted
            if the vertex has a not-visible neighbor (due to merging)
               remove the visible facet from the vertex's neighbors
            otherwise
               add the vertex to qh.del_vertices for later deletion

    if not qh.VERTEXneighbors (not merging)
      for each vertex of a visible facet
        if the vertex is not on a new facet and not itself deleted
           add the vertex to qh.del_vertices for later deletion
*/
void qh_update_vertexneighbors(void /* qh.newvertex_list, newfacet_list, visible_list */) {
  facetT *newfacet= NULL, *neighbor, **neighborp, *visible;
  vertexT *vertex, **vertexp;
  int neighborcount= 0;

  if (qh VERTEXneighbors) {
    trace3((qh ferr, 3013, "qh_update_vertexneighbors: update v.neighbors for qh.newvertex_list (v%d) and qh.newfacet_list (f%d)\n",
         getid_(qh newvertex_list), getid_(qh newfacet_list)));
    FORALLvertex_(qh newvertex_list) {
      neighborcount= 0;
      FOREACHneighbor_(vertex) {
        if (neighbor->visible) {
          neighborcount++;
          SETref_(neighbor)= NULL;
        }
      }
      if (neighborcount) {
        trace4((qh ferr, 4046, "qh_update_vertexneighbors: delete %d of %d vertex neighbors for v%d.  Removes to-be-deleted, visible facets\n",
          neighborcount, qh_setsize(vertex->neighbors), vertex->id));
        qh_setcompact(vertex->neighbors);
      }
    }
    FORALLnew_facets {
      if (qh first_newfacet && newfacet->id >= qh first_newfacet) {
        FOREACHvertex_(newfacet->vertices)
          qh_setappend(&vertex->neighbors, newfacet);
      }else {  /* called after qh_merge_pinchedvertices.  In 7-D, many more neighbors than new facets.  qh_setin is expensive */
        FOREACHvertex_(newfacet->vertices)
          qh_setunique(&vertex->neighbors, newfacet); 
      }
    }
    trace3((qh ferr, 3058, "qh_update_vertexneighbors: delete interior vertices for qh.visible_list (f%d)\n",
        getid_(qh visible_list)));
    FORALLvisible_facets {
      FOREACHvertex_(visible->vertices) {
        if (!vertex->newfacet && !vertex->deleted) {
          FOREACHneighbor_(vertex) { /* this can happen under merging */
            if (!neighbor->visible)
              break;
          }
          if (neighbor)
            qh_setdel(vertex->neighbors, visible);
          else {
            vertex->deleted= True;
            qh_setappend(&qh del_vertices, vertex);
            trace2((qh ferr, 2041, "qh_update_vertexneighbors: delete interior vertex p%d(v%d) of visible f%d\n",
                  qh_pointid(vertex->point), vertex->id, visible->id));
          }
        }
      }
    }
  }else {  /* !VERTEXneighbors */
    trace3((qh ferr, 3058, "qh_update_vertexneighbors: delete old vertices for qh.visible_list (f%d)\n",
      getid_(qh visible_list)));
    FORALLvisible_facets {
      FOREACHvertex_(visible->vertices) {
        if (!vertex->newfacet && !vertex->deleted) {
          vertex->deleted= True;
          qh_setappend(&qh del_vertices, vertex);
          trace2((qh ferr, 2042, "qh_update_vertexneighbors: will delete interior vertex p%d(v%d) of visible f%d\n",
                  qh_pointid(vertex->point), vertex->id, visible->id));
        }
      }
    }
  }
} /* update_vertexneighbors */

/*---------------------------------

  qh_update_vertexneighbors_cone( )
    update vertex neighbors for a cone of new facets and delete interior vertices

  returns:
    if qh.VERTEXneighbors, 
      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 as coplanar points
    if not qh.VERTEXneighbors (not merging)
      interior vertices of visible facets added to qh.del_vertices for later partitioning as coplanar points
  
  notes
    called by qh_addpoint after create cone and before premerge

  design:
    if qh.VERTEXneighbors
      for each vertex on newvertex_list (i.e., new vertices and vertices of new facets)
        delete visible facets from vertex neighbors
      for each new facet on newfacet_list
        for each vertex of facet
          append facet to vertex neighbors
      for each visible facet on qh.visible_list
        for each vertex of facet
          if the vertex is not on a new facet and not itself deleted
            if the vertex has a not-visible neighbor (due to merging)
               remove the visible facet from the vertex's neighbors
            otherwise
               add the vertex to qh.del_vertices for later deletion

    if not qh.VERTEXneighbors (not merging)
      for each vertex of a visible facet
        if the vertex is not on a new facet and not itself deleted
           add the vertex to qh.del_vertices for later deletion

*/
void qh_update_vertexneighbors_cone(void /* qh.newvertex_list, newfacet_list, visible_list */) {
  facetT *newfacet= NULL, *neighbor, **neighborp, *visible;
  vertexT *vertex, **vertexp;
  int delcount= 0;

  if (qh VERTEXneighbors) {
    trace3((qh ferr, 3059, "qh_update_vertexneighbors_cone: update v.neighbors for qh.newvertex_list (v%d) and qh.newfacet_list (f%d)\n",
         getid_(qh newvertex_list), getid_(qh newfacet_list)));
    FORALLvertex_(qh newvertex_list) {
      delcount= 0;
      FOREACHneighbor_(vertex) {
        if (neighbor->visible) { /* alternative design is a loop over visible facets, but needs qh_setdel() */
          delcount++;
          qh_setdelnth(vertex->neighbors, SETindex_(vertex->neighbors, neighbor));
          neighborp--; /* repeat */
        }
      }
      if (delcount) {
        trace4((qh ferr, 4021, "qh_update_vertexneighbors_cone: deleted %d visible vertexneighbors of v%d\n",
          delcount, vertex->id));
      }
    }
    FORALLnew_facets {
      FOREACHvertex_(newfacet->vertices)
        qh_setappend(&vertex->neighbors, newfacet);
    }
    trace3((qh ferr, 3065, "qh_update_vertexneighbors_cone: delete interior vertices, if any, for qh.visible_list (f%d)\n",
        getid_(qh visible_list)));
    FORALLvisible_facets {
      FOREACHvertex_(visible->vertices) {
        if (!vertex->newfacet && !vertex->deleted) {
          FOREACHneighbor_(vertex) { /* this can happen under merging, qh_checkfacet QH4025 */
            if (!neighbor->visible)
              break;
          }
          if (neighbor)
            qh_setdel(vertex->neighbors, visible);
          else {
            vertex->deleted= True;
            qh_setappend(&qh del_vertices, vertex);
            trace2((qh ferr, 2102, "qh_update_vertexneighbors_cone: will delete interior vertex p%d(v%d) of visible f%d\n",
              qh_pointid(vertex->point), vertex->id, visible->id));
          }
        }
      }
    }
  }else {  /* !VERTEXneighbors */
    trace3((qh ferr, 3066, "qh_update_vertexneighbors_cone: delete interior vertices for qh.visible_list (f%d)\n",
      getid_(qh visible_list)));
    FORALLvisible_facets {
      FOREACHvertex_(visible->vertices) {
        if (!vertex->newfacet && !vertex->deleted) {
          vertex->deleted= True;
          qh_setappend(&qh del_vertices, vertex);
          trace2((qh ferr, 2059, "qh_update_vertexneighbors_cone: will delete interior vertex p%d(v%d) of visible f%d\n",
                  qh_pointid(vertex->point), vertex->id, visible->id));
        }
      }
    }
  }
} /* update_vertexneighbors_cone */

qhull-2020.2/src/libqhull/poly.h0000644060175106010010000002652213665505223014743 0ustar  bbarber/*
  ---------------------------------

   poly.h
   header file for poly.c and poly2.c

   see qh-poly.htm, libqhull.h and poly.c

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull/poly.h#5 $$Change: 2963 $
   $DateTime: 2020/06/03 19:31:01 $$Author: bbarber $
*/

#ifndef qhDEFpoly
#define qhDEFpoly 1

#include "libqhull.h"

/*===============   constants ========================== */

/*----------------------------------

  qh_ALGORITHMfault
    use as argument to checkconvex() to report errors during buildhull
*/
#define qh_ALGORITHMfault 0

/*----------------------------------

  qh_DATAfault
    use as argument to checkconvex() to report errors during initialhull
*/
#define qh_DATAfault 1

/*----------------------------------

  qh_DUPLICATEridge
    special value for facet->neighbor to indicate a duplicate ridge

  notes:
    set by qh_matchneighbor for qh_matchdupridge
*/
#define qh_DUPLICATEridge (facetT *)1L

/*----------------------------------

  qh_MERGEridge       flag in facet
    special value for facet->neighbor to indicate a duplicate ridge that needs merging

  notes:
    set by qh_matchnewfacets..qh_matchdupridge from qh_DUPLICATEridge
    used by qh_mark_dupridges to set facet->mergeridge, facet->mergeridge2 from facet->dupridge
*/
#define qh_MERGEridge (facetT *)2L


/*============ -structures- ====================*/

/*=========== -macros- =========================*/

/*----------------------------------

  FORALLfacet_( facetlist ) { ... }
    assign 'facet' to each facet in facetlist

  notes:
    uses 'facetT *facet;'
    assumes last facet is a sentinel

  see:
    FORALLfacets
*/
#define FORALLfacet_( facetlist ) if (facetlist) for ( facet=(facetlist); facet && facet->next; facet= facet->next )

/*----------------------------------

  FORALLnew_facets { ... }
    assign 'newfacet' to each facet in qh.newfacet_list

  notes:
    uses 'facetT *newfacet;'
    at exit, newfacet==NULL
*/
#define FORALLnew_facets for ( newfacet=qh newfacet_list; newfacet && newfacet->next; newfacet=newfacet->next )

/*----------------------------------

  FORALLvertex_( vertexlist ) { ... }
    assign 'vertex' to each vertex in vertexlist

  notes:
    uses 'vertexT *vertex;'
    at exit, vertex==NULL
*/
#define FORALLvertex_( vertexlist ) for (vertex=( vertexlist );vertex && vertex->next;vertex= vertex->next )

/*----------------------------------

  FORALLvisible_facets { ... }
    assign 'visible' to each visible facet in qh.visible_list

  notes:
    uses 'vacetT *visible;'
    at exit, visible==NULL
*/
#define FORALLvisible_facets for (visible=qh visible_list; visible && visible->visible; visible= visible->next)

/*----------------------------------

  FORALLsame_( newfacet ) { ... }
    assign 'same' to each facet in newfacet->f.samecycle

  notes:
    uses 'facetT *same;'
    stops when it returns to newfacet
*/
#define FORALLsame_(newfacet) for (same= newfacet->f.samecycle; same != newfacet; same= same->f.samecycle)

/*----------------------------------

  FORALLsame_cycle_( newfacet ) { ... }
    assign 'same' to each facet in newfacet->f.samecycle

  notes:
    uses 'facetT *same;'
    at exit, same == NULL
*/
#define FORALLsame_cycle_(newfacet) \
     for (same= newfacet->f.samecycle; \
         same; same= (same == newfacet ?  NULL : same->f.samecycle))

/*----------------------------------

  FOREACHneighborA_( facet ) { ... }
    assign 'neighborA' to each neighbor in facet->neighbors

  FOREACHneighborA_( vertex ) { ... }
    assign 'neighborA' to each neighbor in vertex->neighbors

  declare:
    facetT *neighborA, **neighborAp;

  see:
    FOREACHsetelement_
*/
#define FOREACHneighborA_(facet)  FOREACHsetelement_(facetT, facet->neighbors, neighborA)

/*----------------------------------

  FOREACHvisible_( facets ) { ... }
    assign 'visible' to each facet in facets

  notes:
    uses 'facetT *facet, *facetp;'
    see FOREACHsetelement_
*/
#define FOREACHvisible_(facets) FOREACHsetelement_(facetT, facets, visible)

/*----------------------------------

  FOREACHnewfacet_( facets ) { ... }
    assign 'newfacet' to each facet in facets

  notes:
    uses 'facetT *newfacet, *newfacetp;'
    see FOREACHsetelement_
*/
#define FOREACHnewfacet_(facets) FOREACHsetelement_(facetT, facets, newfacet)

/*----------------------------------

  FOREACHvertexA_( vertices ) { ... }
    assign 'vertexA' to each vertex in vertices

  notes:
    uses 'vertexT *vertexA, *vertexAp;'
    see FOREACHsetelement_
*/
#define FOREACHvertexA_(vertices) FOREACHsetelement_(vertexT, vertices, vertexA)

/*----------------------------------

  FOREACHvertexreverse12_( vertices ) { ... }
    assign 'vertex' to each vertex in vertices
    reverse order of first two vertices

  notes:
    uses 'vertexT *vertex, *vertexp;'
    see FOREACHsetelement_
*/
#define FOREACHvertexreverse12_(vertices) FOREACHsetelementreverse12_(vertexT, vertices, vertex)


/*=============== prototypes poly.c in alphabetical order ================*/

void    qh_appendfacet(facetT *facet);
void    qh_appendvertex(vertexT *vertex);
void    qh_attachnewfacets(void /* qh.visible_list, qh.newfacet_list */);
boolT   qh_checkflipped(facetT *facet, realT *dist, boolT allerror);
void    qh_delfacet(facetT *facet);
void    qh_deletevisible(void /* qh.visible_list, qh.horizon_list */);
setT   *qh_facetintersect(facetT *facetA, facetT *facetB, int *skipAp,int *skipBp, int extra);
int     qh_gethash(int hashsize, setT *set, int size, int firstindex, void *skipelem);
facetT *qh_getreplacement(facetT *visible);
facetT *qh_makenewfacet(setT *vertices, boolT toporient, facetT *facet);
void    qh_makenewplanes(void /* qh.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);
coordT  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_update_vertexneighbors(void);
void    qh_update_vertexneighbors_cone(void);


/*========== -prototypes poly2.c in alphabetical order ===========*/

boolT   qh_addfacetvertex(facetT *facet, vertexT *newvertex);
void    qh_addhash(void *newelem, setT *hashtable, int hashsize, int hash);
void    qh_check_bestdist(void);
void    qh_check_maxout(void);
void    qh_check_output(void);
void    qh_check_point(pointT *point, facetT *facet, realT *maxoutside, realT *maxdist, facetT **errfacet1, facetT **errfacet2, int *errcount);
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);
boolT   qh_checklists(facetT *facetlist);
void    qh_checkpolygon(facetT *facetlist);
void    qh_checkvertex(vertexT *vertex, boolT allchecks, boolT *waserrorp);
void    qh_clearcenters(qh_CENTER type);
void    qh_createsimplex(setT *vertices);
void    qh_delridge(ridgeT *ridge);
void    qh_delvertex(vertexT *vertex);
setT   *qh_facet3vertex(facetT *facet);
facetT *qh_findbestfacet(pointT *point, boolT bestoutside,
           realT *bestdist, boolT *isoutside);
facetT *qh_findbestlower(facetT *upperfacet, pointT *point, realT *bestdistp, int *numpart);
facetT *qh_findfacet_all(pointT *point, boolT noupper, 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 /* qh.horizon_list, visible_list */);
coordT  qh_matchdupridge(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);
facetT *qh_nextfacet2d(facetT *facet, vertexT **nextvertexp);
ridgeT *qh_nextridge3d(ridgeT *atridge, facetT *facet, vertexT **vertexp);
vertexT *qh_opposite_vertex(facetT *facetA,  facetT *neighbor);
void    qh_outcoplanar(void /* qh.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_replacefacetvertex(facetT *facet, vertexT *oldvertex, vertexT *newvertex);
void    qh_resetlists(boolT stats, boolT resetVisible /* qh.newvertex_list qh.newfacet_list qh.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 */
qhull-2020.2/src/libqhull/poly2.c0000644060175106010010000045547213665473732015043 0ustar  bbarber/*
  ---------------------------------

   poly2.c
   implements polygons and simplicies

   see qh-poly.htm, poly.h and libqhull.h

   frequently used code is in poly.c

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull/poly2.c#16 $$Change: 2963 $
   $DateTime: 2020/06/03 19:31:01 $$Author: bbarber $
*/

#include "qhull_a.h"

/*======== functions in alphabetical order ==========*/

/*---------------------------------

  qh_addfacetvertex( facet, newvertex )
    add newvertex to facet.vertices if not already there
    vertices are inverse sorted by vertex->id

  returns:
    True if new vertex for facet

  notes:
    see qh_replacefacetvertex
*/
boolT qh_addfacetvertex(facetT *facet, vertexT *newvertex) {
  vertexT *vertex;
  int vertex_i= 0, vertex_n;
  boolT isnew= True;

  FOREACHvertex_i_(facet->vertices) {
    if (vertex->id < newvertex->id) {
      break;
    }else if (vertex->id == newvertex->id) {
      isnew= False;
      break;
    }
  }
  if (isnew)
    qh_setaddnth(&facet->vertices, vertex_i, newvertex);
  return isnew;
} /* addfacetvertex */

/*---------------------------------

  qh_addhash( newelem, hashtable, hashsize, hash )
    add newelem to linear hash table at hash if not already there
*/
void qh_addhash(void *newelem, setT *hashtable, int hashsize, int hash) {
  int scan;
  void *elem;

  for (scan= (int)hash; (elem= SETelem_(hashtable, scan));
       scan= (++scan >= hashsize ? 0 : scan)) {
    if (elem == newelem)
      break;
  }
  /* loop terminates because qh_HASHfactor >= 1.1 by qh_initbuffers */
  if (!elem)
    SETelem_(hashtable, scan)= newelem;
} /* addhash */

/*---------------------------------

  qh_check_bestdist( )
    check that all points are within max_outside of the nearest facet
    if qh.ONLYgood,
      ignores !good facets

  see:
    qh_check_maxout(), qh_outerinner()

  notes:
    only called from qh_check_points()
      seldom used since qh.MERGING is almost always set
    if notverified>0 at end of routine
      some points were well inside the hull.  If the hull contains
      a lens-shaped component, these points were not verified.  Use
      options 'Qi Tv' to verify all points.  (Exhaustive check also verifies)

  design:
    determine facet for each point (if any)
    for each point
      start with the assigned facet or with the first facet
      find the best facet for the point and check all coplanar facets
      error if point is outside of facet
*/
void qh_check_bestdist(void) {
  boolT waserror= False, unassigned;
  facetT *facet, *bestfacet, *errfacet1= NULL, *errfacet2= NULL;
  facetT *facetlist;
  realT dist, maxoutside, maxdist= -REALmax;
  pointT *point;
  int numpart= 0, facet_i, facet_n, notgood= 0, notverified= 0;
  setT *facets;

  trace1((qh ferr, 1020, "qh_check_bestdist: check points below nearest facet.  Facet_list f%d\n",
      qh facet_list->id));
  maxoutside= qh_maxouter();
  maxoutside += qh DISTround;
  /* one more qh.DISTround for check computation */
  trace1((qh ferr, 1021, "qh_check_bestdist: check that all points are within %2.2g of best facet\n", maxoutside));
  facets= qh_pointfacet(/* qh.facet_list */);
  if (!qh_QUICKhelp && qh PRINTprecision)
    qh_fprintf(qh ferr, 8091, "\n\
qhull output completed.  Verifying that %d points are\n\
below %2.2g of the nearest %sfacet.\n",
             qh_setsize(facets), maxoutside, (qh ONLYgood ?  "good " : ""));
  FOREACHfacet_i_(facets) {  /* for each point with facet assignment */
    if (facet)
      unassigned= False;
    else {
      unassigned= True;
      facet= qh facet_list;
    }
    point= qh_point(facet_i);
    if (point == qh GOODpointp)
      continue;
    qh_distplane(point, facet, &dist);
    numpart++;
    bestfacet= qh_findbesthorizon(!qh_IScheckmax, point, facet, qh_NOupper, &dist, &numpart);
    /* occurs after statistics reported */
    maximize_(maxdist, dist);
    if (dist > maxoutside) {
      if (qh ONLYgood && !bestfacet->good
      && !((bestfacet= qh_findgooddist(point, bestfacet, &dist, &facetlist))
      && dist > maxoutside))
        notgood++;
      else {
        waserror= True;
        qh_fprintf(qh ferr, 6109, "qhull precision error (qh_check_bestdist): point p%d is outside facet f%d, distance= %6.8g maxoutside= %6.8g\n",
                facet_i, bestfacet->id, dist, maxoutside);
        if (errfacet1 != bestfacet) {
          errfacet2= errfacet1;
          errfacet1= bestfacet;
        }
      }
    }else if (unassigned && dist < -qh MAXcoplanar)
      notverified++;
  }
  qh_settempfree(&facets);
  if (notverified && !qh DELAUNAY && !qh_QUICKhelp && qh PRINTprecision)
    qh_fprintf(qh ferr, 8092, "\n%d points were well inside the hull.  If the hull contains\n\
a lens-shaped component, these points were not verified.  Use\n\
options 'Qci Tv' to verify all points.\n", notverified);
  if (maxdist > qh outside_err) {
    qh_fprintf(qh ferr, 6110, "qhull precision error (qh_check_bestdist): a coplanar point is %6.2g from convex hull.  The maximum value is qh.outside_err (%6.2g)\n",
              maxdist, qh outside_err);
    qh_errexit2(qh_ERRprec, errfacet1, errfacet2);
  }else if (waserror && qh outside_err > REALmax/2)
    qh_errexit2(qh_ERRprec, errfacet1, errfacet2);
  /* else if waserror, the error was logged to qh.ferr but does not effect the output */
  trace0((qh ferr, 20, "qh_check_bestdist: max distance outside %2.2g\n", maxdist));
} /* check_bestdist */

#ifndef qh_NOmerge
/*---------------------------------

  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 qh.min_vertex instead of qh.MAXcoplanar
    may not need to check near-inside points because of qh.MAXcoplanar
      and qh.KEEPnearinside (before it was -qh.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
*/
void qh_check_maxout(void) {
  facetT *facet, *bestfacet, *neighbor, **neighborp, *facetlist, *maxbestfacet= NULL, *minfacet, *maxfacet, *maxpointfacet;
  realT dist, maxoutside, mindist, nearest;
  realT maxoutside_base, minvertex_base;
  pointT *point, *maxpoint= NULL;
  int numpart= 0, facet_i, facet_n, notgood= 0;
  setT *facets, *vertices;
  vertexT *vertex, *minvertex;

  trace1((qh ferr, 1022, "qh_check_maxout: check and update qh.min_vertex %2.2g and qh.max_outside %2.2g\n", qh min_vertex, qh max_outside));
  minvertex_base= fmin_(qh min_vertex, -(qh ONEmerge+qh DISTround));
  maxoutside= mindist= 0.0;
  minvertex= qh vertex_list;
  maxfacet= minfacet= maxpointfacet= qh facet_list;
  if (qh VERTEXneighbors
  && (qh PRINTsummary || qh KEEPinside || qh KEEPcoplanar
        || qh TRACElevel || qh PRINTstatistics || qh VERIFYoutput || qh CHECKfrequently
        || qh PRINTout[0] == qh_PRINTsummary || qh PRINTout[0] == qh_PRINTnone)) {
    trace1((qh ferr, 1023, "qh_check_maxout: determine actual 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);
        if (dist < mindist) {
          if (qh min_vertex/minvertex_base > qh_WIDEmaxoutside && (qh PRINTprecision || !qh ALLOWwide)) {
            nearest= qh_vertex_bestdist(neighbor->vertices);
            /* should be caught in qh_mergefacet */
            qh_fprintf(qh ferr, 7083, "Qhull precision warning: in post-processing (qh_check_maxout) p%d(v%d) is %2.2g below f%d nearest vertices %2.2g\n",
              qh_pointid(vertex->point), vertex->id, dist, neighbor->id, nearest);
          }
          mindist= dist;
          minvertex= vertex;
          minfacet= neighbor;
        }
#ifndef qh_NOtrace
        if (-dist > qh TRACEdist || dist > qh TRACEdist
        || neighbor == qh tracefacet || vertex == qh tracevertex) {
          nearest= qh_vertex_bestdist(neighbor->vertices);
          qh_fprintf(qh ferr, 8093, "qh_check_maxout: p%d(v%d) is %.2g from f%d nearest vertices %2.2g\n",
                    qh_pointid(vertex->point), vertex->id, dist, neighbor->id, nearest);
        }
#endif
      }
    }
    if (qh MERGING) {
      wmin_(Wminvertex, qh min_vertex);
    }
    qh min_vertex= mindist;
    qh_settempfree(&vertices);
  }
  trace1((qh ferr, 1055, "qh_check_maxout: determine actual maxoutside\n"));
  maxoutside_base= fmax_(qh max_outside, qh ONEmerge+qh DISTround);
  /* maxoutside_base is same as qh.MAXoutside without qh.MINoutside (qh_detmaxoutside) */
  facets= qh_pointfacet(/* qh.facet_list */);
  FOREACHfacet_i_(facets) {     /* for each point with facet assignment */
    if (facet) {
      point= qh_point(facet_i);
      if (point == qh GOODpointp)
        continue;
      zzinc_(Ztotcheck);
      qh_distplane(point, facet, &dist);
      numpart++;
      bestfacet= qh_findbesthorizon(qh_IScheckmax, point, facet, !qh_NOupper, &dist, &numpart);
      if (bestfacet && dist >= maxoutside) { 
        if (qh ONLYgood && !bestfacet->good
        && !((bestfacet= qh_findgooddist(point, bestfacet, &dist, &facetlist))
        && dist > maxoutside)) {       
          notgood++;
        }else if (dist/maxoutside_base > qh_WIDEmaxoutside && (qh PRINTprecision || !qh ALLOWwide)) {
          nearest= qh_vertex_bestdist(bestfacet->vertices);
          if (nearest < fmax_(qh ONEmerge, qh max_outside) * qh_RATIOcoplanaroutside * 2) {
            qh_fprintf(qh ferr, 7087, "Qhull precision warning: in post-processing (qh_check_maxout) p%d for f%d is %2.2g above twisted facet f%d nearest vertices %2.2g\n",
              qh_pointid(point), facet->id, dist, bestfacet->id, nearest);
          }else {
            qh_fprintf(qh ferr, 7088, "Qhull precision warning: in post-processing (qh_check_maxout) p%d for f%d is %2.2g above hidden facet f%d nearest vertices %2.2g\n",
              qh_pointid(point), facet->id, dist, bestfacet->id, nearest);
          }
          maxbestfacet= bestfacet;
        }
        maxoutside= dist;
        maxfacet= bestfacet;
        maxpoint= point;
        maxpointfacet= facet;
      }
      if (dist > qh TRACEdist || (bestfacet && bestfacet == qh tracefacet))
        qh_fprintf(qh ferr, 8094, "qh_check_maxout: p%d is %.2g above f%d\n",
              qh_pointid(point), dist, (bestfacet ? bestfacet->id : UINT_MAX));
    }
  }
  zzadd_(Zcheckpart, numpart);
  qh_settempfree(&facets);
  wval_(Wmaxout)= maxoutside - qh max_outside;
  wmax_(Wmaxoutside, qh max_outside);
  if (!qh APPROXhull && maxoutside > qh DISTround) { /* initial value for f.maxoutside */
    FORALLfacets {
      if (maxoutside < facet->maxoutside) {
        if (!qh KEEPcoplanar) {
          maxoutside= facet->maxoutside;
        }else if (maxoutside + qh DISTround < facet->maxoutside) { /* maxoutside is computed distance, e.g., rbox 100 s D3 t1547136913 | qhull R1e-3 Tcv Qc */
          qh_fprintf(qh ferr, 7082, "Qhull precision warning (qh_check_maxout): f%d.maxoutside (%4.4g) is greater than computed qh.max_outside (%2.2g) + qh.DISTround (%2.2g).  It should be less than or equal\n",
            facet->id, facet->maxoutside, maxoutside, qh DISTround); 
        }
      }
    }
  }
  qh max_outside= maxoutside; 
  qh_nearcoplanar(/* qh.facet_list */);
  qh maxoutdone= True;
  trace1((qh ferr, 1024, "qh_check_maxout:  p%d(v%d) is qh.min_vertex %2.2g below facet f%d.  Point p%d for f%d is qh.max_outside %2.2g above f%d.  %d points are outside of not-good facets\n", 
    qh_pointid(minvertex->point), minvertex->id, qh min_vertex, minfacet->id, qh_pointid(maxpoint), maxpointfacet->id, qh max_outside, maxfacet->id, notgood));
  if(!qh ALLOWwide) {
    if (maxoutside/maxoutside_base > qh_WIDEmaxoutside) {
      qh_fprintf(qh ferr, 6297, "Qhull precision error (qh_check_maxout): large increase in qh.max_outside during post-processing dist %2.2g (%.1fx).  See warning QH0032/QH0033.  Allow with 'Q12' (allow-wide) and 'Pp'\n",
        maxoutside, maxoutside/maxoutside_base);
      qh_errexit(qh_ERRwide, maxbestfacet, NULL);
    }else if (!qh APPROXhull && maxoutside_base > (qh ONEmerge * qh_WIDEmaxoutside2)) {
      if (maxoutside > (qh ONEmerge * qh_WIDEmaxoutside2)) {  /* wide facets may have been deleted */
        qh_fprintf(qh ferr, 6298, "Qhull precision error (qh_check_maxout): a facet merge, vertex merge, vertex, or coplanar point produced a wide facet %2.2g (%.1fx). Trace with option 'TWn' to identify the merge.   Allow with 'Q12' (allow-wide)\n",
          maxoutside_base, maxoutside_base/(qh ONEmerge + qh DISTround));
        qh_errexit(qh_ERRwide, maxbestfacet, NULL);
      }
    }else if (qh min_vertex/minvertex_base > qh_WIDEmaxoutside) {
      qh_fprintf(qh ferr, 6354, "Qhull precision error (qh_check_maxout): large increase in qh.min_vertex during post-processing dist %2.2g (%.1fx).  See warning QH7083.  Allow with 'Q12' (allow-wide) and 'Pp'\n",
        qh min_vertex, qh min_vertex/minvertex_base);
      qh_errexit(qh_ERRwide, minfacet, NULL);
    }else if (minvertex_base < -(qh ONEmerge * qh_WIDEmaxoutside2)) {
      if (qh min_vertex < -(qh ONEmerge * qh_WIDEmaxoutside2)) {  /* wide facets may have been deleted */
        qh_fprintf(qh ferr, 6380, "Qhull precision error (qh_check_maxout): a facet or vertex merge produced a wide facet: v%d below f%d distance %2.2g (%.1fx). Trace with option 'TWn' to identify the merge.  Allow with 'Q12' (allow-wide)\n",
          minvertex->id, minfacet->id, mindist, -qh min_vertex/(qh ONEmerge + qh DISTround));
        qh_errexit(qh_ERRwide, minfacet, NULL);
      }
    }
  }
} /* check_maxout */
#else /* qh_NOmerge */
void qh_check_maxout(void) {
}
#endif

/*---------------------------------

  qh_check_output( )
    performs the checks at the end of qhull algorithm
    Maybe called after Voronoi output.  If so, it recomputes centrums since they are Voronoi centers instead.
*/
void qh_check_output(void) {
  int i;

  if (qh STOPcone)
    return;
  if (qh VERIFYoutput || qh IStracing || qh CHECKfrequently) {
    qh_checkpolygon(qh facet_list);
    qh_checkflipped_all(qh facet_list);
    qh_checkconvex(qh facet_list, qh_ALGORITHMfault);
  }else if (!qh MERGING && qh_newstats(qhstat precision, &i)) {
    qh_checkflipped_all(qh facet_list);
    qh_checkconvex(qh facet_list, qh_ALGORITHMfault);
  }
} /* check_output */



/*---------------------------------

  qh_check_point( point, facet, maxoutside, maxdist, errfacet1, errfacet2, errcount )
    check that point is less than maxoutside from facet

  notes:
    only called from qh_checkpoints
    reports up to qh_MAXcheckpoint-1 errors per facet
*/
void qh_check_point(pointT *point, facetT *facet, realT *maxoutside, realT *maxdist, facetT **errfacet1, facetT **errfacet2, int *errcount) {
  realT dist, nearest;

  /* occurs after statistics reported */
  qh_distplane(point, facet, &dist);
  maximize_(*maxdist, dist);
  if (dist > *maxoutside) {
    (*errcount)++;
    if (*errfacet1 != facet) {
      *errfacet2= *errfacet1;
      *errfacet1= facet;
    }
    if (*errcount < qh_MAXcheckpoint) {
      nearest= qh_vertex_bestdist(facet->vertices);
      qh_fprintf(qh ferr, 6111, "qhull precision error: point p%d is outside facet f%d, distance= %6.8g maxoutside= %6.8g nearest vertices %2.2g\n",
                qh_pointid(point), facet->id, dist, *maxoutside, nearest);
    }
  }
} /* qh_check_point */


/*---------------------------------

  qh_check_points( )
    checks that all points are inside all facets

  notes:
    if many points and qh_check_maxout not called (i.e., !qh.MERGING),
       calls qh_findbesthorizon via qh_check_bestdist (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;
  int errcount;
  boolT testouter;

  maxoutside= qh_maxouter();
  maxoutside += qh DISTround;
  /* one more qh.DISTround for check computation */
  trace1((qh ferr, 1025, "qh_check_points: check all points below %2.2g of all facet planes\n",
          maxoutside));
  if (qh num_good)   /* miss counts other_points and !good facets */
     total= (float)qh num_good * (float)qh num_points;
  else
     total= (float)qh num_facets * (float)qh num_points;
  if (total >= qh_VERIFYdirect && !qh maxoutdone) {
    if (!qh_QUICKhelp && qh SKIPcheckmax && qh MERGING)
      qh_fprintf(qh ferr, 7075, "qhull input warning: merging without checking outer planes('Q5' or 'Po').  Verify may report that a point is outside of a facet.\n");
    qh_check_bestdist();
  }else {
    if (qh_MAXoutside && qh maxoutdone)
      testouter= True;
    else
      testouter= False;
    if (!qh_QUICKhelp) {
      if (qh MERGEexact)
        qh_fprintf(qh ferr, 7076, "qhull input warning: exact merge ('Qx').  Verify may report that a point is outside of a facet.  See qh-optq.htm#Qx\n");
      else if (qh SKIPcheckmax || qh NOnearinside)
        qh_fprintf(qh ferr, 7077, "qhull input warning: no outer plane check ('Q5') or no processing of near-inside points ('Q8').  Verify may report that a point is outside of a facet.\n");
    }
    if (qh PRINTprecision) {
      if (testouter)
        qh_fprintf(qh ferr, 8098, "\n\
Output completed.  Verifying that all points are below outer planes of\n\
all %sfacets.  Will make %2.0f distance computations.\n",
              (qh ONLYgood ?  "good " : ""), total);
      else
        qh_fprintf(qh ferr, 8099, "\n\
Output completed.  Verifying that all points are below %2.2g of\n\
all %sfacets.  Will make %2.0f distance computations.\n",
              maxoutside, (qh ONLYgood ?  "good " : ""), total);
    }
    FORALLfacets {
      if (!facet->good && qh ONLYgood)
        continue;
      if (facet->flipped)
        continue;
      if (!facet->normal) {
        qh_fprintf(qh ferr, 7061, "qhull warning (qh_check_points): missing normal for facet f%d\n", facet->id);
        if (!errfacet1)
          errfacet1= facet;
        continue;
      }
      if (testouter) {
#if qh_MAXoutside
        maxoutside= facet->maxoutside + 2 * qh DISTround;
        /* one DISTround to actual point and another to computed point */
#endif
      }
      errcount= 0;
      FORALLpoints {
        if (point != qh GOODpointp)
          qh_check_point(point, facet, &maxoutside, &maxdist, &errfacet1, &errfacet2, &errcount);
      }
      FOREACHpoint_(qh other_points) {
        if (point != qh GOODpointp)
          qh_check_point(point, facet, &maxoutside, &maxdist, &errfacet1, &errfacet2, &errcount);
      }
      if (errcount >= qh_MAXcheckpoint) {
        qh_fprintf(qh ferr, 6422, "qhull precision error (qh_check_points): %d additional points outside facet f%d, maxdist= %6.8g\n",
             errcount-qh_MAXcheckpoint+1, facet->id, maxdist);
      }
    }
    if (maxdist > qh outside_err) {
      qh_fprintf(qh ferr, 6112, "qhull precision error (qh_check_points): a coplanar point is %6.2g from convex hull.  The maximum value(qh.outside_err) is %6.2g\n",
                maxdist, qh outside_err );
      qh_errexit2(qh_ERRprec, errfacet1, errfacet2 );
    }else if (errfacet1 && qh outside_err > REALmax/2)
        qh_errexit2(qh_ERRprec, errfacet1, errfacet2 );
    /* else if errfacet1, the error was logged to qh.ferr but does not effect the output */
    trace0((qh ferr, 21, "qh_check_points: max distance outside %2.2g\n", maxdist));
  }
} /* check_points */


/*---------------------------------

  qh_checkconvex( facetlist, fault )
    check that each ridge in facetlist is convex
    fault = qh_DATAfault if reporting errors from qh_initialhull with qh.ZEROcentrum
          = qh_ALGORITHMfault otherwise

  returns:
    counts Zconcaveridges and Zcoplanarridges
    errors if !qh.FORCEoutput ('Fo') and concaveridge or if merging a coplanar ridge
    overwrites Voronoi centers if set by qh_setvoronoi_all/qh_ASvoronoi

  notes:
    called by qh_initial_hull, qh_check_output, qh_all_merges ('Tc'), qh_build_withrestart ('QJ')
    does not test f.tricoplanar facets (qh_triangulate)
    must be no stronger than qh_test_appendmerge
    if not merging,
      tests vertices for neighboring simplicial facets < -qh.DISTround
    else if ZEROcentrum and simplicial facet,
      tests vertices for neighboring simplicial facets < 0.0
      tests centrums of neighboring nonsimplicial facets < 0.0
    else if ZEROcentrum 
      tests centrums of neighboring facets < 0.0
    else 
      tests centrums of neighboring facets < -qh.DISTround ('En' 'Rn')
    Does not test against -qh.centrum_radius since repeated computations may have different round-off errors (e.g., 'Rn')

  design:
    for all facets
      report flipped facets
      if ZEROcentrum and simplicial neighbors
        test vertices against neighbor
      else
        test centrum against neighbor
*/
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, first_nonsimplicial= False, tested_simplicial, allsimplicial;
  int neighbor_i, neighbor_n;

  if (qh ZEROcentrum) {
    trace1((qh ferr, 1064, "qh_checkconvex: check that facets are not-flipped and for qh.ZEROcentrum that simplicial vertices are below their neighbor (dist<0.0)\n"));
    first_nonsimplicial= True;
  }else if (!qh MERGING) {
    trace1((qh ferr, 1026, "qh_checkconvex: check that facets are not-flipped and that simplicial vertices are convex by qh.DISTround ('En', 'Rn')\n"));
    first_nonsimplicial= True;
  }else
    trace1((qh ferr, 1062, "qh_checkconvex: check that facets are not-flipped and that their centrums are convex by qh.DISTround ('En', 'Rn') \n"));
  if (!qh RERUN) {
    zzval_(Zconcaveridges)= 0;
    zzval_(Zcoplanarridges)= 0;
  }
  FORALLfacet_(facetlist) {
    if (facet->flipped) {
      qh_joggle_restart("flipped facet"); /* also tested by qh_checkflipped */
      qh_fprintf(qh ferr, 6113, "qhull precision error: f%d is flipped (interior point is outside)\n",
               facet->id);
      errfacet1= facet;
      waserror= True;
      continue;
    }
    if (facet->tricoplanar)
      continue;
    if (qh MERGING && (!qh ZEROcentrum || !facet->simplicial)) {
      allsimplicial= False;
      tested_simplicial= False;
    }else {
      allsimplicial= True;
      tested_simplicial= True;
      FOREACHneighbor_i_(facet) {
        if (neighbor->tricoplanar)
          continue;
        if (!neighbor->simplicial) {
          allsimplicial= False;
          continue;
        }
        vertex= SETelemt_(facet->vertices, neighbor_i, vertexT);
        qh_distplane(vertex->point, neighbor, &dist);
        if (dist >= -qh DISTround) {
          if (fault == qh_DATAfault) {
            qh_joggle_restart("non-convex initial simplex");
            if (dist > qh DISTround)
              qh_fprintf(qh ferr, 6114, "qhull precision error: initial simplex is not convex, since p%d(v%d) is %6.4g above opposite f%d\n", 
                  qh_pointid(vertex->point), vertex->id, dist, neighbor->id);
            else
              qh_fprintf(qh ferr, 6379, "qhull precision error: initial simplex is not convex, since p%d(v%d) is within roundoff of opposite facet f%d (dist %6.4g)\n",
                  qh_pointid(vertex->point), vertex->id, neighbor->id, dist);
            qh_errexit(qh_ERRsingular, neighbor, NULL);
          }
          if (dist > qh DISTround) {
            zzinc_(Zconcaveridges);
            qh_joggle_restart("concave ridge");
            qh_fprintf(qh ferr, 6115, "qhull precision error: f%d is concave to f%d, since p%d(v%d) is %6.4g above f%d\n",
              facet->id, neighbor->id, qh_pointid(vertex->point), vertex->id, dist, neighbor->id);
            errfacet1= facet;
            errfacet2= neighbor;
            waserror= True;
          }else if (qh ZEROcentrum) {
            if (dist > 0.0) {     /* qh_checkzero checked convex (dist < (- 2*qh DISTround)), computation may differ e.g. 'Rn' */
              zzinc_(Zcoplanarridges);
              qh_joggle_restart("coplanar ridge");
              qh_fprintf(qh ferr, 6116, "qhull precision error: f%d is clearly not convex to f%d, since p%d(v%d) is %6.4g above or coplanar with f%d with qh.ZEROcentrum\n",
                facet->id, neighbor->id, qh_pointid(vertex->point), vertex->id, dist, neighbor->id);
              errfacet1= facet;
              errfacet2= neighbor;
              waserror= True;
            }
          }else {
            zzinc_(Zcoplanarridges);
            qh_joggle_restart("coplanar ridge");
            trace0((qh ferr, 22, "qhull precision error: f%d is coplanar to f%d, since p%d(v%d) is within %6.4g of f%d, during p%d\n",
              facet->id, neighbor->id, qh_pointid(vertex->point), vertex->id, dist, neighbor->id, qh furthest_id));
          }
        }
      }
    }
    if (!allsimplicial) {
      if (first_nonsimplicial) {
        trace1((qh ferr, 1063, "qh_checkconvex: starting with f%d, also check that centrums of non-simplicial ridges are below their neighbors (dist<0.0)\n",
             facet->id));
        first_nonsimplicial= False;
      }
      if (qh CENTERtype == qh_AScentrum) {
        if (!facet->center)
          facet->center= qh_getcentrum(facet);
        centrum= facet->center;
      }else {
        if (!centrum_warning && !facet->simplicial) {  /* recomputed centrum correct for simplicial facets */
           centrum_warning= True;
           qh_fprintf(qh ferr, 7062, "qhull warning: recomputing centrums for convexity test.  This may lead to false, precision errors.\n");
        }
        centrum= qh_getcentrum(facet);
        tempcentrum= True;
      }
      FOREACHneighbor_(facet) {
        if (neighbor->simplicial && tested_simplicial) /* tested above since f.simplicial */
          continue;
        if (neighbor->tricoplanar)
          continue;
        zzinc_(Zdistconvex);
        qh_distplane(centrum, neighbor, &dist);
        if (dist > qh DISTround) {
          zzinc_(Zconcaveridges);
          qh_joggle_restart("concave ridge");
          qh_fprintf(qh ferr, 6117, "qhull precision error: f%d is concave to f%d.  Centrum of f%d is %6.4g above f%d\n",
            facet->id, neighbor->id, facet->id, dist, neighbor->id);
          errfacet1= facet;
          errfacet2= neighbor;
          waserror= True;
        }else if (dist >= 0.0) {   /* if arithmetic always rounds the same,
                                     can test against centrum radius instead */
          zzinc_(Zcoplanarridges);
          qh_joggle_restart("coplanar ridge");
          qh_fprintf(qh ferr, 6118, "qhull precision error: f%d is coplanar or concave to f%d.  Centrum of f%d is %6.4g above f%d\n",
            facet->id, neighbor->id, facet->id, dist, neighbor->id);
          errfacet1= facet;
          errfacet2= neighbor;
          waserror= True;
        }
      }
      if (tempcentrum)
        qh_memfree(centrum, qh normal_size);
    }
  }
  if (waserror && !qh FORCEoutput)
    qh_errexit2(qh_ERRprec, errfacet1, errfacet2);
} /* checkconvex */


/*---------------------------------

  qh_checkfacet( facet, newmerge, waserror )
    checks for consistency errors in facet
    newmerge set if from merge.c

  returns:
    sets waserror if any error occurs

  checks:
    vertex ids are inverse sorted
    unless newmerge, at least hull_dim neighbors and vertices (exactly if simplicial)
    if non-simplicial, at least as many ridges as neighbors
    neighbors are not duplicated
    ridges are not duplicated
    in 3-d, ridges=verticies
    (qh.hull_dim-1) ridge vertices
    neighbors are reciprocated
    ridge neighbors are facet neighbors and a ridge for every neighbor
    simplicial neighbors match facetintersect
    vertex intersection matches vertices of common ridges
    vertex neighbors and facet vertices agree
    all ridges have distinct vertex sets

  notes:
    called by qh_tracemerge and qh_checkpolygon
    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 int previousid= INT_MAX;
  int numneighbors, numvertices, numridges=0, numRvertices=0;
  boolT waserror= False;
  int skipA, skipB, ridge_i, ridge_n, i, last_v= qh hull_dim-2;
  setT *intersection;

  trace4((qh ferr, 4088, "qh_checkfacet: check f%d newmerge? %d\n", facet->id, newmerge));
  if (facet->id >= qh facet_id) {
    qh_fprintf(qh ferr, 6414, "qhull internal error (qh_checkfacet): unknown facet id f%d >= qh.facet_id (%d)\n", facet->id, qh facet_id);
    waserror= True;
  }
  if (facet->visitid > qh visit_id) {
    qh_fprintf(qh ferr, 6415, "qhull internal error (qh_checkfacet): expecting f%d.visitid <= qh.visit_id (%d).  Got visitid %d\n", facet->id, qh visit_id, facet->visitid);
    waserror= True;
  }
  if (facet->visible && !qh NEWtentative) {
    qh_fprintf(qh ferr, 6119, "qhull internal error (qh_checkfacet): facet f%d is on qh.visible_list\n",
      facet->id);
    qh_errexit(qh_ERRqhull, facet, NULL);
  }
  if (facet->redundant && !facet->visible && qh_setsize(qh degen_mergeset)==0) {
    qh_fprintf(qh ferr, 6399, "qhull internal error (qh_checkfacet): redundant facet f%d not on qh.visible_list\n",
      facet->id);
    waserror= True;
  }
  if (facet->degenerate && !facet->visible && qh_setsize(qh degen_mergeset)==0) { 
    qh_fprintf(qh ferr, 6400, "qhull internal error (qh_checkfacet): degenerate facet f%d is not on qh.visible_list and qh.degen_mergeset is empty\n",
      facet->id);
    waserror= True;
  }
  if (!facet->normal) {
    qh_fprintf(qh ferr, 6120, "qhull internal error (qh_checkfacet): facet f%d does not have a normal\n",
      facet->id);
    waserror= True;
  }
  if (!facet->newfacet) {
    if (facet->dupridge) {
      qh_fprintf(qh ferr, 6349, "qhull internal error (qh_checkfacet): f%d is 'dupridge' but it is not a newfacet on qh.newfacet_list f%d\n",
        facet->id, getid_(qh newfacet_list));
      waserror= True;
    }
    if (facet->newmerge) {
      qh_fprintf(qh ferr, 6383, "qhull internal error (qh_checkfacet): f%d is 'newmerge' but it is not a newfacet on qh.newfacet_list f%d.  Missing call to qh_reducevertices\n",  
        facet->id, getid_(qh newfacet_list));
      waserror= True;
    }
  }
  qh_setcheck(facet->vertices, "vertices for f", facet->id);
  qh_setcheck(facet->ridges, "ridges for f", facet->id);
  qh_setcheck(facet->outsideset, "outsideset for f", facet->id);
  qh_setcheck(facet->coplanarset, "coplanarset for f", facet->id);
  qh_setcheck(facet->neighbors, "neighbors for f", facet->id);
  FOREACHvertex_(facet->vertices) {
    if (vertex->deleted) {
      qh_fprintf(qh ferr, 6121, "qhull internal error (qh_checkfacet): deleted vertex v%d in f%d\n", vertex->id, facet->id);
      qh_errprint("ERRONEOUS", NULL, NULL, NULL, vertex);
      waserror= True;
    }
    if (vertex->id >= previousid) {
      qh_fprintf(qh ferr, 6122, "qhull internal error (qh_checkfacet): vertices of f%d are not in descending id order at v%d\n", facet->id, vertex->id);
      waserror= True;
      break;
    }
    previousid= vertex->id;
  }
  numneighbors= qh_setsize(facet->neighbors);
  numvertices= qh_setsize(facet->vertices);
  numridges= qh_setsize(facet->ridges);
  if (facet->simplicial) {
    if (numvertices+numneighbors != 2*qh hull_dim
    && !facet->degenerate && !facet->redundant) {
      qh_fprintf(qh ferr, 6123, "qhull internal error (qh_checkfacet): for simplicial facet f%d, #vertices %d + #neighbors %d != 2*qh hull_dim\n",
                facet->id, numvertices, numneighbors);
      qh_setprint(qh ferr, "", facet->neighbors);
      waserror= True;
    }
  }else { /* non-simplicial */
    if (!newmerge
    &&(numvertices < qh hull_dim || numneighbors < qh hull_dim)
    && !facet->degenerate && !facet->redundant) {
      qh_fprintf(qh ferr, 6124, "qhull internal error (qh_checkfacet): for facet f%d, #vertices %d or #neighbors %d < qh hull_dim\n",
         facet->id, numvertices, numneighbors);
       waserror= True;
    }
    /* in 3-d, can get a vertex twice in an edge list, e.g., RBOX 1000 s W1e-13 t995849315 D2 | QHULL d Tc Tv TP624 TW1e-13 T4 */
    if (numridges < numneighbors
    ||(qh hull_dim == 3 && numvertices > numridges && !qh NEWfacets)
    ||(qh hull_dim == 2 && numridges + numvertices + numneighbors != 6)) {
      if (!facet->degenerate && !facet->redundant) {
        qh_fprintf(qh ferr, 6125, "qhull internal error (qh_checkfacet): for facet f%d, #ridges %d < #neighbors %d or(3-d) > #vertices %d or(2-d) not all 2\n",
            facet->id, numridges, numneighbors, numvertices);
        waserror= True;
      }
    }
  }
  FOREACHneighbor_(facet) {
    if (neighbor == qh_MERGEridge || neighbor == qh_DUPLICATEridge) {
      qh_fprintf(qh ferr, 6126, "qhull internal error (qh_checkfacet): facet f%d still has a MERGEridge or DUPLICATEridge neighbor\n", facet->id);
      qh_errexit(qh_ERRqhull, facet, NULL);
    }
    if (neighbor->visible) {
      qh_fprintf(qh ferr, 6401, "qhull internal error (qh_checkfacet): facet f%d has deleted neighbor f%d (qh.visible_list)\n",
        facet->id, neighbor->id);
      errother= neighbor;
      waserror= True;
    }
    neighbor->seen= True;
  }
  FOREACHneighbor_(facet) {
    if (!qh_setin(neighbor->neighbors, facet)) {
      qh_fprintf(qh ferr, 6127, "qhull internal error (qh_checkfacet): facet f%d has neighbor f%d, but f%d does not have neighbor f%d\n",
              facet->id, neighbor->id, neighbor->id, facet->id);
      errother= neighbor;
      waserror= True;
    }
    if (!neighbor->seen) {
      qh_fprintf(qh ferr, 6128, "qhull internal error (qh_checkfacet): facet f%d has a duplicate neighbor f%d\n",
              facet->id, neighbor->id);
      errother= neighbor;
      waserror= True;
    }
    neighbor->seen= False;
  }
  FOREACHridge_(facet->ridges) {
    qh_setcheck(ridge->vertices, "vertices for r", ridge->id);
    ridge->seen= False;
  }
  FOREACHridge_(facet->ridges) {
    if (ridge->seen) {
      qh_fprintf(qh ferr, 6129, "qhull internal error (qh_checkfacet): facet f%d has a duplicate ridge r%d\n",
              facet->id, ridge->id);
      errridge= ridge;
      waserror= True;
    }
    ridge->seen= True;
    numRvertices= qh_setsize(ridge->vertices);
    if (numRvertices != qh hull_dim - 1) {
      qh_fprintf(qh ferr, 6130, "qhull internal error (qh_checkfacet): ridge between f%d and f%d has %d vertices\n",
                ridge->top->id, ridge->bottom->id, numRvertices);
      errridge= ridge;
      waserror= True;
    }
    neighbor= otherfacet_(ridge, facet);
    neighbor->seen= True;
    if (!qh_setin(facet->neighbors, neighbor)) {
      qh_fprintf(qh ferr, 6131, "qhull internal error (qh_checkfacet): for facet f%d, neighbor f%d of ridge r%d not in facet\n",
           facet->id, neighbor->id, ridge->id);
      errridge= ridge;
      waserror= True;
    }
    if (!facet->newfacet && !neighbor->newfacet) {
      if ((!ridge->tested) | ridge->nonconvex | ridge->mergevertex) {
        qh_fprintf(qh ferr, 6384, "qhull internal error (qh_checkfacet): ridge r%d is nonconvex (%d), mergevertex (%d) or not tested (%d) for facet f%d, neighbor f%d\n",
          ridge->id, ridge->nonconvex, ridge->mergevertex, ridge->tested, facet->id, neighbor->id);
        errridge= ridge;
        waserror= True;
      }
    }
  }
  if (!facet->simplicial) {
    FOREACHneighbor_(facet) {
      if (!neighbor->seen) {
        qh_fprintf(qh ferr, 6132, "qhull internal error (qh_checkfacet): facet f%d does not have a ridge for neighbor f%d\n",
              facet->id, neighbor->id);
        errother= neighbor;
        waserror= True;
      }
      intersection= qh_vertexintersect_new(facet->vertices, neighbor->vertices);
      qh_settemppush(intersection);
      FOREACHvertex_(facet->vertices) {
        vertex->seen= False;
        vertex->seen2= False;
      }
      FOREACHvertex_(intersection)
        vertex->seen= True;
      FOREACHridge_(facet->ridges) {
        if (neighbor != otherfacet_(ridge, facet))
            continue;
        FOREACHvertex_(ridge->vertices) {
          if (!vertex->seen) {
            qh_fprintf(qh ferr, 6133, "qhull internal error (qh_checkfacet): vertex v%d in r%d not in f%d intersect f%d\n",
                  vertex->id, ridge->id, facet->id, neighbor->id);
            qh_errexit(qh_ERRqhull, facet, ridge);
          }
          vertex->seen2= True;
        }
      }
      if (!newmerge) {
        FOREACHvertex_(intersection) {
          if (!vertex->seen2) {
            if (!qh MERGING) {
              qh_fprintf(qh ferr, 6420, "qhull topology error (qh_checkfacet): vertex v%d in f%d intersect f%d but not in a ridge.  Last point was p%d\n",
                     vertex->id, facet->id, neighbor->id, qh furthest_id);
              if (!qh FORCEoutput) {
                qh_errprint("ERRONEOUS", facet, neighbor, NULL, vertex);
                qh_errexit(qh_ERRtopology, NULL, NULL);
              }
            }else {
              trace4((qh ferr, 4025, "qh_checkfacet: vertex v%d in f%d intersect f%d but not in a ridge.  Repaired by qh_remove_extravertices in qh_reducevertices\n",
                vertex->id, facet->id, neighbor->id));
            }
          }
        }
      }
      qh_settempfree(&intersection);
    }
  }else { /* simplicial */
    FOREACHneighbor_(facet) {
      if (neighbor->simplicial && !facet->degenerate && !neighbor->degenerate) {
        skipA= SETindex_(facet->neighbors, neighbor);
        skipB= qh_setindex(neighbor->neighbors, facet);
        if (skipA<0 || skipB<0 || !qh_setequal_skip(facet->vertices, skipA, neighbor->vertices, skipB)) {
          qh_fprintf(qh ferr, 6135, "qhull internal error (qh_checkfacet): facet f%d skip %d and neighbor f%d skip %d do not match \n",
                   facet->id, skipA, neighbor->id, skipB);
          errother= neighbor;
          waserror= True;
        }
      }
    }
  }
  if (!newmerge && qh CHECKduplicates && qh hull_dim < 5 && (qh IStracing > 2 || qh CHECKfrequently)) {
    FOREACHridge_i_(facet->ridges) {           /* expensive, if was merge and qh_maybe_duplicateridges hasn't been called yet */
      if (!ridge->mergevertex) {
        for (i=ridge_i+1; i < ridge_n; i++) {
          ridge2= SETelemt_(facet->ridges, i, ridgeT);
          if (SETelem_(ridge->vertices, last_v) == SETelem_(ridge2->vertices, last_v)) { /* SETfirst is likely to be the same */
            if (SETfirst_(ridge->vertices) == SETfirst_(ridge2->vertices)) {
              if (qh_setequal(ridge->vertices, ridge2->vertices)) {
                qh_fprintf(qh ferr, 6294, "qhull internal error (qh_checkfacet): ridges r%d and r%d (f%d) have the same vertices\n", /* same as duplicate ridge */
                    ridge->id, ridge2->id, facet->id);
                errridge= ridge;
                waserror= True;
              }
            }
          }
        }
      }
    }
  }
  if (waserror) {
    qh_errprint("ERRONEOUS", facet, errother, errridge, NULL);
    *waserrorp= True;
  }
} /* checkfacet */

/*---------------------------------

  qh_checkflipped_all( facetlist )
    checks orientation of facets in list against interior point

  notes:
    called by qh_checkoutput
*/
void qh_checkflipped_all(facetT *facetlist) {
  facetT *facet;
  boolT waserror= False;
  realT dist;

  if (facetlist == qh facet_list)
    zzval_(Zflippedfacets)= 0;
  FORALLfacet_(facetlist) {
    if (facet->normal && !qh_checkflipped(facet, &dist, !qh_ALL)) {
      qh_fprintf(qh ferr, 6136, "qhull precision error: facet f%d is flipped, distance= %6.12g\n",
              facet->id, dist);
      if (!qh FORCEoutput) {
        qh_errprint("ERRONEOUS", facet, NULL, NULL, NULL);
        waserror= True;
      }
    }
  }
  if (waserror) {
    qh_fprintf(qh ferr, 8101, "\n\
A flipped facet occurs when its distance to the interior point is\n\
greater than or equal to %2.2g, the maximum roundoff error.\n", -qh DISTround);
    qh_errexit(qh_ERRprec, NULL, NULL);
  }
} /* checkflipped_all */

/*---------------------------------

  qh_checklists( facetlist )
    Check and repair facetlist and qh.vertex_list for infinite loops or overwritten facets
    Checks that qh.newvertex_list is on qh.vertex_list
    if facetlist is qh.facet_list
      Checks that qh.visible_list and qh.newfacet_list are on qh.facet_list
    Updates qh.facetvisit and qh.vertexvisit

  returns:
    True if no errors found
    If false, repairs erroneous lists to prevent infinite loops by FORALL macros

  notes:
    called by qh_buildtracing, qh_checkpolygon, qh_collectstatistics, qh_printfacetlist, qh_printsummary
    not called by qh_printlists

  design:
    if facetlist
      check qh.facet_tail
      for each facet
        check for infinite loop or overwritten facet
        check previous facet
      if facetlist is qh.facet_list
        check qh.next_facet, qh.visible_list and qh.newfacet_list
    if vertexlist
      check qh.vertex_tail
      for each vertex
        check for infinite loop or overwritten vertex
        check previous vertex
      check qh.newvertex_list
*/
boolT qh_checklists(facetT *facetlist) {
  facetT *facet, *errorfacet= NULL, *errorfacet2= NULL, *previousfacet;
  vertexT *vertex, *vertexlist, *previousvertex, *errorvertex= NULL;
  boolT waserror= False, newseen= False, nextseen= False, newvertexseen= False, visibleseen= False;

  if (facetlist == qh newfacet_list || facetlist == qh visible_list) {
    vertexlist= qh vertex_list;
    previousvertex= NULL;
    trace2((qh ferr, 2110, "qh_checklists: check qh.%s_list f%d and qh.vertex_list v%d\n", 
        (facetlist == qh newfacet_list ? "newfacet" : "visible"), facetlist->id, getid_(vertexlist)));
  }else {
    vertexlist= qh vertex_list;
    previousvertex= NULL;
    trace2((qh ferr, 2111, "qh_checklists: check %slist f%d and qh.vertex_list v%d\n", 
        (facetlist == qh facet_list ? "qh.facet_" : "facet"), getid_(facetlist), getid_(vertexlist)));
  }
  if (facetlist) {
    if (qh facet_tail == NULL || qh facet_tail->id != 0 || qh facet_tail->next != NULL) {
      qh_fprintf(qh ferr, 6397, "qhull internal error (qh_checklists): either qh.facet_tail f%d is NULL, or its id is not 0, or its next is not NULL\n", 
          getid_(qh facet_tail));
      qh_errexit(qh_ERRqhull, qh facet_tail, NULL);
    }
    previousfacet= (facetlist == qh facet_list ? NULL : facetlist->previous);
    qh visit_id++;
    FORALLfacet_(facetlist) {
      if (facet->visitid >= qh visit_id || facet->id >= qh facet_id) {
        waserror= True;
        errorfacet= facet;
        errorfacet2= previousfacet;
        if (facet->visitid == qh visit_id)
          qh_fprintf(qh ferr, 6039, "qhull internal error (qh_checklists): f%d already in facetlist causing an infinite loop ... f%d > f%d ... > f%d > f%d.  Truncate facetlist at f%d\n", 
            facet->id, facet->id, facet->next->id, getid_(previousfacet), facet->id, getid_(previousfacet));
        else
          qh_fprintf(qh ferr, 6350, "qhull internal error (qh_checklists): unknown or overwritten facet f%d, either id >= qh.facet_id (%d) or f.visitid %u > qh.visit_id %u.  Facetlist terminated at previous facet f%d\n", 
              facet->id, qh facet_id, facet->visitid, qh visit_id, getid_(previousfacet));
        if (previousfacet)
          previousfacet->next= qh facet_tail;
        else
          facetlist= qh facet_tail;
        break;
      }
      facet->visitid= qh visit_id;
      if (facet->previous != previousfacet) {
        qh_fprintf(qh ferr, 6416, "qhull internal error (qh_checklists): expecting f%d.previous == f%d.  Got f%d\n",
          facet->id, getid_(previousfacet), getid_(facet->previous));
        waserror= True;
        errorfacet= facet;
        errorfacet2= facet->previous;
      }
      previousfacet= facet;
      if (facetlist == qh facet_list) {
        if (facet == qh visible_list) {
          if(newseen){
            qh_fprintf(qh ferr, 6285, "qhull internal error (qh_checklists): qh.visible_list f%d is after qh.newfacet_list f%d.  It should be at, before, or NULL\n",
              facet->id, getid_(qh newfacet_list));
            waserror= True;
            errorfacet= facet;
            errorfacet2= qh newfacet_list;
          }
          visibleseen= True;
        }
        if (facet == qh newfacet_list)
          newseen= True;
        if (facet == qh facet_next)
          nextseen= True;
      }
    }
    if (facetlist == qh facet_list) {
      if (!nextseen && qh facet_next && qh facet_next->next) {
        qh_fprintf(qh ferr, 6369, "qhull internal error (qh_checklists): qh.facet_next f%d for qh_addpoint is not on qh.facet_list f%d\n", 
          qh facet_next->id, facetlist->id);
        waserror= True;
        errorfacet= qh facet_next;
        errorfacet2= facetlist;
      }
      if (!newseen && qh newfacet_list && qh newfacet_list->next) {
        qh_fprintf(qh ferr, 6286, "qhull internal error (qh_checklists): qh.newfacet_list f%d is not on qh.facet_list f%d\n", 
          qh newfacet_list->id, facetlist->id);
        waserror= True;
        errorfacet= qh newfacet_list;
        errorfacet2= facetlist;
      }
      if (!visibleseen && qh visible_list && qh visible_list->next) {
        qh_fprintf(qh ferr, 6138, "qhull internal error (qh_checklists): qh.visible_list f%d is not on qh.facet_list f%d\n", 
          qh visible_list->id, facetlist->id);
        waserror= True;
        errorfacet= qh visible_list;
        errorfacet2= facetlist;
      }
    }
  }
  if (vertexlist) {
    if (qh vertex_tail == NULL || qh vertex_tail->id != 0 || qh vertex_tail->next != NULL) {
      qh_fprintf(qh ferr, 6366, "qhull internal error (qh_checklists): either qh.vertex_tail v%d is NULL, or its id is not 0, or its next is not NULL\n", 
           getid_(qh vertex_tail));
      qh_errprint("ERRONEOUS", errorfacet, errorfacet2, NULL, qh vertex_tail);
      qh_errexit(qh_ERRqhull, NULL, NULL);
    }
    qh vertex_visit++;
    FORALLvertex_(vertexlist) {
      if (vertex->visitid >= qh vertex_visit || vertex->id >= qh vertex_id) {
        waserror= True;
        errorvertex= vertex;
        if (vertex->visitid == qh visit_id)
          qh_fprintf(qh ferr, 6367, "qhull internal error (qh_checklists): v%d already in vertexlist causing an infinite loop ... v%d > v%d ... > v%d > v%d.  Truncate vertexlist at v%d\n", 
            vertex->id, vertex->id, vertex->next->id, getid_(previousvertex), vertex->id, getid_(previousvertex));
        else
          qh_fprintf(qh ferr, 6368, "qhull internal error (qh_checklists): unknown or overwritten vertex v%d, either id >= qh.vertex_id (%d) or v.visitid %u > qh.visit_id %u.  vertexlist terminated at previous vertex v%d\n", 
            vertex->id, qh vertex_id, vertex->visitid, qh visit_id, getid_(previousvertex));
        if (previousvertex)
          previousvertex->next= qh vertex_tail;
        else
          vertexlist= qh vertex_tail;
        break;
      }
      vertex->visitid= qh vertex_visit;
      if (vertex->previous != previousvertex) {
        qh_fprintf(qh ferr, 6427, "qhull internal error (qh_checklists): expecting v%d.previous == v%d.  Got v%d\n",
              vertex->id, previousvertex, getid_(vertex->previous));
        waserror= True;
        errorvertex= vertex;
      }
      previousvertex= vertex;
      if(vertex == qh newvertex_list)
        newvertexseen= True;
    }
    if(!newvertexseen && qh newvertex_list && qh newvertex_list->next) {
      qh_fprintf(qh ferr, 6287, "qhull internal error (qh_checklists): new vertex list v%d is not on vertex list\n", qh newvertex_list->id);
      waserror= True;
      errorvertex= qh newvertex_list;
    }
  }
  if (waserror) {
    qh_errprint("ERRONEOUS", errorfacet, errorfacet2, NULL, errorvertex);
    return False;
  }
  return True;
} /* checklists */

/*---------------------------------

  qh_checkpolygon( facetlist )
    checks the correctness of the structure

  notes:
    called by qh_addpoint, qh_all_vertexmerge, qh_check_output, qh_initialhull, qh_prepare_output, qh_triangulate
    call with qh.facet_list or qh.newfacet_list or another list
    checks num_facets and num_vertices if qh.facet_list

  design:
    check and repair lists for infinite loop
    for each facet
      check f.newfacet and f.visible
      check facet and outside set if qh.NEWtentative and not f.newfacet, or not f.visible
    initializes vertexlist for qh.facet_list or qh.newfacet_list
    for each vertex
      check vertex
      check v.newfacet
    for each facet
      count f.ridges
      check and count f.vertices
    if checking qh.facet_list
      check facet count
      if qh.VERTEXneighbors
        check and count v.neighbors for all vertices
        check v.neighbors count and report possible causes of mismatch
        check that facets are in their v.neighbors
      check vertex count
*/
void qh_checkpolygon(facetT *facetlist) {
  facetT *facet, *neighbor, **neighborp;
  facetT *errorfacet= NULL, *errorfacet2= NULL;
  vertexT *vertex, **vertexp, *vertexlist;
  int numfacets= 0, numvertices= 0, numridges= 0;
  int totvneighbors= 0, totfacetvertices= 0;
  boolT waserror= False, newseen= False, newvertexseen= False, nextseen= False, visibleseen= False;
  boolT checkfacet;

  trace1((qh ferr, 1027, "qh_checkpolygon: check all facets from f%d, qh.NEWtentative? %d\n", facetlist->id, qh NEWtentative));
  if (!qh_checklists(facetlist)) {
    waserror= True;
    qh_fprintf(qh ferr, 6374, "qhull internal error: qh_checklists failed in qh_checkpolygon\n");
    if (qh num_facets < 4000)
      qh_printlists();
  }
  if (facetlist != qh facet_list || qh ONLYgood)
    nextseen= True; /* allow f.outsideset */
  FORALLfacet_(facetlist) {
    if (facet == qh visible_list)
      visibleseen= True;
    if (facet == qh newfacet_list)
      newseen= True;
    if (facet->newfacet && !newseen && !visibleseen) {
        qh_fprintf(qh ferr, 6289, "qhull internal error (qh_checkpolygon): f%d is 'newfacet' but it is not on qh.newfacet_list f%d or visible_list f%d\n",  facet->id, getid_(qh newfacet_list), getid_(qh visible_list));
        qh_errexit(qh_ERRqhull, facet, NULL);
    }
    if (!facet->newfacet && newseen) {
        qh_fprintf(qh ferr, 6292, "qhull internal error (qh_checkpolygon): f%d is on qh.newfacet_list f%d but it is not 'newfacet'\n",  facet->id, getid_(qh newfacet_list));
        qh_errexit(qh_ERRqhull, facet, NULL);
    }
    if (facet->visible != (visibleseen & !newseen)) {
      if(facet->visible)
        qh_fprintf(qh ferr, 6290, "qhull internal error (qh_checkpolygon): f%d is 'visible' but it is not on qh.visible_list f%d\n", facet->id, getid_(qh visible_list));
      else
        qh_fprintf(qh ferr, 6291, "qhull internal error (qh_checkpolygon): f%d is on qh.visible_list f%d but it is not 'visible'\n", facet->id, qh newfacet_list->id);
      qh_errexit(qh_ERRqhull, facet, NULL);
    }
    if (qh NEWtentative) {
      checkfacet= !facet->newfacet;
    }else {
      checkfacet= !facet->visible;
    }
    if(checkfacet) {
      if (!nextseen) {
        if (facet == qh facet_next)  /* previous facets do not have outsideset */
          nextseen= True;
        else if (qh_setsize(facet->outsideset)) {
          if (!qh NARROWhull
#if !qh_COMPUTEfurthest
          || facet->furthestdist >= qh MINoutside
#endif
          ) {
            qh_fprintf(qh ferr, 6137, "qhull internal error (qh_checkpolygon): f%d has outside points before qh.facet_next f%d\n",
                     facet->id, getid_(qh facet_next));
            qh_errexit2(qh_ERRqhull, facet, qh facet_next);
          }
        }
      }
      numfacets++;
      qh_checkfacet(facet, False, &waserror);
    }else if (facet->visible && qh NEWfacets) {
      if (!SETempty_(facet->neighbors) || !SETempty_(facet->ridges)) {
        qh_fprintf(qh ferr, 6376, "qhull internal error (qh_checkpolygon): expecting empty f.neighbors and f.ridges for visible facet f%d.  Got %d neighbors and %d ridges\n", 
          facet->id, qh_setsize(facet->neighbors), qh_setsize(facet->ridges));
        qh_errexit(qh_ERRqhull, facet, 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) {
    qh_checkvertex(vertex, !qh_ALL, &waserror);
    if(vertex == qh newvertex_list)
      newvertexseen= True;
    vertex->seen= False;
    vertex->visitid= 0;
    if(vertex->newfacet && !newvertexseen && !vertex->deleted) {
      qh_fprintf(qh ferr, 6288, "qhull internal error (qh_checkpolygon): v%d is 'newfacet' but it is not on new vertex list v%d\n", vertex->id, getid_(qh newvertex_list));
      qh_errexit(qh_ERRqhull, qh visible_list, NULL);
    }
  }
  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) == qh_IDunknown) {
          qh_fprintf(qh ferr, 6139, "qhull internal error (qh_checkpolygon): unknown point %p for vertex v%d first_point %p\n",
                   vertex->point, vertex->id, qh first_point);
          waserror= True;
        }
      }
    }
  }
  qh vertex_visit += (unsigned int)numfacets;
  if (facetlist == qh facet_list) {
    if (numfacets != qh num_facets - qh num_visible) {
      qh_fprintf(qh ferr, 6140, "qhull internal error (qh_checkpolygon): actual number of facets is %d, cumulative facet count is %d - %d visible facets\n",
              numfacets, qh num_facets, qh num_visible);
      waserror= True;
    }
    qh vertex_visit++;
    if (qh VERTEXneighbors) {
      FORALLvertices {
        if (!vertex->neighbors) {
          qh_fprintf(qh ferr, 6407, "qhull internal error (qh_checkpolygon): missing vertex neighbors for v%d\n", vertex->id);
          waserror= True;
        }
        qh_setcheck(vertex->neighbors, "neighbors for v", vertex->id);
        if (vertex->deleted)
          continue;
        totvneighbors += qh_setsize(vertex->neighbors);
      }
      FORALLfacet_(facetlist) {
        if (!facet->visible)
          totfacetvertices += qh_setsize(facet->vertices);
      }
      if (totvneighbors != totfacetvertices) {
        qh_fprintf(qh ferr, 6141, "qhull internal error (qh_checkpolygon): vertex neighbors inconsistent (tot_vneighbors %d != tot_facetvertices %d).  Maybe duplicate or missing vertex\n",
                totvneighbors, totfacetvertices);
        waserror= True;
        FORALLvertices {
          if (vertex->deleted)
            continue;
          qh visit_id++;
          FOREACHneighbor_(vertex) {
            if (neighbor->visitid==qh visit_id) {
              qh_fprintf(qh ferr, 6275, "qhull internal error (qh_checkpolygon): facet f%d occurs twice in neighbors of vertex v%d\n",
                  neighbor->id, vertex->id);
              errorfacet2= errorfacet;
              errorfacet= neighbor;
            }
            neighbor->visitid= qh visit_id;
            if (!qh_setin(neighbor->vertices, vertex)) {
              qh_fprintf(qh ferr, 6276, "qhull internal error (qh_checkpolygon): facet f%d is a neighbor of vertex v%d but v%d is not a vertex of f%d\n",
                  neighbor->id, vertex->id, vertex->id, neighbor->id);
              errorfacet2= errorfacet;
              errorfacet= neighbor;
            }
          }
        }
        FORALLfacet_(facetlist){
          if (!facet->visible) {
            /* vertices are inverse sorted and are unlikely to be duplicated */
            FOREACHvertex_(facet->vertices){
              if (!qh_setin(vertex->neighbors, facet)) {
                qh_fprintf(qh ferr, 6277, "qhull internal error (qh_checkpolygon): v%d is a vertex of facet f%d but f%d is not a neighbor of v%d\n",
                  vertex->id, facet->id, facet->id, vertex->id);
                errorfacet2= errorfacet;
                errorfacet= facet;
              }
            }
          }
        }
      }
    }
    if (numvertices != qh num_vertices - qh_setsize(qh del_vertices)) {
      qh_fprintf(qh ferr, 6142, "qhull internal error (qh_checkpolygon): actual number of vertices is %d, cumulative vertex count is %d\n",
              numvertices, qh num_vertices - qh_setsize(qh del_vertices));
      waserror= True;
    }
    if (qh hull_dim == 2 && numvertices != numfacets) {
      qh_fprintf(qh ferr, 6143, "qhull internal error (qh_checkpolygon): #vertices %d != #facets %d\n",
        numvertices, numfacets);
      waserror= True;
    }
    if (qh hull_dim == 3 && numvertices + numfacets - numridges/2 != 2) {
      qh_fprintf(qh ferr, 7063, "qhull warning: #vertices %d + #facets %d - #edges %d != 2.  A vertex appears twice in a edge list.  May occur during merging.\n",
          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_errexit2(qh_ERRqhull, errorfacet, errorfacet2);
} /* checkpolygon */


/*---------------------------------

  qh_checkvertex( vertex, allchecks, &waserror )
    check vertex for consistency
    if allchecks, checks vertex->neighbors

  returns:
    sets waserror if any error occurs

  notes:
    called by qh_tracemerge and qh_checkpolygon
    neighbors checked efficiently in qh_checkpolygon
*/
void qh_checkvertex(vertexT *vertex, boolT allchecks, boolT *waserrorp) {
  boolT waserror= False;
  facetT *neighbor, **neighborp, *errfacet=NULL;

  if (qh_pointid(vertex->point) == qh_IDunknown) {
    qh_fprintf(qh ferr, 6144, "qhull internal error (qh_checkvertex): unknown point id %p\n", vertex->point);
    waserror= True;
  }
  if (vertex->id >= qh vertex_id) {
    qh_fprintf(qh ferr, 6145, "qhull internal error (qh_checkvertex): unknown vertex id v%d >= qh.vertex_id (%d)\n", vertex->id, qh vertex_id);
    waserror= True;
  }
  if (vertex->visitid > qh vertex_visit) {
    qh_fprintf(qh ferr, 6413, "qhull internal error (qh_checkvertex): expecting v%d.visitid <= qh.vertex_visit (%d).  Got visitid %d\n", vertex->id, qh vertex_visit, vertex->visitid);
    waserror= True;
  }
  if (allchecks && !waserror && !vertex->deleted) {
    if (qh_setsize(vertex->neighbors)) {
      FOREACHneighbor_(vertex) {
        if (!qh_setin(neighbor->vertices, vertex)) {
          qh_fprintf(qh ferr, 6146, "qhull internal error (qh_checkvertex): neighbor f%d does not contain v%d\n", neighbor->id, vertex->id);
          errfacet= neighbor;
          waserror= True;
        }
      }
    }
  }
  if (waserror) {
    qh_errprint("ERRONEOUS", NULL, NULL, NULL, vertex);
    if (errfacet)
      qh_errexit(qh_ERRqhull, errfacet, NULL);
    *waserrorp= True;
  }
} /* checkvertex */

/*---------------------------------

  qh_clearcenters( type )
    clear old data from facet->center

  notes:
    sets new centertype
    nop if CENTERtype is the same
*/
void qh_clearcenters(qh_CENTER type) {
  facetT *facet;

  if (qh CENTERtype != type) {
    FORALLfacets {
      if (facet->tricoplanar && !facet->keepcentrum)
          facet->center= NULL;  /* center is owned by the ->keepcentrum facet */
      else if (qh CENTERtype == qh_ASvoronoi){
        if (facet->center) {
          qh_memfree(facet->center, qh center_size);
          facet->center= NULL;
        }
      }else /* qh.CENTERtype == qh_AScentrum */ {
        if (facet->center) {
          qh_memfree(facet->center, qh normal_size);
          facet->center= NULL;
        }
      }
    }
    qh CENTERtype= type;
  }
  trace2((qh ferr, 2043, "qh_clearcenters: switched to center type %d\n", type));
} /* clearcenters */

/*---------------------------------

  qh_createsimplex( vertices )
    creates a simplex from a set of vertices

  returns:
    initializes qh.facet_list to the simplex

  notes: 
    only called by qh_initialhull

  design:
    for each vertex
      create a new facet
    for each new facet
      create its neighbor set
*/
void qh_createsimplex(setT *vertices /* qh.facet_list */) {
  facetT *facet= NULL, *newfacet;
  boolT toporient= True;
  int vertex_i, vertex_n, nth;
  setT *newfacets= qh_settemp(qh hull_dim+1);
  vertexT *vertex;

  FOREACHvertex_i_(vertices) {
    newfacet= qh_newfacet();
    newfacet->vertices= qh_setnew_delnthsorted(vertices, vertex_n, vertex_i, 0);
    if (toporient)
      newfacet->toporient= True;
    qh_appendfacet(newfacet);
    newfacet->newfacet= True;
    qh_appendvertex(vertex);
    qh_setappend(&newfacets, newfacet);
    toporient ^= True;
  }
  FORALLnew_facets {
    nth= 0;
    FORALLfacet_(qh newfacet_list) {
      if (facet != newfacet)
        SETelem_(newfacet->neighbors, nth++)= facet;
    }
    qh_settruncate(newfacet->neighbors, qh hull_dim);
  }
  qh_settempfree(&newfacets);
  trace1((qh ferr, 1028, "qh_createsimplex: created simplex\n"));
} /* createsimplex */

/*---------------------------------

  qh_delridge( ridge )
    delete a ridge's vertices and frees its memory

  notes:
    assumes r.top->ridges and r.bottom->ridges have been updated
*/
void qh_delridge(ridgeT *ridge) {

  if (ridge == qh traceridge)
    qh traceridge= NULL;
  qh_setfree(&(ridge->vertices));
  qh_memfree(ridge, (int)sizeof(ridgeT));
} /* delridge */

/*---------------------------------

  qh_delvertex( vertex )
    deletes a vertex and frees its memory

  notes:
    assumes vertex->adjacencies have been updated if needed
    unlinks from vertex_list
*/
void qh_delvertex(vertexT *vertex) {

  if (vertex->deleted && !vertex->partitioned && !qh NOerrexit) {
    qh_fprintf(qh ferr, 6395, "qhull internal error (qh_delvertex): vertex v%d was deleted but it was not partitioned as a coplanar point\n",
      vertex->id);
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  if (vertex == qh tracevertex)
    qh tracevertex= NULL;
  qh_removevertex(vertex);
  qh_setfree(&vertex->neighbors);
  qh_memfree(vertex, (int)sizeof(vertexT));
} /* delvertex */


/*---------------------------------

  qh_facet3vertex( )
    return temporary set of 3-d vertices in qh_ORIENTclock order

  design:
    if simplicial facet
      build set from facet->vertices with facet->toporient
    else
      for each ridge in order
        build set from ridge's vertices
*/
setT *qh_facet3vertex(facetT *facet) {
  ridgeT *ridge, *firstridge;
  vertexT *vertex;
  int cntvertices, cntprojected=0;
  setT *vertices;

  cntvertices= qh_setsize(facet->vertices);
  vertices= qh_settemp(cntvertices);
  if (facet->simplicial) {
    if (cntvertices != 3) {
      qh_fprintf(qh ferr, 6147, "qhull internal error (qh_facet3vertex): only %d vertices for simplicial facet f%d\n",
                  cntvertices, facet->id);
      qh_errexit(qh_ERRqhull, facet, NULL);
    }
    qh_setappend(&vertices, SETfirst_(facet->vertices));
    if (facet->toporient ^ qh_ORIENTclock)
      qh_setappend(&vertices, SETsecond_(facet->vertices));
    else
      qh_setaddnth(&vertices, 0, SETsecond_(facet->vertices));
    qh_setappend(&vertices, SETelem_(facet->vertices, 2));
  }else {
    ridge= firstridge= SETfirstt_(facet->ridges, ridgeT);   /* no infinite */
    while ((ridge= qh_nextridge3d(ridge, facet, &vertex))) {
      qh_setappend(&vertices, vertex);
      if (++cntprojected > cntvertices || ridge == firstridge)
        break;
    }
    if (!ridge || cntprojected != cntvertices) {
      qh_fprintf(qh ferr, 6148, "qhull internal error (qh_facet3vertex): ridges for facet %d don't match up.  got at least %d\n",
                  facet->id, cntprojected);
      qh_errexit(qh_ERRqhull, facet, ridge);
    }
  }
  return vertices;
} /* facet3vertex */

/*---------------------------------

  qh_findbestfacet( point, bestoutside, bestdist, isoutside )
    find facet that is furthest below a point

    for Delaunay triangulations,
      Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed
      Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates.

  returns:
    if bestoutside is set (e.g., qh_ALL)
      returns best facet that is not upperdelaunay
      if Delaunay and inside, point is outside circumsphere of bestfacet
    else
      returns first facet below point
      if point is inside, returns nearest, !upperdelaunay facet
    distance to facet
    isoutside set if outside of facet

  notes:
    Distance is measured by distance to the facet's hyperplane.  For
    Delaunay facets, this is not the same as the containing facet.  It may
    be an adjacent facet or a different tricoplanar facet.  See 
    locate a facet with qh_findbestfacet()

    For tricoplanar facets, this finds one of the tricoplanar facets closest
    to the point.  

    If inside, qh_findbestfacet performs an exhaustive search
       this may be too conservative.  Sometimes it is clearly required.

    qh_findbestfacet is not used by qhull.
    uses qh.visit_id and qh.coplanarset

  see:
    qh_findbest
*/
facetT *qh_findbestfacet(pointT *point, boolT bestoutside,
           realT *bestdist, boolT *isoutside) {
  facetT *bestfacet= NULL;
  int numpart, totpart= 0;

  bestfacet= qh_findbest(point, qh facet_list,
                            bestoutside, !qh_ISnewfacets, bestoutside /* qh_NOupper */,
                            bestdist, isoutside, &totpart);
  if (*bestdist < -qh DISTround) {
    bestfacet= qh_findfacet_all(point, !qh_NOupper, bestdist, isoutside, &numpart);
    totpart += numpart;
    if ((isoutside && *isoutside && bestoutside)
    || (isoutside && !*isoutside && bestfacet->upperdelaunay)) {
      bestfacet= qh_findbest(point, bestfacet,
                            bestoutside, False, bestoutside,
                            bestdist, isoutside, &totpart);
      totpart += numpart;
    }
  }
  trace3((qh ferr, 3014, "qh_findbestfacet: f%d dist %2.2g isoutside %d totpart %d\n",
          bestfacet->id, *bestdist, (isoutside ? *isoutside : UINT_MAX), totpart));
  return bestfacet;
} /* findbestfacet */

/*---------------------------------

  qh_findbestlower( facet, point, bestdist, numpart )
    returns best non-upper, non-flipped neighbor of facet for point
    if needed, searches vertex neighbors

  returns:
    returns bestdist and updates numpart

  notes:
    called by qh_findbest() for points above an upperdelaunay facet
    if Delaunay and inside, point is outside of circumsphere of bestfacet

*/
facetT *qh_findbestlower(facetT *upperfacet, pointT *point, realT *bestdistp, int *numpart) {
  facetT *neighbor, **neighborp, *bestfacet= NULL;
  realT bestdist= -REALmax/2 /* avoid underflow */;
  realT dist;
  vertexT *vertex;
  boolT isoutside= False;  /* not used */

  zinc_(Zbestlower);
  FOREACHneighbor_(upperfacet) {
    if (neighbor->upperdelaunay || neighbor->flipped)
      continue;
    (*numpart)++;
    qh_distplane(point, neighbor, &dist);
    if (dist > bestdist) {
      bestfacet= neighbor;
      bestdist= dist;
    }
  }
  if (!bestfacet) {
    zinc_(Zbestlowerv);
    /* rarely called, numpart does not count nearvertex computations */
    vertex= qh_nearvertex(upperfacet, point, &dist);
    qh_vertexneighbors();
    FOREACHneighbor_(vertex) {
      if (neighbor->upperdelaunay || neighbor->flipped)
        continue;
      (*numpart)++;
      qh_distplane(point, neighbor, &dist);
      if (dist > bestdist) {
        bestfacet= neighbor;
        bestdist= dist;
      }
    }
  }
  if (!bestfacet) {
    zinc_(Zbestlowerall);  /* invoked once per point in outsideset */
    zmax_(Zbestloweralln, qh num_facets);
    /* [dec'15] Previously reported as QH6228 */
    trace3((qh ferr, 3025, "qh_findbestlower: all neighbors of facet %d are flipped or upper Delaunay.  Search all facets\n",
        upperfacet->id));
    /* rarely called */
    bestfacet= qh_findfacet_all(point, qh_NOupper, &bestdist, &isoutside, numpart);
  }
  *bestdistp= bestdist;
  trace3((qh ferr, 3015, "qh_findbestlower: f%d dist %2.2g for f%d p%d\n",
          bestfacet->id, bestdist, upperfacet->id, qh_pointid(point)));
  return bestfacet;
} /* findbestlower */

/*---------------------------------

  qh_findfacet_all( point, noupper, bestdist, isoutside, numpart )
    exhaustive search for facet below a point
    ignore flipped and visible facets, f.normal==NULL, and if noupper, f.upperdelaunay facets

    for Delaunay triangulations,
      Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed
      Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates.

  returns:
    returns first facet below point
    if point is inside,
      returns nearest facet
    distance to facet
    isoutside if point is outside of the hull
    number of distance tests

  notes:
    called by qh_findbestlower if all neighbors are flipped or upper Delaunay (QH3025)
    primarily for library users (qh_findbestfacet), rarely used by Qhull
*/
facetT *qh_findfacet_all(pointT *point, boolT noupper, realT *bestdist, boolT *isoutside,
                          int *numpart) {
  facetT *bestfacet= NULL, *facet;
  realT dist;
  int totpart= 0;

  *bestdist= -REALmax;
  *isoutside= False;
  FORALLfacets {
    if (facet->flipped || !facet->normal || facet->visible)
      continue;
    if (noupper && facet->upperdelaunay)
      continue;
    totpart++;
    qh_distplane(point, facet, &dist);
    if (dist > *bestdist) {
      *bestdist= dist;
      bestfacet= facet;
      if (dist > qh MINoutside) {
        *isoutside= True;
        break;
      }
    }
  }
  *numpart= totpart;
  trace3((qh ferr, 3016, "qh_findfacet_all: p%d, noupper? %d, f%d, dist %2.2g, isoutside %d, totpart %d\n",
      qh_pointid(point), noupper, getid_(bestfacet), *bestdist, *isoutside, totpart));
  return bestfacet;
} /* findfacet_all */

/*---------------------------------

  qh_findgood( facetlist, goodhorizon )
    identify good facets for qh.PRINTgood and qh_buildcone_onlygood
    goodhorizon is count of good, horizon facets from qh_find_horizon, otherwise 0 from qh_findgood_all
    if not qh.MERGING and qh.GOODvertex>0
      facet includes point as vertex
      if !match, returns goodhorizon
    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 to thresholds
      sets GOODclosest

  returns:
    number of new, good facets found
    determines facet->good
    may update qh.GOODclosest

  notes:
    called from qh_initbuild, qh_buildcone_onlygood, and qh_findgood_all
    qh_findgood_all (called from qh_prepare_output) further reduces the good region

  design:
    count good facets
    if not merging, clear good facets that fail qh.GOODvertex ('QVn', but not 'QV-n')
    clear good facets that fail qh.GOODpoint ('QGn' or 'QG-n')
    clear good facets that fail qh.GOODthreshold
    if !goodhorizon and !find f.good,
      sets GOODclosest to facet with closest angle to thresholds
*/
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 (facet->good && !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 == 0 && (goodhorizon == 0 || 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) {   /* numgood == 0 */
        if (qh GOODclosest)
          qh GOODclosest->good= False;
        qh GOODclosest= bestfacet;
        bestfacet->good= True;
        numgood++;
        trace2((qh ferr, 2044, "qh_findgood: f%d is closest(%2.2g) to thresholds\n",
           bestfacet->id, bestangle));
        return numgood;
      }
    }else if (qh GOODclosest) { /* numgood > 0 */
      qh GOODclosest->good= False;
      qh GOODclosest= NULL;
    }
  }
  zadd_(Zgoodfacet, numgood);
  trace2((qh ferr, 2045, "qh_findgood: found %d good facets with %d good horizon and qh.GOODclosest f%d\n",
               numgood, goodhorizon, getid_(qh GOODclosest)));
  if (!numgood && qh GOODvertex>0 && !qh MERGING)
    return goodhorizon;
  return numgood;
} /* findgood */

/*---------------------------------

  qh_findgood_all( facetlist )
    apply other constraints for good facets (used by qh.PRINTgood)
    if qh.GOODvertex
      facet includes (>0) or doesn't include (<0) point as vertex
      if last good facet and ONLYgood, prints warning and continues
    if qh.SPLITthresholds (e.g., qh.DELAUNAY)
      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:
    called by qh_prepare_output and qh_printneighborhood
    unless qh.ONLYgood, calls qh_findgood first

  design:
    uses qh_findgood to mark good facets
    clear f.good for failed qh.GOODvertex
    clear f.good for failed qh.SPLITthreholds
       if no more good facets, select best of qh.SPLITthresholds
*/
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))) { /* convert to bool */
        if (!--numgood) {
          if (qh ONLYgood) {
            qh_fprintf(qh ferr, 7064, "qhull warning: good vertex p%d does not match last good facet f%d.  Ignored.\n",
               qh_pointid(qh GOODvertexp), facet->id);
            return;
          }else if (qh GOODvertex > 0)
            qh_fprintf(qh ferr, 7065, "qhull warning: point p%d is not a vertex('QV%d').\n",
                qh GOODvertex-1, qh GOODvertex-1);
          else
            qh_fprintf(qh ferr, 7066, "qhull warning: point p%d is a vertex for every facet('QV-%d').\n",
                -qh GOODvertex - 1, -qh GOODvertex - 1);
        }
        facet->good= False;
      }
    }
  }
  startgood= numgood;
  if (qh SPLITthresholds) {
    FORALLfacet_(facetlist) {
      if (facet->good) {
        if (!qh_inthresholds(facet->normal, &angle)) {
          facet->good= False;
          numgood--;
          if (angle < bestangle) {
            bestangle= angle;
            bestfacet= facet;
          }
        }
      }
    }
    if (!numgood && bestfacet) {
      bestfacet->good= True;
      numgood++;
      trace0((qh ferr, 23, "qh_findgood_all: f%d is closest(%2.2g) to split thresholds\n",
           bestfacet->id, bestangle));
      return;
    }
  }
  if (numgood == 1 && !qh PRINTgood && qh GOODclosest && qh GOODclosest->good) {
    trace2((qh ferr, 2109, "qh_findgood_all: undo selection of qh.GOODclosest f%d since it would fail qh_inthresholds in qh_skipfacet\n",
      qh GOODclosest->id));
    qh GOODclosest->good= False;
    numgood= 0;
  }
  qh num_good= numgood;
  trace0((qh ferr, 24, "qh_findgood_all: %d good facets remain out of %d facets\n",
        numgood, startgood));
} /* findgood_all */

/*---------------------------------

  qh_furthestnext()
    set qh.facet_next to facet with furthest of all furthest points
    searches all facets on qh.facet_list

  notes:
    this may help avoid precision problems
*/
void qh_furthestnext(void /* qh.facet_list */) {
  facetT *facet, *bestfacet= NULL;
  realT dist, bestdist= -REALmax;

  FORALLfacets {
    if (facet->outsideset) {
#if qh_COMPUTEfurthest
      pointT *furthest;
      furthest= (pointT *)qh_setlast(facet->outsideset);
      zinc_(Zcomputefurthest);
      qh_distplane(furthest, facet, &dist);
#else
      dist= facet->furthestdist;
#endif
      if (dist > bestdist) {
        bestfacet= facet;
        bestdist= dist;
      }
    }
  }
  if (bestfacet) {
    qh_removefacet(bestfacet);
    qh_prependfacet(bestfacet, &qh facet_next);
    trace1((qh ferr, 1029, "qh_furthestnext: made f%d next facet(dist %.2g)\n",
            bestfacet->id, bestdist));
  }
} /* furthestnext */

/*---------------------------------

  qh_furthestout( facet )
    make furthest outside point the last point of outsideset

  returns:
    updates facet->outsideset
    clears facet->notfurthest
    sets facet->furthestdist

  design:
    determine best point of outsideset
    make it the last point of outsideset
*/
void qh_furthestout(facetT *facet) {
  pointT *point, **pointp, *bestpoint= NULL;
  realT dist, bestdist= -REALmax;

  FOREACHpoint_(facet->outsideset) {
    qh_distplane(point, facet, &dist);
    zinc_(Zcomputefurthest);
    if (dist > bestdist) {
      bestpoint= point;
      bestdist= dist;
    }
  }
  if (bestpoint) {
    qh_setdel(facet->outsideset, point);
    qh_setappend(&facet->outsideset, point);
#if !qh_COMPUTEfurthest
    facet->furthestdist= bestdist;
#endif
  }
  facet->notfurthest= False;
  trace3((qh ferr, 3017, "qh_furthestout: p%d is furthest outside point of f%d\n",
          qh_pointid(point), facet->id));
} /* furthestout */


/*---------------------------------

  qh_infiniteloop( facet )
    report infinite loop error due to facet
*/
void qh_infiniteloop(facetT *facet) {

  qh_fprintf(qh ferr, 6149, "qhull internal error (qh_infiniteloop): potential infinite loop detected.  If visible, f.replace. If newfacet, f.samecycle\n");
  qh_errexit(qh_ERRqhull, facet, NULL);
} /* qh_infiniteloop */

/*---------------------------------

  qh_initbuild()
    initialize hull and outside sets with point array
    qh.FIRSTpoint/qh.NUMpoints is point array
    if qh.GOODpoint
      adds qh.GOODpoint to initial hull

  returns:
    qh_facetlist with initial hull
    points partioned into outside sets, coplanar sets, or inside
    initializes qh.GOODpointp, qh.GOODvertexp,

  design:
    initialize global variables used during qh_buildhull
    determine precision constants and points with max/min coordinate values
      if qh.SCALElast, scale last coordinate(for 'd')
    initialize qh.newfacet_list, qh.facet_tail
    initialize qh.vertex_list, qh.newvertex_list, qh.vertex_tail
    determine initial vertices
    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;

  if (qh PRINTstatistics) {
    qh_fprintf(qh ferr, 9350, "qhull %s Statistics: %s | %s\n",
      qh_version, qh rbox_command, qh qhull_command);
    fflush(NULL);
  }
  qh furthest_id= qh_IDunknown;
  qh lastreport= 0;
  qh lastfacets= 0;
  qh lastmerges= 0;
  qh lastplanes= 0;
  qh lastdist= 0;
  qh facet_id= qh vertex_id= qh ridge_id= 0;
  qh visit_id= qh vertex_visit= 0;
  qh maxoutdone= False;

  if (qh GOODpoint > 0)
    qh GOODpointp= qh_point(qh GOODpoint-1);
  else if (qh GOODpoint < 0)
    qh GOODpointp= qh_point(-qh GOODpoint-1);
  if (qh GOODvertex > 0)
    qh GOODvertexp= qh_point(qh GOODvertex-1);
  else if (qh GOODvertex < 0)
    qh GOODvertexp= qh_point(-qh GOODvertex-1);
  if ((qh GOODpoint
       && (qh GOODpointp < qh first_point  /* also catches !GOODpointp */
           || qh GOODpointp > qh_point(qh num_points-1)))
  || (qh GOODvertex
       && (qh GOODvertexp < qh first_point  /* also catches !GOODvertexp */
           || qh GOODvertexp > qh_point(qh num_points-1)))) {
    qh_fprintf(qh ferr, 6150, "qhull input error: either QGn or QVn point is > p%d\n",
             qh num_points-1);
    qh_errexit(qh_ERRinput, NULL, NULL);
  }
  maxpoints= qh_maxmin(qh first_point, qh num_points, qh hull_dim);
  if (qh SCALElast)
    qh_scalelast(qh first_point, qh num_points, qh hull_dim, qh MINlastcoord, qh MAXlastcoord, qh MAXabs_coord);
  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. */
      }
    }
  }
  trace4((qh ferr, 4091, "qh_initbuild: create sentinels for qh.facet_tail and qh.vertex_tail\n"));
  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);
  vertices= qh_initialvertices(qh hull_dim, maxpoints, qh first_point, qh num_points);
  qh_initialhull(vertices);  /* initial qh facet_list */
  qh_partitionall(vertices, qh first_point, qh num_points);
  if (qh PRINToptions1st || qh TRACElevel || qh IStracing) {
    if (qh TRACElevel || qh IStracing)
      qh_fprintf(qh ferr, 8103, "\nTrace level T%d, IStracing %d, point TP%d, merge TM%d, dist TW%2.2g, qh.tracefacet_id %d, traceridge_id %d, tracevertex_id %d, last qh.RERUN %d, %s | %s\n",
         qh TRACElevel, qh IStracing, qh TRACEpoint, qh TRACEmerge, qh TRACEdist, qh tracefacet_id, qh traceridge_id, qh tracevertex_id, qh TRACElastrun, qh rbox_command, qh qhull_command);
    qh_fprintf(qh ferr, 8104, "Options selected for Qhull %s:\n%s\n", qh_version, qh qhull_options);
  }
  qh_resetlists(False, qh_RESETvisible /* qh.visible_list newvertex_list qh.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; /* overwritten by qh_premerge */
  }
  if (qh ONLYgood) {
    if (qh GOODvertex > 0 && qh MERGING) {
      qh_fprintf(qh ferr, 6151, "qhull input error: 'Qg QVn' (only good vertex) does not work with merging.\nUse 'QJ' to joggle the input or 'Q0' to turn off merging.\n");
      qh_errexit(qh_ERRinput, NULL, NULL);
    }
    if (!(qh GOODthreshold || qh GOODpoint
         || (!qh MERGEexact && !qh PREmerge && qh GOODvertexp))) {
      qh_fprintf(qh ferr, 6152, "qhull input error: 'Qg' (ONLYgood) needs a good threshold('Pd0D0'), a good point(QGn or QG-n), or a good vertex with 'QJ' or 'Q0' (QVn).\n");
      qh_errexit(qh_ERRinput, NULL, NULL);
    }
    if (qh GOODvertex > 0  && !qh MERGING  /* matches qh_partitionall */
    && !qh_isvertex(qh GOODvertexp, vertices)) {
      facet= qh_findbestnew(qh GOODvertexp, qh facet_list,
                          &dist, !qh_ALL, &isoutside, &numpart);
      zadd_(Zdistgood, numpart);
      if (!isoutside) {
        qh_fprintf(qh ferr, 6153, "qhull input error: point for QV%d is inside initial simplex.  It can not be made a vertex.\n",
               qh_pointid(qh GOODvertexp));
        qh_errexit(qh_ERRinput, NULL, NULL);
      }
      if (!qh_addpoint(qh GOODvertexp, facet, False)) {
        qh_settempfree(&vertices);
        qh_settempfree(&maxpoints);
        return;
      }
    }
    qh_findgood(qh facet_list, 0);
  }
  qh_settempfree(&vertices);
  qh_settempfree(&maxpoints);
  trace1((qh ferr, 1030, "qh_initbuild: initial hull created and points partitioned\n"));
} /* initbuild */

/*---------------------------------

  qh_initialhull( vertices )
    constructs the initial hull as a DIM3 simplex of vertices

  notes:
    only called by qh_initbuild

  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 angle, minangle= REALmax, dist;

  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);
  if (qh IStracing) {
    qh_fprintf(qh ferr, 8105, "qh_initialhull: ");
    qh_printpoint(qh ferr, "qh.interior_point", qh interior_point);
  }
  firstfacet= qh facet_list;
  qh_setfacetplane(firstfacet);   /* qh_joggle_restart if flipped */
  if (firstfacet->flipped) {
    trace1((qh ferr, 1065, "qh_initialhull: ignore f%d flipped.  Test qh.interior_point (p-2) for clearly flipped\n", firstfacet->id));
    firstfacet->flipped= False;
  }
  zzinc_(Zdistcheck);
  qh_distplane(qh interior_point, firstfacet, &dist);
  if (dist > qh DISTround) {  /* clearly flipped */
    trace1((qh ferr, 1060, "qh_initialhull: initial orientation incorrect, qh.interior_point is %2.2g from f%d.  Reversing orientation of all facets\n",
          dist, firstfacet->id));
    FORALLfacets
      facet->toporient ^= (unsigned char)True;
    qh_setfacetplane(firstfacet);
  }
  FORALLfacets {
    if (facet != firstfacet)
      qh_setfacetplane(facet);    /* qh_joggle_restart if flipped */
  }
  FORALLfacets {
    if (facet->flipped) {
      trace1((qh ferr, 1066, "qh_initialhull: ignore f%d flipped.  Test qh.interior_point (p-2) for clearly flipped\n", facet->id));
      facet->flipped= False;
    }
    zzinc_(Zdistcheck);
    qh_distplane(qh interior_point, facet, &dist);  /* duplicates qh_setfacetplane */
    if (dist > qh DISTround) {  /* clearly flipped, due to axis-parallel facet or coplanar firstfacet */
      trace1((qh ferr, 1031, "qh_initialhull: initial orientation incorrect, qh.interior_point is %2.2g from f%d.  Either axis-parallel facet or coplanar firstfacet f%d.  Force outside orientation of all facets\n"));
      FORALLfacets { /* reuse facet, then 'break' */
        facet->flipped= False;
        facet->toporient ^= (unsigned char)True;
        qh_orientoutside(facet);  /* force outside orientation for f.normal */
      }
      break;
    }
  }
  FORALLfacets {
    if (!qh_checkflipped(facet, NULL, qh_ALL)) {
      if (qh DELAUNAY && ! qh ATinfinity) {
        qh_joggle_restart("initial Delaunay cocircular or cospherical");
        if (qh UPPERdelaunay)
          qh_fprintf(qh ferr, 6240, "Qhull precision error: initial Delaunay input sites are cocircular or cospherical.  Option 'Qs' searches all points.  Use option 'QJ' to joggle the input, otherwise cannot compute the upper Delaunay triangulation or upper Voronoi diagram of cocircular/cospherical points.\n");
        else
          qh_fprintf(qh ferr, 6239, "Qhull precision error: initial Delaunay input sites are cocircular or cospherical.  Use option 'Qz' for the Delaunay triangulation or Voronoi diagram of cocircular/cospherical points; it adds a point \"at infinity\".  Alternatively use option 'QJ' to joggle the input.  Use option 'Qs' to search all points for the initial simplex.\n");
        qh_printvertexlist(qh ferr, "\ninput sites with last coordinate projected to a paraboloid\n", qh facet_list, NULL, qh_ALL);
        qh_errexit(qh_ERRinput, NULL, NULL);
      }else {
        qh_joggle_restart("initial simplex is flat");
        qh_fprintf(qh ferr, 6154, "Qhull precision error: Initial simplex is flat (facet %d is coplanar with the interior point)\n",
                   facet->id);
        qh_errexit(qh_ERRsingular, NULL, NULL);  /* calls qh_printhelp_singular */
      }
    }
    FOREACHneighbor_(facet) {
      angle= qh_getangle(facet->normal, neighbor->normal);
      minimize_( minangle, angle);
    }
  }
  if (minangle < qh_MAXnarrow && !qh NOnarrow) {
    realT diff= 1.0 + minangle;

    qh NARROWhull= True;
    qh_option("_narrow-hull", NULL, &diff);
    if (minangle < qh_WARNnarrow && !qh RERUN && qh PRINTprecision)
      qh_printhelp_narrowhull(qh ferr, minangle);
  }
  zzval_(Zprocessed)= qh hull_dim+1;
  qh_checkpolygon(qh facet_list);
  qh_checkconvex(qh facet_list, qh_DATAfault);
  if (qh IStracing >= 1) {
    qh_fprintf(qh ferr, 8105, "qh_initialhull: simplex constructed\n");
  }
} /* initialhull */

/*---------------------------------

  qh_initialvertices( dim, maxpoints, points, numpoints )
    determines a non-singular set of initial vertices
    maxpoints may include duplicate points

  returns:
    temporary set of dim+1 vertices in descending order by vertex id
    if qh.RANDOMoutside && !qh.ALLpoints
      picks random points
    if dim >= qh_INITIALmax,
      uses min/max x and max points with non-zero determinants

  notes:
    unless qh.ALLpoints,
      uses maxpoints as long as determinate is non-zero
*/
setT *qh_initialvertices(int dim, setT *maxpoints, pointT *points, int numpoints) {
  pointT *point, **pointp;
  setT *vertices, *simplex, *tested;
  realT randr;
  int idx, point_i, point_n, k;
  boolT nearzero= False;

  vertices= qh_settemp(dim + 1);
  simplex= qh_settemp(dim + 1);
  if (qh ALLpoints)
    qh_maxsimplex(dim, NULL, points, numpoints, &simplex);
  else if (qh RANDOMoutside) {
    while (qh_setsize(simplex) != dim+1) {
      randr= qh_RANDOMint;
      randr= randr/(qh_RANDOMmax+1);
      randr= floor(qh num_points * randr);
      idx= (int)randr;
      while (qh_setin(simplex, qh_point(idx))) {
        idx++; /* in case qh_RANDOMint always returns the same value */
        idx= idx < qh num_points ? idx : 0;
      }
      qh_setappend(&simplex, qh_point(idx));
    }
  }else if (qh hull_dim >= qh_INITIALmax) {
    tested= qh_settemp(dim+1);
    qh_setappend(&simplex, SETfirst_(maxpoints));   /* max and min X coord */
    qh_setappend(&simplex, SETsecond_(maxpoints));
    qh_maxsimplex(fmin_(qh_INITIALsearch, dim), maxpoints, points, numpoints, &simplex);
    k= qh_setsize(simplex);
    FOREACHpoint_i_(maxpoints) {
      if (k >= dim)  /* qh_maxsimplex for last point */
        break;
      if (point_i & 0x1) {     /* first try up to dim, 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);
            k++;
          }
        }
      }
    }
    FOREACHpoint_i_(maxpoints) {
      if (k >= dim)  /* qh_maxsimplex for last point */
        break;
      if ((point_i & 0x1) == 0) {  /* then test min. 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);
            k++;
          }
        }
      }
    }
    /* remove tested points from maxpoints */
    FOREACHpoint_i_(maxpoints) {
      if (qh_setin(simplex, point) || qh_setin(tested, point))
        SETelem_(maxpoints, point_i)= NULL;
    }
    qh_setcompact(maxpoints);
    idx= 0;
    while (k < dim && (point= qh_point(idx++))) {
      if (!qh_setin(simplex, point) && !qh_setin(tested, point)){
        qh_detsimplex(point, simplex, k, &nearzero);
        if (!nearzero){
          qh_setappend(&simplex, point);
          k++;
        }
      }
    }
    qh_settempfree(&tested);
    qh_maxsimplex(dim, maxpoints, points, numpoints, &simplex);
  }else /* qh.hull_dim < qh_INITIALmax */
    qh_maxsimplex(dim, maxpoints, points, numpoints, &simplex);
  FOREACHpoint_(simplex)
    qh_setaddnth(&vertices, 0, qh_newvertex(point)); /* descending order */
  qh_settempfree(&simplex);
  return vertices;
} /* initialvertices */


/*---------------------------------

  qh_isvertex( point, vertices )
    returns vertex if point is in vertex set, else returns NULL

  notes:
    for qh.GOODvertex
*/
vertexT *qh_isvertex(pointT *point, setT *vertices) {
  vertexT *vertex, **vertexp;

  FOREACHvertex_(vertices) {
    if (vertex->point == point)
      return vertex;
  }
  return NULL;
} /* isvertex */

/*---------------------------------

  qh_makenewfacets( point )
    make new facets from point and qh.visible_list

  returns:
    apex (point) of the new facets
    qh.newfacet_list= list of new facets with hyperplanes and ->newfacet
    qh.newvertex_list= list of vertices in new facets with ->newfacet set

    if (qh.NEWtentative)
      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 NEWtentative
    qh_matchnewfacets() -- match up neighbors
    qh_update_vertexneighbors() -- 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 /* qh.visible_list */) {
  facetT *visible, *newfacet= NULL, *newfacet2= NULL, *neighbor, **neighborp;
  vertexT *apex;
  int numnew=0;

  if (qh CHECKfrequently) {
    qh_checkdelridge();
  }
  qh newfacet_list= qh facet_tail;
  qh newvertex_list= qh vertex_tail;
  apex= qh_newvertex(point);
  qh_appendvertex(apex);
  qh visit_id++;
  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 NEWtentative) {
      if (newfacet2)  /* newfacet is null if all ridges defined */
        newfacet= newfacet2;
      if (newfacet)
        visible->f.replace= newfacet;
      else
        zinc_(Zinsidevisible);
      if (visible->ridges)      /* ridges and neighbors are no longer valid for visible facet */
        SETfirst_(visible->ridges)= NULL;
      SETfirst_(visible->neighbors)= NULL;
    }
  }
  if (!qh NEWtentative)
    qh NEWfacets= True;
  trace1((qh ferr, 1032, "qh_makenewfacets: created %d new facets f%d..f%d from point p%d to horizon\n",
    numnew, qh first_newfacet, qh facet_id-1, qh_pointid(point)));
  if (qh IStracing >= 4)
    qh_printfacetlist(qh newfacet_list, NULL, qh_ALL);
  return apex;
} /* makenewfacets */

#ifndef qh_NOmerge
/*---------------------------------

  qh_matchdupridge( atfacet, atskip, hashsize, hashcount )
    match duplicate ridges in qh.hash_table for atfacet@atskip
    duplicates marked with ->dupridge and qh_DUPLICATEridge

  returns:
    vertex-facet distance (>0.0) for qh_MERGEridge ridge
    updates hashcount
    set newfacet, facet, matchfacet's hyperplane (removes from mergecycle of coplanarhorizon facets)

  see also:
    qh_matchneighbor

  notes:
    only called by qh_matchnewfacets for qh_buildcone and qh_triangulate_facet
    assumes atfacet is simplicial
    assumes atfacet->neighbors @ atskip == qh_DUPLICATEridge
    usually keeps ridge with the widest merge
    both MRGdupridge and MRGflipped are required merges -- rbox 100 C1,2e-13 D4 t1 | qhull d Qbb
      can merge flipped f11842 skip 3 into f11862 skip 2 and vice versa (forced by goodmatch/goodmatch2)
         blocks -- cannot merge f11862 skip 2 and f11863 skip2 (the widest merge)
         must block -- can merge f11843 skip 3 into f11842 flipped skip 3, but not vice versa
      can merge f11843 skip 3 into f11863 skip 2, but not vice versa
    working/unused.h: [jan'19] Dropped qh_matchdupridge_coplanarhorizon, it was the same or slightly worse.  Complex addition, rarely occurs

  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 with the same orientation 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 with the same orientation and pass 1
          test if this is a better match
      if pass 1,
        make best match (it will not be merged)
        set newfacet, facet, matchfacet's hyperplane (removes from mergecycle of coplanarhorizon facets)

*/
coordT qh_matchdupridge(facetT *atfacet, int atskip, int hashsize, int *hashcount) {
  boolT same, ismatch, isduplicate= False;
  int hash, scan;
  facetT *facet, *newfacet, *nextfacet;
  facetT *maxmatch= NULL, *maxmatch2= NULL, *goodmatch= NULL, *goodmatch2= NULL;
  int skip, newskip, nextskip= 0, makematch;
  int maxskip= 0, maxskip2= 0, goodskip= 0, goodskip2= 0;
  coordT maxdist= -REALmax, maxdist2= 0.0, dupdist, dupdist2, low, high, maxgood, gooddist= 0.0;

  maxgood= qh_WIDEdupridge * (qh ONEmerge + qh DISTround); 
  hash= qh_gethash(hashsize, atfacet->vertices, qh hull_dim, 1,
                     SETelem_(atfacet->vertices, atskip));
  trace2((qh ferr, 2046, "qh_matchdupridge: find dupridge matches for f%d skip %d hash %d hashcount %d\n",
          atfacet->id, atskip, hash, *hashcount));
  for (makematch=0; makematch < 2; makematch++) { /* makematch is false on the first pass and 1 on the second */
    qh visit_id++;
    for (newfacet=atfacet, newskip=atskip; newfacet; newfacet= nextfacet, newskip= nextskip) {
      zinc_(Zhashlookup);
      nextfacet= NULL; /* exit when ismatch found */
      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)) {
          if (SETelem_(newfacet->vertices, newskip) == SETelem_(facet->vertices, skip)) {
            trace3((qh ferr, 3053, "qh_matchdupridge: duplicate ridge due to duplicate facets (f%d skip %d and f%d skip %d) previously reported as QH7084.  Maximize dupdist to force vertex merge\n",
              newfacet->id, newskip, facet->id, skip));
            isduplicate= True;
          }
          ismatch= (same == (boolT)(newfacet->toporient ^ facet->toporient));
          if (SETelemt_(facet->neighbors, skip, facetT) != qh_DUPLICATEridge) {
            if (!makematch) {  /* occurs if many merges, e.g., rbox 100 W0 C2,1e-13 D6 t1546872462 | qhull C0 Qt Tcv */
              qh_fprintf(qh ferr, 6155, "qhull topology error (qh_matchdupridge): missing qh_DUPLICATEridge at f%d skip %d for new f%d skip %d hash %d ismatch %d.  Set by qh_matchneighbor\n",
                facet->id, skip, newfacet->id, newskip, hash, ismatch);
              qh_errexit2(qh_ERRtopology, facet, newfacet);
            }
          }else if (!ismatch) {
            nextfacet= facet;
            nextskip= skip;
          }else if (SETelemt_(newfacet->neighbors, newskip, facetT) == qh_DUPLICATEridge) {
            if (makematch) {
              if (newfacet->tricoplanar) {
                SETelem_(facet->neighbors, skip)= newfacet;
                SETelem_(newfacet->neighbors, newskip)= facet;
                *hashcount -= 2; /* removed two unmatched facets */
                trace2((qh ferr, 2075, "qh_matchdupridge: allow tricoplanar dupridge for new f%d skip %d and f%d skip %d\n",
                    newfacet->id, newskip, facet->id, skip)); 
              }else if (goodmatch && goodmatch2) {
                SETelem_(goodmatch2->neighbors, goodskip2)= qh_MERGEridge;  /* undo selection of goodmatch */
                SETelem_(facet->neighbors, skip)= newfacet;
                SETelem_(newfacet->neighbors, newskip)= facet;
                *hashcount -= 2; /* removed two unmatched facets */
                trace2((qh ferr, 2105, "qh_matchdupridge: make good forced merge of dupridge f%d skip %d into f%d skip %d, keep new f%d skip %d and f%d skip %d, dist %4.4g\n",
                  goodmatch->id, goodskip, goodmatch2->id, goodskip2, newfacet->id, newskip, facet->id, skip, gooddist)); 
                goodmatch2= NULL;
              }else {
                SETelem_(facet->neighbors, skip)= newfacet;
                SETelem_(newfacet->neighbors, newskip)= qh_MERGEridge;  /* resolved by qh_mark_dupridges */
                *hashcount -= 2; /* removed two unmatched facets */
                trace3((qh ferr, 3073, "qh_matchdupridge: make forced merge of dupridge for new f%d skip %d and f%d skip %d, maxdist %4.4g in qh_forcedmerges\n",
                  newfacet->id, newskip, facet->id, skip, maxdist2));
              }
            }else { /* !makematch */
              if (!facet->normal)
                qh_setfacetplane(facet); /* qh_mergecycle will ignore 'mergehorizon' facets with normals, too many cases otherwise */
              if (!newfacet->normal) 
                qh_setfacetplane(newfacet);
              dupdist= qh_getdistance(facet, newfacet, &low, &high); /* ignore low/high */
              dupdist2= qh_getdistance(newfacet, facet, &low, &high);
              if (isduplicate) {
                goodmatch= NULL;
                minimize_(dupdist, dupdist2);
                maxdist= dupdist;
                maxdist2= REALmax/2;
                maxmatch= facet;
                maxskip= skip;
                maxmatch2= newfacet;
                maxskip2= newskip;
                break; /* force maxmatch */
              }else if (facet->flipped && !newfacet->flipped && dupdist < maxgood) {
                if (!goodmatch || !goodmatch->flipped || dupdist < gooddist) {
                  goodmatch= facet; 
                  goodskip= skip;
                  goodmatch2= newfacet;
                  goodskip2= newskip;
                  gooddist= dupdist;
                  trace3((qh ferr, 3070, "qh_matchdupridge: try good dupridge flipped f%d skip %d into new f%d skip %d at dist %2.2g otherdist %2.2g\n",
                    goodmatch->id, goodskip, goodmatch2->id, goodskip2, gooddist, dupdist2));
                }
              }else if (newfacet->flipped && !facet->flipped && dupdist2 < maxgood) {
                if (!goodmatch || !goodmatch->flipped || dupdist2 < gooddist) {
                  goodmatch= newfacet;  
                  goodskip= newskip;
                  goodmatch2= facet;
                  goodskip2= skip;
                  gooddist= dupdist2;
                  trace3((qh ferr, 3071, "qh_matchdupridge: try good dupridge flipped new f%d skip %d into f%d skip %d at dist %2.2g otherdist %2.2g\n",
                    goodmatch->id, goodskip, goodmatch2->id, goodskip2, gooddist, dupdist));
                }
              }else if (dupdist < maxgood && (!newfacet->flipped || facet->flipped)) { /* disallow not-flipped->flipped */
                if (!goodmatch || (!goodmatch->flipped && dupdist < gooddist)) {
                  goodmatch= facet;
                  goodskip= skip;
                  goodmatch2= newfacet;
                  goodskip2= newskip;
                  gooddist= dupdist;
                  trace3((qh ferr, 3072, "qh_matchdupridge: try good dupridge f%d skip %d into new f%d skip %d at dist %2.2g otherdist %2.2g\n",
                    goodmatch->id, goodskip, goodmatch2->id, goodskip2, gooddist, dupdist2));
                }
              }else if (dupdist2 < maxgood && (!facet->flipped || newfacet->flipped)) { /* disallow not-flipped->flipped */
                if (!goodmatch || (!goodmatch->flipped && dupdist2 < gooddist)) {
                  goodmatch= newfacet;  
                  goodskip= newskip;
                  goodmatch2= facet;
                  goodskip2= skip;
                  gooddist= dupdist2;
                  trace3((qh ferr, 3018, "qh_matchdupridge: try good dupridge new f%d skip %d into f%d skip %d at dist %2.2g otherdist %2.2g\n",
                    goodmatch->id, goodskip, goodmatch2->id, goodskip2, gooddist, dupdist));
                }
              }else if (!goodmatch) { /* otherwise match the furthest apart facets */
                if (!newfacet->flipped || facet->flipped) {
                  minimize_(dupdist, dupdist2);
                }
                if (dupdist > maxdist) { /* could keep !flipped->flipped, but probably lost anyway */
                  maxdist2= maxdist;
                  maxdist= dupdist;
                  maxmatch= facet;
                  maxskip= skip;
                  maxmatch2= newfacet;
                  maxskip2= newskip;
                  trace3((qh ferr, 3055, "qh_matchdupridge: try furthest dupridge f%d skip %d new f%d skip %d at dist %2.2g\n",
                    maxmatch->id, maxskip, maxmatch2->id, maxskip2, maxdist));
                }else if (dupdist > maxdist2)
                  maxdist2= dupdist;
              }
            }
          }
        }
      } /* end of foreach entry in qh.hash_table starting at 'hash' */
      if (makematch && SETelemt_(newfacet->neighbors, newskip, facetT) == qh_DUPLICATEridge) {
        qh_fprintf(qh ferr, 6156, "qhull internal error (qh_matchdupridge): no MERGEridge match for dupridge new f%d skip %d at hash %d..%d\n",
                    newfacet->id, newskip, hash, scan);
        qh_errexit(qh_ERRqhull, newfacet, NULL);
      }
    } /* end of foreach newfacet at 'hash' */
    if (!makematch) {
      if (!maxmatch && !goodmatch) {
        qh_fprintf(qh ferr, 6157, "qhull internal error (qh_matchdupridge): no maximum or good match for dupridge new f%d skip %d at hash %d..%d\n",
          atfacet->id, atskip, hash, scan);
        qh_errexit(qh_ERRqhull, atfacet, NULL);
      }
      if (goodmatch) {
        SETelem_(goodmatch->neighbors, goodskip)= goodmatch2;
        SETelem_(goodmatch2->neighbors, goodskip2)= goodmatch;
        *hashcount -= 2; /* removed two unmatched facets */
        if (goodmatch->flipped) {
          if (!goodmatch2->flipped) {
            zzinc_(Zflipridge);
          }else {
            zzinc_(Zflipridge2);
            /* qh_joggle_restart called by qh_matchneighbor if qh_DUPLICATEridge */
          }
        }
        /* previously traced */
      }else {
        SETelem_(maxmatch->neighbors, maxskip)= maxmatch2; /* maxmatch!=NULL by QH6157 */
        SETelem_(maxmatch2->neighbors, maxskip2)= maxmatch;
        *hashcount -= 2; /* removed two unmatched facets */
        zzinc_(Zmultiridge);
        /* qh_joggle_restart called by qh_matchneighbor if qh_DUPLICATEridge */
        trace0((qh ferr, 25, "qh_matchdupridge: keep dupridge f%d skip %d and f%d skip %d, dist %4.4g\n",
          maxmatch2->id, maxskip2, maxmatch->id, maxskip, maxdist));
      }
    }
  }
  if (goodmatch)
    return gooddist;
  return maxdist2;
} /* matchdupridge */

#else /* qh_NOmerge */
coordT qh_matchdupridge(facetT *atfacet, int atskip, int hashsize, int *hashcount) {
  QHULL_UNUSED(atfacet)
  QHULL_UNUSED(atskip)
  QHULL_UNUSED(hashsize)
  QHULL_UNUSED(hashcount)

  return 0.0;
}
#endif /* qh_NOmerge */

/*---------------------------------

  qh_nearcoplanar()
    for all facets, remove near-inside points from facet->coplanarset
    coplanar points defined by innerplane from qh_outerinner()

  returns:
    if qh KEEPcoplanar && !qh KEEPinside
      facet->coplanarset only contains coplanar points
    if qh.JOGGLEmax
      drops inner plane by another qh.JOGGLEmax diagonal since a
        vertex could shift out while a coplanar point shifts in

  notes:
    used for qh.PREmerge and qh.JOGGLEmax
    must agree with computation of qh.NEARcoplanar in qh_detroundoff

  design:
    if not keeping coplanar or inside points
      free all coplanar sets
    else if not keeping both coplanar and inside points
      remove !coplanar or !inside points from coplanar sets
*/
void qh_nearcoplanar(void /* qh.facet_list */) {
  facetT *facet;
  pointT *point, **pointp;
  int numpart;
  realT dist, innerplane;

  if (!qh KEEPcoplanar && !qh KEEPinside) {
    FORALLfacets {
      if (facet->coplanarset)
        qh_setfree(&facet->coplanarset);
    }
  }else if (!qh KEEPcoplanar || !qh KEEPinside) {
    qh_outerinner(NULL, NULL, &innerplane);
    if (qh JOGGLEmax < REALmax/2)
      innerplane -= qh JOGGLEmax * sqrt((realT)qh hull_dim);
    numpart= 0;
    FORALLfacets {
      if (facet->coplanarset) {
        FOREACHpoint_(facet->coplanarset) {
          numpart++;
          qh_distplane(point, facet, &dist);
          if (dist < innerplane) {
            if (!qh KEEPinside)
              SETref_(point)= NULL;
          }else if (!qh KEEPcoplanar)
            SETref_(point)= NULL;
        }
        qh_setcompact(facet->coplanarset);
      }
    }
    zzadd_(Zcheckpart, numpart);
  }
} /* nearcoplanar */

/*---------------------------------

  qh_nearvertex( facet, point, bestdist )
    return nearest vertex in facet to point

  returns:
    vertex and its distance

  notes:
    if qh.DELAUNAY
      distance is measured in the input set
    searches neighboring tricoplanar facets (requires vertexneighbors)
      Slow implementation.  Recomputes vertex set for each point.
    The vertex set could be stored in the qh.keepcentrum facet.
*/
vertexT *qh_nearvertex(facetT *facet, pointT *point, realT *bestdistp) {
  realT bestdist= REALmax, dist;
  vertexT *bestvertex= NULL, *vertex, **vertexp, *apex;
  coordT *center;
  facetT *neighbor, **neighborp;
  setT *vertices;
  int dim= qh hull_dim;

  if (qh DELAUNAY)
    dim--;
  if (facet->tricoplanar) {
    if (!qh VERTEXneighbors || !facet->center) {
      qh_fprintf(qh ferr, 6158, "qhull internal error (qh_nearvertex): qh.VERTEXneighbors and facet->center required for tricoplanar facets\n");
      qh_errexit(qh_ERRqhull, facet, NULL);
    }
    vertices= qh_settemp(qh TEMPsize);
    apex= SETfirstt_(facet->vertices, vertexT);
    center= facet->center;
    FOREACHneighbor_(apex) {
      if (neighbor->center == center) {
        FOREACHvertex_(neighbor->vertices)
          qh_setappend(&vertices, vertex);
      }
    }
  }else
    vertices= facet->vertices;
  FOREACHvertex_(vertices) {
    dist= qh_pointdist(vertex->point, point, -dim);
    if (dist < bestdist) {
      bestdist= dist;
      bestvertex= vertex;
    }
  }
  if (facet->tricoplanar)
    qh_settempfree(&vertices);
  *bestdistp= sqrt(bestdist);
  if (!bestvertex) {
      qh_fprintf(qh ferr, 6261, "qhull internal error (qh_nearvertex): did not find bestvertex for f%d p%d\n", facet->id, qh_pointid(point));
      qh_errexit(qh_ERRqhull, facet, NULL);
  }
  trace3((qh ferr, 3019, "qh_nearvertex: v%d dist %2.2g for f%d p%d\n",
        bestvertex->id, *bestdistp, facet->id, qh_pointid(point))); /* bestvertex!=0 by QH2161 */
  return bestvertex;
} /* nearvertex */

/*---------------------------------

  qh_newhashtable( newsize )
    returns size of qh.hash_table of at least newsize slots

  notes:
    assumes qh.hash_table is NULL
    qh_HASHfactor determines the number of extra slots
    size is not divisible by 2, 3, or 5
*/
int qh_newhashtable(int newsize) {
  int size;

  size= ((newsize+1)*qh_HASHfactor) | 0x1;  /* odd number */
  while (True) {
    if (newsize<0 || size<0) {
        qh_fprintf(qhmem.ferr, 6236, "qhull error (qh_newhashtable): negative request (%d) or size (%d).  Did int overflow due to high-D?\n", newsize, size); /* WARN64 */
        qh_errexit(qhmem_ERRmem, NULL, NULL);
    }
    if ((size%3) && (size%5))
      break;
    size += 2;
    /* loop terminates because there is an infinite number of primes */
  }
  qh hash_table= qh_setnew(size);
  qh_setzero(qh hash_table, 0, size);
  return size;
} /* newhashtable */

/*---------------------------------

  qh_newvertex( point )
    returns a new vertex for point
*/
vertexT *qh_newvertex(pointT *point) {
  vertexT *vertex;

  zinc_(Ztotvertices);
  vertex= (vertexT *)qh_memalloc((int)sizeof(vertexT));
  memset((char *) vertex, (size_t)0, sizeof(vertexT));
  if (qh vertex_id == UINT_MAX) {
    qh_memfree(vertex, (int)sizeof(vertexT));
    qh_fprintf(qh ferr, 6159, "qhull error: 2^32 or more vertices.  vertexT.id field overflows.  Vertices would not be sorted correctly.\n");
    qh_errexit(qh_ERRother, NULL, NULL);
  }
  if (qh vertex_id == qh tracevertex_id)
    qh tracevertex= vertex;
  vertex->id= qh vertex_id++;
  vertex->point= point;
  trace4((qh ferr, 4060, "qh_newvertex: vertex p%d(v%d) created\n", qh_pointid(vertex->point),
          vertex->id));
  return(vertex);
} /* newvertex */

/*---------------------------------

  qh_nextfacet2d( facet, &nextvertex )
    return next facet and vertex for a 2d facet in qh_ORIENTclock order
    returns NULL on error

  notes:
    in qh_ORIENTclock order (default counter-clockwise)
    nextvertex is in between the two facets
    does not use qhT or qh_errexit [QhullFacet.cpp]

  design:
    see io.c/qh_printextremes_2d
*/
facetT *qh_nextfacet2d(facetT *facet, vertexT **nextvertexp) {
  facetT *nextfacet;

  if (facet->toporient ^ qh_ORIENTclock) {
    *nextvertexp= SETfirstt_(facet->vertices, vertexT);
    nextfacet= SETfirstt_(facet->neighbors, facetT);
  }else {
    *nextvertexp= SETsecondt_(facet->vertices, vertexT);
    nextfacet= SETsecondt_(facet->neighbors, facetT);
  }
  return nextfacet;
} /* nextfacet2d */

/*---------------------------------

  qh_nextridge3d( atridge, facet, &vertex )
    return next ridge and vertex for a 3d facet
    returns NULL on error
    [for QhullFacet::nextRidge3d] Does not call qh_errexit nor access qh_qh.

  notes:
    in qh_ORIENTclock order
    this is a O(n^2) implementation to trace all ridges
    be sure to stop on any 2nd visit
    same as QhullRidge::nextRidge3d
    does not use qh_qh or qh_errexit [QhullFacet.cpp]

  design:
    for each ridge
      exit if it is the ridge after atridge
*/
ridgeT *qh_nextridge3d(ridgeT *atridge, facetT *facet, vertexT **vertexp) {
  vertexT *atvertex, *vertex, *othervertex;
  ridgeT *ridge, **ridgep;

  if ((atridge->top == facet) ^ qh_ORIENTclock)
    atvertex= SETsecondt_(atridge->vertices, vertexT);
  else
    atvertex= SETfirstt_(atridge->vertices, vertexT);
  FOREACHridge_(facet->ridges) {
    if (ridge == atridge)
      continue;
    if ((ridge->top == facet) ^ qh_ORIENTclock) {
      othervertex= SETsecondt_(ridge->vertices, vertexT);
      vertex= SETfirstt_(ridge->vertices, vertexT);
    }else {
      vertex= SETsecondt_(ridge->vertices, vertexT);
      othervertex= SETfirstt_(ridge->vertices, vertexT);
    }
    if (vertex == atvertex) {
      if (vertexp)
        *vertexp= othervertex;
      return ridge;
    }
  }
  return NULL;
} /* nextridge3d */

/*---------------------------------

  qh_opposite_vertex( facetA, neighbor )
    return the opposite vertex in facetA to neighbor

*/
vertexT *qh_opposite_vertex(facetT *facetA,  facetT *neighbor) {
    vertexT *opposite= NULL;
    facetT *facet;
    int facet_i, facet_n;

    if (facetA->simplicial) {
      FOREACHfacet_i_(facetA->neighbors) {
        if (facet == neighbor) {
          opposite= SETelemt_(facetA->vertices, facet_i, vertexT);
          break;
        }
      }
    }
    if (!opposite) {
      qh_fprintf(qh ferr, 6396, "qhull internal error (qh_opposite_vertex): opposite vertex in facet f%d to neighbor f%d is not defined.  Either is facet is not simplicial or neighbor not found\n",
        facetA->id, neighbor->id);
      qh_errexit2(qh_ERRqhull, facetA, neighbor);
    }
    return opposite;
} /* opposite_vertex */

/*---------------------------------

  qh_outcoplanar()
    move points from all facets' outsidesets to their coplanarsets

  notes:
    for post-processing under qh.NARROWhull

  design:
    for each facet
      for each outside point for facet
        partition point into coplanar set
*/
void qh_outcoplanar(void /* facet_list */) {
  pointT *point, **pointp;
  facetT *facet;
  realT dist;

  trace1((qh ferr, 1033, "qh_outcoplanar: move outsideset to coplanarset for qh NARROWhull\n"));
  FORALLfacets {
    FOREACHpoint_(facet->outsideset) {
      qh num_outside--;
      if (qh KEEPcoplanar || qh KEEPnearinside) {
        qh_distplane(point, facet, &dist);
        zinc_(Zpartition);
        qh_partitioncoplanar(point, facet, &dist, qh findbestnew);
      }
    }
    qh_setfree(&facet->outsideset);
  }
} /* outcoplanar */

/*---------------------------------

  qh_point( id )
    return point for a point id, or NULL if unknown

  alternative code:
    return((pointT *)((unsigned long)qh.first_point
           + (unsigned long)((id)*qh.normal_size)));
*/
pointT *qh_point(int id) {

  if (id < 0)
    return NULL;
  if (id < qh num_points)
    return qh first_point + id * qh hull_dim;
  id -= qh num_points;
  if (id < qh_setsize(qh other_points))
    return SETelemt_(qh other_points, id, pointT);
  return NULL;
} /* point */

/*---------------------------------

  qh_point_add( set, point, elem )
    stores elem at set[point.id]

  returns:
    access function for qh_pointfacet and qh_pointvertex

  notes:
    checks point.id
*/
void qh_point_add(setT *set, pointT *point, void *elem) {
  int id, size;

  SETreturnsize_(set, size);
  if ((id= qh_pointid(point)) < 0)
    qh_fprintf(qh ferr, 7067, "qhull internal warning (point_add): unknown point %p id %d\n",
      point, id);
  else if (id >= size) {
    qh_fprintf(qh ferr, 6160, "qhull internal error (point_add): point p%d is out of bounds(%d)\n",
             id, size);
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }else
    SETelem_(set, id)= elem;
} /* point_add */


/*---------------------------------

  qh_pointfacet()
    return temporary set of facet for each point
    the set is indexed by point id
    at most one facet per point, arbitrary selection

  notes:
    each point is assigned to at most one of vertices, coplanarset, or outsideset
    unassigned points are interior points or 
    vertices assigned to one of its facets
    coplanarset assigned to the facet
    outside set assigned to the facet
    NULL if no facet for point (inside)
      includes qh.GOODpointp

  access:
    FOREACHfacet_i_(facets) { ... }
    SETelem_(facets, i)

  design:
    for each facet
      add each vertex
      add each coplanar point
      add each outside point
*/
setT *qh_pointfacet(void /* qh.facet_list */) {
  int numpoints= qh num_points + qh_setsize(qh other_points);
  setT *facets;
  facetT *facet;
  vertexT *vertex, **vertexp;
  pointT *point, **pointp;

  facets= qh_settemp(numpoints);
  qh_setzero(facets, 0, numpoints);
  qh vertex_visit++;
  FORALLfacets {
    FOREACHvertex_(facet->vertices) {
      if (vertex->visitid != qh vertex_visit) {
        vertex->visitid= qh vertex_visit;
        qh_point_add(facets, vertex->point, facet);
      }
    }
    FOREACHpoint_(facet->coplanarset)
      qh_point_add(facets, point, facet);
    FOREACHpoint_(facet->outsideset)
      qh_point_add(facets, point, facet);
  }
  return facets;
} /* pointfacet */

/*---------------------------------

  qh_pointvertex( )
    return temporary set of vertices indexed by point id
    entry is NULL if no vertex for a point
      this will include qh.GOODpointp

  access:
    FOREACHvertex_i_(vertices) { ... }
    SETelem_(vertices, i)
*/
setT *qh_pointvertex(void /* qh.facet_list */) {
  int numpoints= qh num_points + qh_setsize(qh other_points);
  setT *vertices;
  vertexT *vertex;

  vertices= qh_settemp(numpoints);
  qh_setzero(vertices, 0, numpoints);
  FORALLvertices
    qh_point_add(vertices, vertex->point, vertex);
  return vertices;
} /* pointvertex */


/*---------------------------------

  qh_prependfacet( facet, facetlist )
    prepend facet to the start of a facetlist

  returns:
    increments qh.numfacets
    updates facetlist, qh.facet_list, facet_next

  notes:
    be careful of prepending since it can lose a pointer.
      e.g., can lose _next by deleting and then prepending before _next
*/
void qh_prependfacet(facetT *facet, facetT **facetlist) {
  facetT *prevfacet, *list;

  trace4((qh ferr, 4061, "qh_prependfacet: prepend f%d before f%d\n",
          facet->id, getid_(*facetlist)));
  if (!*facetlist)
    (*facetlist)= qh facet_tail;
  list= *facetlist;
  prevfacet= list->previous;
  facet->previous= prevfacet;
  if (prevfacet)
    prevfacet->next= facet;
  list->previous= facet;
  facet->next= *facetlist;
  if (qh facet_list == list)  /* this may change *facetlist */
    qh facet_list= facet;
  if (qh facet_next == list)
    qh facet_next= facet;
  *facetlist= facet;
  qh num_facets++;
} /* prependfacet */


/*---------------------------------

  qh_printhashtable( fp )
    print hash table to fp

  notes:
    not in I/O to avoid bringing io.c in

  design:
    for each hash entry
      if defined
        if unmatched or will merge (NULL, qh_MERGEridge, qh_DUPLICATEridge)
          print entry and neighbors
*/
void qh_printhashtable(FILE *fp) {
  facetT *facet, *neighbor;
  int id, facet_i, facet_n, neighbor_i= 0, neighbor_n= 0;
  vertexT *vertex, **vertexp;

  FOREACHfacet_i_(qh hash_table) {
    if (facet) {
      FOREACHneighbor_i_(facet) {
        if (!neighbor || neighbor == qh_MERGEridge || neighbor == qh_DUPLICATEridge)
          break;
      }
      if (neighbor_i == neighbor_n)
        continue;
      qh_fprintf(fp, 9283, "hash %d f%d ", facet_i, facet->id);
      FOREACHvertex_(facet->vertices)
        qh_fprintf(fp, 9284, "v%d ", vertex->id);
      qh_fprintf(fp, 9285, "\n neighbors:");
      FOREACHneighbor_i_(facet) {
        if (neighbor == qh_MERGEridge)
          id= -3;
        else if (neighbor == qh_DUPLICATEridge)
          id= -2;
        else
          id= getid_(neighbor);
        qh_fprintf(fp, 9286, " %d", id);
      }
      qh_fprintf(fp, 9287, "\n");
    }
  }
} /* printhashtable */

/*---------------------------------

  qh_printlists( )
    print out facet and vertex lists for debugging (without 'f/v' tags)

  notes:
    not in I/O to avoid bringing io.c in
*/
void qh_printlists(void) {
  facetT *facet;
  vertexT *vertex;
  int count= 0;

  qh_fprintf(qh ferr, 3062, "qh_printlists: max_outside %2.2g all facets:", qh max_outside);
  FORALLfacets{
    if (++count % 100 == 0)
      qh_fprintf(qh ferr, 8109, "\n     ");
    qh_fprintf(qh ferr, 8110, " %d", facet->id);
  }
    qh_fprintf(qh ferr, 8111, "\n  qh.visible_list f%d, newfacet_list f%d, facet_next f%d for qh_addpoint\n  qh.newvertex_list v%d all vertices:",
      getid_(qh visible_list), getid_(qh newfacet_list), getid_(qh facet_next), getid_(qh newvertex_list));
  count= 0;
  FORALLvertices{
    if (++count % 100 == 0)
      qh_fprintf(qh ferr, 8112, "\n     ");
    qh_fprintf(qh ferr, 8113, " %d", vertex->id);
  }
  qh_fprintf(qh ferr, 8114, "\n");
} /* printlists */

/*---------------------------------

  qh_replacefacetvertex( facet, oldvertex, newvertex )
    replace oldvertex with newvertex in f.vertices
    vertices are inverse sorted by vertex->id

  returns:
    toporient is flipped if an odd parity, position change

  notes:
    for simplicial facets in qh_rename_adjacentvertex
    see qh_addfacetvertex
*/
void qh_replacefacetvertex(facetT *facet, vertexT *oldvertex, vertexT *newvertex) {
  vertexT *vertex;
  facetT *neighbor;
  int vertex_i, vertex_n= 0;
  int old_i= -1, new_i= -1;

  trace3((qh ferr, 3038, "qh_replacefacetvertex: replace v%d with v%d in f%d\n", oldvertex->id, newvertex->id, facet->id));
  if (!facet->simplicial) {
    qh_fprintf(qh ferr, 6283, "qhull internal error (qh_replacefacetvertex): f%d is not simplicial\n", facet->id);
    qh_errexit(qh_ERRqhull, facet, NULL);
  }
  FOREACHvertex_i_(facet->vertices) {
    if (new_i == -1 && vertex->id < newvertex->id) {
      new_i= vertex_i;
    }else if (vertex->id == newvertex->id) {
      qh_fprintf(qh ferr, 6281, "qhull internal error (qh_replacefacetvertex): f%d already contains new v%d\n", facet->id, newvertex->id);
      qh_errexit(qh_ERRqhull, facet, NULL);
    }
    if (vertex->id == oldvertex->id) {
      old_i= vertex_i;
    }
  }
  if (old_i == -1) {
    qh_fprintf(qh ferr, 6282, "qhull internal error (qh_replacefacetvertex): f%d does not contain old v%d\n", facet->id, oldvertex->id);
    qh_errexit(qh_ERRqhull, facet, NULL);
  }
  if (new_i == -1) {
    new_i= vertex_n;
  }
  if (old_i < new_i)
    new_i--;
  if ((old_i & 0x1) != (new_i & 0x1))
    facet->toporient ^= 1;
  qh_setdelnthsorted(facet->vertices, old_i);
  qh_setaddnth(&facet->vertices, new_i, newvertex);
  neighbor= SETelemt_(facet->neighbors, old_i, facetT);
  qh_setdelnthsorted(facet->neighbors, old_i);
  qh_setaddnth(&facet->neighbors, new_i, neighbor);
} /* replacefacetvertex */

/*---------------------------------

  qh_resetlists( stats, qh_RESETvisible )
    reset newvertex_list, newfacet_list, visible_list, NEWfacets, NEWtentative
    if stats,
      maintains statistics
    if resetVisible, 
      visible_list is restored to facet_list
      otherwise, f.visible/f.replace is retained

  returns:
    newvertex_list, newfacet_list, visible_list are NULL

  notes:
    To delete visible facets, call qh_deletevisible before qh_resetlists
*/
void qh_resetlists(boolT stats, boolT resetVisible /* qh.newvertex_list newfacet_list visible_list */) {
  vertexT *vertex;
  facetT *newfacet, *visible;
  int totnew=0, totver=0;

  trace2((qh ferr, 2066, "qh_resetlists: reset newvertex_list v%d, newfacet_list f%d, visible_list f%d, facet_list f%d next f%d vertex_list v%d -- NEWfacets? %d, NEWtentative? %d, stats? %d\n",
    getid_(qh newvertex_list), getid_(qh newfacet_list), getid_(qh visible_list), getid_(qh facet_list), getid_(qh facet_next), getid_(qh vertex_list), qh NEWfacets, qh NEWtentative, stats));
  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->newfacet= False;
  qh newvertex_list= NULL;
  qh first_newfacet= 0;
  FORALLnew_facets {
    newfacet->newfacet= False;
    newfacet->dupridge= False;
  }
  qh newfacet_list= NULL;
  if (resetVisible) {
    FORALLvisible_facets {
      visible->f.replace= NULL;
      visible->visible= False;
    }
    qh num_visible= 0;
  }
  qh visible_list= NULL; 
  qh NEWfacets= False;
  qh NEWtentative= False;
} /* resetlists */

/*---------------------------------

  qh_setvoronoi_all( )
    compute Voronoi centers for all facets
    includes upperDelaunay facets if qh.UPPERdelaunay ('Qu')

  returns:
    facet->center is the Voronoi center

  notes:
    unused/untested code: please email bradb@shore.net if this works ok for you

  use:
    FORALLvertices {...} to locate the vertex for a point.
    FOREACHneighbor_(vertex) {...} to visit the Voronoi centers for a Voronoi cell.
*/
void qh_setvoronoi_all(void) {
  facetT *facet;

  qh_clearcenters(qh_ASvoronoi);
  qh_vertexneighbors();

  FORALLfacets {
    if (!facet->normal || !facet->upperdelaunay || qh UPPERdelaunay) {
      if (!facet->center)
        facet->center= qh_facetcenter(facet->vertices);
    }
  }
} /* setvoronoi_all */

#ifndef qh_NOmerge
/*---------------------------------

  qh_triangulate()
    triangulate non-simplicial facets on qh.facet_list,
    if qh VORONOI, sets Voronoi centers of non-simplicial facets
    nop if hasTriangulation

  returns:
    all facets simplicial
    each tricoplanar facet has ->f.triowner == owner of ->center,normal,etc.
    resets qh.newfacet_list and visible_list

  notes:
    called by qh_prepare_output and user_eg2.c
    call after qh_check_output since may switch to Voronoi centers, and qh_checkconvex skips f.tricoplanar facets
    Output may overwrite ->f.triowner with ->f.area
    while running, 'triangulated_facet_list' is a list of
       one non-simplicial facet followed by its 'f.tricoplanar' triangulated facets
    See qh_buildcone
*/
void qh_triangulate(void /* qh.facet_list */) {
  facetT *facet, *nextfacet, *owner;
  facetT *neighbor, *visible= NULL, *facet1, *facet2, *triangulated_facet_list= NULL;
  facetT *orig_neighbor= NULL, *otherfacet;
  vertexT *triangulated_vertex_list= NULL;
  mergeT *merge;
  mergeType mergetype;
  int neighbor_i, neighbor_n;
  boolT onlygood= qh ONLYgood;

  if (qh hasTriangulation)
      return;
  trace1((qh ferr, 1034, "qh_triangulate: triangulate non-simplicial facets\n"));
  if (qh hull_dim == 2)
    return;
  if (qh VORONOI) {  /* otherwise lose Voronoi centers [could rebuild vertex set from tricoplanar] */
    qh_clearcenters(qh_ASvoronoi);
    qh_vertexneighbors();
  }
  qh ONLYgood= False; /* for makenew_nonsimplicial */
  qh visit_id++;
  qh_initmergesets(/* qh.facet_mergeset,degen_mergeset,vertex_mergeset */);
  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 (!triangulated_facet_list)
      triangulated_facet_list= facet;  /* will be first triangulated facet */
    qh_triangulate_facet(facet, &triangulated_vertex_list); /* qh_resetlists ! */
  }
  /* qh_checkpolygon invalid due to f.visible without qh.visible_list */
  trace2((qh ferr, 2047, "qh_triangulate: delete null facets from facetlist f%d.  A null facet has the same first (apex) and second vertices\n", getid_(triangulated_facet_list)));
  for (facet=triangulated_facet_list; facet && facet->next; facet= nextfacet) {
    nextfacet= facet->next;
    if (facet->visible)
      continue;
    if (facet->ridges) {
      if (qh_setsize(facet->ridges) > 0) {
        qh_fprintf(qh ferr, 6161, "qhull internal 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); /* will delete facet */
    }
  }
  trace2((qh ferr, 2048, "qh_triangulate: delete %d or more mirrored facets.  Mirrored facets have the same vertices due to a null facet\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->mergetype;
    qh_memfree(merge, (int)sizeof(mergeT));
    if (mergetype == MRGmirror) {
      zinc_(Ztrimirror);
      qh_triangulate_mirror(facet1, facet2);  /* will delete both facets */
    }
  }
  qh_freemergesets();
  trace2((qh ferr, 2049, "qh_triangulate: update neighbor lists for vertices from v%d\n", getid_(triangulated_vertex_list)));
  qh newvertex_list= triangulated_vertex_list;  /* all vertices of triangulated facets */
  qh visible_list= NULL;
  qh_update_vertexneighbors(/* qh.newvertex_list, empty newfacet_list and visible_list */);
  qh_resetlists(False, !qh_RESETvisible /* qh.newvertex_list, empty newfacet_list and visible_list */);

  trace2((qh ferr, 2050, "qh_triangulate: identify degenerate tricoplanar facets from f%d\n", getid_(triangulated_facet_list)));
  trace2((qh ferr, 2051, "qh_triangulate: and replace facet->f.triowner with tricoplanar facets that own center, normal, etc.\n"));
  FORALLfacet_(triangulated_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;
          }
        }
      }
    }
  }
  if (qh IStracing >= 4)
    qh_printlists();
  trace2((qh ferr, 2052, "qh_triangulate: delete visible facets -- non-simplicial, null, and mirrored facets\n"));
  owner= NULL;
  visible= NULL;
  for (facet=triangulated_facet_list; facet && facet->next; facet= nextfacet) { 
    /* deleting facets, triangulated_facet_list is no longer valid */
    nextfacet= facet->next;
    if (facet->visible) {
      if (facet->tricoplanar) { /* a null or mirrored facet */
        qh_delfacet(facet);
        qh num_visible--;
      }else {  /* a non-simplicial facet followed by its tricoplanars */
        if (visible && !owner) {
          /*  RBOX 200 s D5 t1001471447 | QHULL Qt C-0.01 Qx Qc Tv Qt -- f4483 had 6 vertices/neighbors and 8 ridges */
          trace2((qh ferr, 2053, "qh_triangulate: delete f%d.  All tricoplanar facets degenerate for non-simplicial facet\n",
                       visible->id));
          qh_delfacet(visible);
          qh num_visible--;
        }
        visible= facet;
        owner= NULL;
      }
    }else if (facet->tricoplanar) {
      if (facet->f.triowner != visible || visible==NULL) {
        qh_fprintf(qh ferr, 6162, "qhull internal 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, visible!=0 by QH6162 */
        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--;
      }
    }
    facet->degenerate= False; /* reset f.degenerate set by qh_triangulate*/
  }
  if (visible && !owner) {
    trace2((qh ferr, 2054, "qh_triangulate: all tricoplanar facets degenerate for last non-simplicial facet f%d\n",
                 visible->id));
    qh_delfacet(visible);
    qh num_visible--;
  }
  qh ONLYgood= onlygood; /* restore value */
  if (qh CHECKfrequently)
    qh_checkpolygon(qh facet_list);
  qh hasTriangulation= True;
} /* triangulate */


/*---------------------------------

  qh_triangulate_facet( facetA, &firstVertex )
    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:
      only called by qh_triangulate
      qh_makenew_nonsimplicial uses neighbor->seen for the same
      if qh.TRInormals, newfacet->normal will need qh_free
        if qh.TRInormals and qh_AScentrum, newfacet->center will need qh_free
        keepcentrum is also set on Zwidefacet in qh_mergefacet
        freed by qh_clearcenters

  see also:
      qh_addpoint() -- add a point
      qh_makenewfacets() -- construct a cone of facets for a new vertex

  design:
      if qh_ASvoronoi,
         compute Voronoi center (facet->center)
      select first vertex (highest ID to preserve ID ordering of ->vertices)
      triangulate from vertex to ridges
      copy facet->center, normal, offset
      update vertex neighbors
*/
void qh_triangulate_facet(facetT *facetA, vertexT **first_vertex) {
  facetT *newfacet;
  facetT *neighbor, **neighborp;
  vertexT *apex;
  int numnew=0;

  trace3((qh ferr, 3020, "qh_triangulate_facet: triangulate facet f%d\n", facetA->id));

  qh first_newfacet= qh facet_id;
  if (qh IStracing >= 4)
    qh_printfacet(qh ferr, facetA);
  FOREACHneighbor_(facetA) {
    neighbor->seen= False;
    neighbor->coplanarhorizon= 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 visible_list= qh newfacet_list= qh facet_tail;
  facetA->visitid= qh visit_id;
  apex= SETfirstt_(facetA->vertices, vertexT);
  qh_makenew_nonsimplicial(facetA, apex, &numnew);
  qh_willdelete(facetA, NULL);
  FORALLnew_facets {
    newfacet->tricoplanar= True;
    newfacet->f.trivisible= facetA;
    newfacet->degenerate= False;
    newfacet->upperdelaunay= facetA->upperdelaunay;
    newfacet->good= facetA->good;
    if (qh TRInormals) { /* 'Q11' triangulate duplicates ->normal and ->center */
      newfacet->keepcentrum= True;
      if(facetA->normal){
        newfacet->normal= (double *)qh_memalloc(qh normal_size);
        memcpy((char *)newfacet->normal, facetA->normal, (size_t)qh normal_size);
      }
      if (qh CENTERtype == qh_AScentrum)
        newfacet->center= qh_getcentrum(newfacet);
      else if (qh CENTERtype == qh_ASvoronoi && facetA->center){
        newfacet->center= (double *)qh_memalloc(qh center_size);
        memcpy((char *)newfacet->center, facetA->center, (size_t)qh center_size);
      }
    }else {
      newfacet->keepcentrum= False;
      /* one facet will have keepcentrum=True at end of qh_triangulate */
      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 */); /* ignore returned value, maxdupdist */ 
  zinc_(Ztricoplanar);
  zadd_(Ztricoplanartot, numnew);
  zmax_(Ztricoplanarmax, numnew);
  if (!(*first_vertex))
    (*first_vertex)= qh newvertex_list;
  qh newvertex_list= NULL;
  qh visible_list= NULL;
  /* only update v.neighbors for qh.newfacet_list.  qh.visible_list and qh.newvertex_list are NULL */
  qh_update_vertexneighbors(/* qh.newfacet_list */);
  qh_resetlists(False, !qh_RESETvisible /* qh.newfacet_list */);
} /* triangulate_facet */

/*---------------------------------

  qh_triangulate_link(oldfacetA, facetA, oldfacetB, facetB)
    relink facetA to facetB via null oldfacetA or mirrored oldfacetA and oldfacetB
  returns:
    if neighbors are already linked, will merge as MRGmirror (qh.degen_mergeset, 4-d and up)
*/
void qh_triangulate_link(facetT *oldfacetA, facetT *facetA, facetT *oldfacetB, facetT *facetB) {
  int errmirror= False;

  if (oldfacetA == oldfacetB) {
    trace3((qh ferr, 3052, "qh_triangulate_link: relink neighbors f%d and f%d of null facet f%d\n",
      facetA->id, facetB->id, oldfacetA->id));
  }else {
    trace3((qh ferr, 3021, "qh_triangulate_link: relink neighbors f%d and f%d of mirrored facets f%d and f%d\n",
      facetA->id, facetB->id, oldfacetA->id, oldfacetB->id));
  }
  if (qh_setin(facetA->neighbors, facetB)) {
    if (!qh_setin(facetB->neighbors, facetA))
      errmirror= True;
    else if (!facetA->redundant || !facetB->redundant || !qh_hasmerge(qh degen_mergeset, MRGmirror, facetA, facetB))
      qh_appendmergeset(facetA, facetB, MRGmirror, 0.0, 1.0);
  }else if (qh_setin(facetB->neighbors, facetA))
    errmirror= True;
  if (errmirror) {
    qh_fprintf(qh ferr, 6163, "qhull internal error (qh_triangulate_link): neighbors f%d and f%d do not match for null facet or mirrored facets f%d and f%d\n",
       facetA->id, facetB->id, oldfacetA->id, oldfacetB->id);
    qh_errexit2(qh_ERRqhull, facetA, facetB);
  }
  qh_setreplace(facetB->neighbors, oldfacetB, facetA);
  qh_setreplace(facetA->neighbors, oldfacetA, facetB);
} /* triangulate_link */

/*---------------------------------

  qh_triangulate_mirror(facetA, facetB)
    delete two mirrored facets identified by qh_triangulate_null() and itself
      a mirrored facet shares the same vertices of a logical ridge
  design:
    since a null facet duplicates the first two vertices, the opposing neighbors absorb the null facet
    if they are already neighbors, the opposing neighbors become MRGmirror facets
*/
void qh_triangulate_mirror(facetT *facetA, facetT *facetB) {
  facetT *neighbor, *neighborB;
  int neighbor_i, neighbor_n;

  trace3((qh ferr, 3022, "qh_triangulate_mirror: delete mirrored facets f%d and f%d and link their neighbors\n",
         facetA->id, facetB->id));
  FOREACHneighbor_i_(facetA) {
    neighborB= SETelemt_(facetB->neighbors, neighbor_i, facetT);
    if (neighbor == facetB && neighborB == facetA)
      continue; /* occurs twice */
    else if (neighbor->redundant && neighborB->redundant) { /* also mirrored facets (D5+) */
      if (qh_hasmerge(qh degen_mergeset, MRGmirror, neighbor, neighborB))
        continue;
    }
    if (neighbor->visible && neighborB->visible) /* previously deleted as mirrored facets */
      continue;
    qh_triangulate_link(facetA, neighbor, facetB, neighborB);
  }
  qh_willdelete(facetA, NULL);
  qh_willdelete(facetB, NULL);
} /* triangulate_mirror */

/*---------------------------------

  qh_triangulate_null(facetA)
    remove null facetA from qh_triangulate_facet()
      a null facet has vertex #1 (apex) == vertex #2
  returns:
    adds facetA to ->visible for deletion after qh_update_vertexneighbors
    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 will be merged (MRGmirror)
*/
void qh_triangulate_null(facetT *facetA) {
  facetT *neighbor, *otherfacet;

  trace3((qh ferr, 3023, "qh_triangulate_null: delete null facet f%d\n", facetA->id));
  neighbor= SETfirstt_(facetA->neighbors, facetT);
  otherfacet= SETsecondt_(facetA->neighbors, facetT);
  qh_triangulate_link(facetA, neighbor, facetA, otherfacet);
  qh_willdelete(facetA, NULL);
} /* triangulate_null */

#else /* qh_NOmerge */
void qh_triangulate(void) {
}
#endif /* qh_NOmerge */

/*---------------------------------

  qh_vertexintersect( verticesA, verticesB )
    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:
    only called by qh_neighbor_intersections
    if !qh.QHULLfinished, non-simplicial facets may have f.vertices with extraneous vertices
      cleaned by qh_remove_extravertices in qh_reduce_vertices
    could optimize by overwriting vertexsetA
*/
void qh_vertexintersect(setT **vertexsetA, setT *vertexsetB) {
  setT *intersection;

  intersection= qh_vertexintersect_new(*vertexsetA, vertexsetB);
  qh_settempfree(vertexsetA);
  *vertexsetA= intersection;
  qh_settemppush(intersection);
} /* vertexintersect */

/*---------------------------------

  qh_vertexintersect_new( verticesA, verticesB )
    intersects two vertex sets (inverse id ordered)

  returns:
    a new set

  notes:
    called by qh_checkfacet, qh_vertexintersect, qh_rename_sharedvertex, qh_findbest_pinchedvertex, qh_neighbor_intersections
    if !qh.QHULLfinished, non-simplicial facets may have f.vertices with extraneous vertices
       cleaned by qh_remove_extravertices in qh_reduce_vertices
*/
setT *qh_vertexintersect_new(setT *vertexsetA, setT *vertexsetB) {
  setT *intersection= qh_setnew(qh hull_dim - 1);
  vertexT **vertexA= SETaddr_(vertexsetA, vertexT);
  vertexT **vertexB= SETaddr_(vertexsetB, vertexT);

  while (*vertexA && *vertexB) {
    if (*vertexA  == *vertexB) {
      qh_setappend(&intersection, *vertexA);
      vertexA++; vertexB++;
    }else {
      if ((*vertexA)->id > (*vertexB)->id)
        vertexA++;
      else
        vertexB++;
    }
  }
  return intersection;
} /* vertexintersect_new */

/*---------------------------------

  qh_vertexneighbors( )
    for each vertex in qh.facet_list,
      determine its neighboring facets

  returns:
    sets qh.VERTEXneighbors
      nop if qh.VERTEXneighbors already set
      qh_addpoint() will maintain them

  notes:
    assumes all vertex->neighbors are NULL

  design:
    for each facet
      for each vertex
        append facet to vertex->neighbors
*/
void qh_vertexneighbors(void /* qh.facet_list */) {
  facetT *facet;
  vertexT *vertex, **vertexp;

  if (qh VERTEXneighbors)
    return;
  trace1((qh ferr, 1035, "qh_vertexneighbors: determining neighboring facets for each vertex\n"));
  qh vertex_visit++;
  FORALLfacets {
    if (facet->visible)
      continue;
    FOREACHvertex_(facet->vertices) {
      if (vertex->visitid != qh vertex_visit) {
        vertex->visitid= qh vertex_visit;
        vertex->neighbors= qh_setnew(qh hull_dim);
      }
      qh_setappend(&vertex->neighbors, facet);
    }
  }
  qh VERTEXneighbors= True;
} /* vertexneighbors */

/*---------------------------------

  qh_vertexsubset( vertexsetA, vertexsetB )
    returns True if vertexsetA is a subset of vertexsetB
    assumes vertexsets are sorted

  note:
    empty set is a subset of any other set
*/
boolT qh_vertexsubset(setT *vertexsetA, setT *vertexsetB) {
  vertexT **vertexA= (vertexT **) SETaddr_(vertexsetA, vertexT);
  vertexT **vertexB= (vertexT **) SETaddr_(vertexsetB, vertexT);

  while (True) {
    if (!*vertexA)
      return True;
    if (!*vertexB)
      return False;
    if ((*vertexA)->id > (*vertexB)->id)
      return False;
    if (*vertexA  == *vertexB)
      vertexA++;
    vertexB++;
  }
  return False; /* avoid warnings */
} /* vertexsubset */
qhull-2020.2/src/libqhull/qh-geom.htm0000644060175106010010000003263413716274032015655 0ustar  bbarber



geom.c, geom2.c -- geometric and floating point routines




Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


geom.c, geom2.c, random.c -- geometric and floating point routines

Geometrically, a vertex is a point with d coordinates and a facet is a halfspace. A halfspace is defined by an oriented hyperplane through the facet's vertices. A hyperplane is defined by d normalized coefficients and an offset. A point is above a facet if its distance to the facet is positive.

Qhull uses floating point coordinates for input points, vertices, halfspace equations, centrums, and an interior point.

Qhull may be configured for single precision or double precision floating point arithmetic (see realT ).

Each floating point operation may incur round-off error (see Merge). The maximum error for distance computations is determined at initialization. The roundoff error in halfspace computation is accounted for by computing the distance from vertices to the halfspace.

Copyright © 1995-2020 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to geom.c, geom2.c, geom.h, random.c, random.h

»geometric data types and constants

  • coordT coordinates and coefficients are stored as realT
  • pointT a point is an array of DIM3 coordinates

»mathematical macros

  • fabs_ returns the absolute value of a
  • fmax_ returns the maximum value of a and b
  • fmin_ returns the minimum value of a and b
  • maximize_ maximize a value
  • minimize_ minimize a value
  • det2_ compute a 2-d determinate
  • det3_ compute a 3-d determinate
  • dX, dY, dZ compute the difference between two coordinates

»mathematical functions

»computational geometry functions

»point array functions

»geometric facet functions

»geometric roundoff functions

  • qh_detjoggle determine default joggle for points and distance roundoff error
  • qh_detmaxoutside determine qh.MAXoutside target for qh_RATIO... tests
  • qh_detroundoff determine maximum roundoff error and other precision constants
  • qh_distround compute maximum roundoff error due to a distance computation to a normalized hyperplane
  • qh_divzero divide by a number that is nearly zero
  • qh_maxouter return maximum outer plane
  • qh_outerinner return actual outer and inner planes


Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

qhull-2020.2/src/libqhull/qh-globa.htm0000644060175106010010000001756413716274067016027 0ustar bbarber global.c -- global variables and their functions

Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


global.c -- global variables and their functions

Qhull uses a global data structure, qh, to store globally defined constants, lists, sets, and variables. This allows multiple instances of Qhull to execute at the same time. The structure may be statically allocated or dynamically allocated with malloc(). See QHpointer.

Copyright © 1995-2020 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to global.c and libqhull.h

»Qhull's global variables

»Global variable and initialization routines


Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

qhull-2020.2/src/libqhull/qh-io.htm0000644060175106010010000003367113716274121015336 0ustar bbarber io.c -- input and output operations

Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


io.c -- input and output operations

Qhull provides a wide range of input and output options. To organize the code, most output formats use the same driver:

    qh_printbegin( fp, format, facetlist, facets, printall );

    FORALLfacet_( facetlist )
      qh_printafacet( fp, format, facet, printall );

    FOREACHfacet_( facets )
      qh_printafacet( fp, format, facet, printall );

    qh_printend( fp, format );

Note the 'printall' flag. It selects whether or not qh_skipfacet() is tested.

Copyright © 1995-2020 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to io.c and io.h

»io.h constants and types

»User level functions

»Print functions for all output formats

»Text output functions

»Text utility functions

»Geomview output functions

»Geomview utility functions


Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

qhull-2020.2/src/libqhull/qh-mem.htm0000644060175106010010000001422113716274264015503 0ustar bbarber mem.c -- memory operations

Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


mem.c -- memory operations

Qhull uses quick-fit memory allocation. It maintains a set of free lists for a variety of small allocations. A small request returns a block from the best fitting free list. If the free list is empty, Qhull allocates a block from a reserved buffer.

Use 'T5' to trace memory allocations.

Copyright © 1995-2020 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to mem.c and mem.h

»mem.h data types and constants

  • ptr_intT for casting a void* to an integer-type
  • qhmemT global memory structure for mem.c
  • qh_NOmem disable memory allocation

»mem.h macros

»User level functions

»Initialization and termination functions


Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

qhull-2020.2/src/libqhull/qh-merge.htm0000644060175106010010000004674113716274264016040 0ustar bbarber merge.c -- facet merge operations

Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


merge.c -- facet merge operations

Qhull handles precision problems by merged facets or joggled input. Except for redundant vertices, it corrects a problem by merging two facets. When done, all facets are clearly convex. See Imprecision in Qhull for further information.

Users may joggle the input ('QJn') instead of merging facets.

Qhull detects and corrects the following problems:

  • More than two facets meeting at a ridge. When Qhull creates facets, it creates an even number of facets for each ridge. A convex hull always has two facets for each ridge. More than two facets may be created if non-adjacent facets share a subridge. This is called a dupridge. In 2-d, a dupridge would create a loop of facets. See 'pinched vertices' below for the resolution of a dupridge.
  • A facet contained in another facet. Facet merging may leave all vertices of one facet as a subset of the vertices of another facet. This is called a redundant facet.
  • A facet with fewer than three neighbors. Facet merging may leave a facet with one or two neighbors. This is called a degenerate facet.
  • A facet with flipped orientation. A facet's hyperplane may define a halfspace that does not include the interior point.This is called a flipped facet.
  • A coplanar horizon facet. A newly processed point may be coplanar with an horizon facet. Qhull creates a new facet without a hyperplane. It links new facets for the same horizon facet together. This is called a samecycle. The new facet or samecycle is merged into the horizon facet.
  • Concave facets. A facet's centrum may be above a neighboring facet. If so, the facets meet at a concave angle.
  • Coplanar facets. A facet's centrum may be coplanar with a neighboring facet (i.e., it is neither clearly below nor clearly above the facet's hyperplane). Qhull removes coplanar facets in independent sets sorted by angle.
  • Redundant vertex. A vertex may have fewer than three neighboring facets. If so, it is redundant and may be renamed to an adjacent vertex without changing the topological structure.This is called a redundant vertex.
  • Pinched vertices. Nearly adjacent vertices may allow a dupridge that connects more than two new facets. A pinched vertex is the nearest horizon vertex that is a neighbor of a dupridge vertex. In 4-D and higher, both vertices may be in the same dupridge. If the vertices are in new facets with inverse orientation, the facets cannot be merged. If so, qhull merges the pinched vertices and recreates the cone of new facets. For a discussion, see 'Nearly adjacent vertices within 1e-13' in Limitations of merged facets.

Copyright © 1995-2020 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to merge.c and merge.h

»merge.h data types, macros, and global sets

  • mergeT structure to identify a merge of two facets
  • FOREACHmerge_ assign 'merge' to each merge in mergeset
  • FOREACHmergeA_ assign 'mergeA' to each merge in mergeset
  • FOREACHmerge_i_ assign 'merge' and 'merge_i' to each merge in mergeset
  • qh global sets qh.facet_mergeset contains non-convex merges while qh.degen_mergeset contains degenerate and redundant facets

»merge.h constants

»top-level merge functions

»functions for identifying merges

»functions for determining the best merge

»functions for merging facets

»functions for merging a cycle of facets

If a point is coplanar with an horizon facet, the corresponding new facets are linked together (a samecycle) for merging.

»functions for pinched vertices of dupridges

»functions for renaming a vertex

»functions for identifying vertices for renaming

»functions for check and trace


Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

qhull-2020.2/src/libqhull/qh-poly.htm0000644060175106010010000005333213716274264015716 0ustar bbarber poly.c, poly2.c -- polyhedron operations

Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


poly.c, poly2.c -- polyhedron operations

Qhull uses dimension-free terminology. Qhull builds a polyhedron in dimension d. A polyhedron is a simplicial complex of faces with geometric information for the top and bottom-level faces. A (d-1)-face is a facet, a (d-2)-face is a ridge, and a 0-face is a vertex. For example in 3-d, a facet is a polygon and a ridge is an edge. A facet is built from a ridge (the base) and a vertex (the apex). See Qhull's data structures.

Qhull's primary data structure is a polyhedron. A polyhedron is a list of facets. Each facet has a set of neighboring facets and a set of vertices. Each facet has a hyperplane. For example, a tetrahedron has four facets. If its vertices are a, b, c, d, and its facets are 1, 2, 3, 4, the tetrahedron is

  • facet 1
    • vertices: b c d
    • neighbors: 2 3 4
  • facet 2
    • vertices: a c d
    • neighbors: 1 3 4
  • facet 3
    • vertices: a b d
    • neighbors: 1 2 4
  • facet 4
    • vertices: a b c
    • neighbors: 1 2 3

A facet may be simplicial or non-simplicial. In 3-d, a simplicial facet has three vertices and three neighbors. A nonsimplicial facet has more than three vertices and more than three neighbors. A nonsimplicial facet has a set of ridges and a centrum.

A simplicial facet has an orientation. An orientation is either top or bottom. The flag, facet->toporient, defines the orientation of the facet's vertices. For example in 3-d, 'top' is left-handed orientation (i.e., the vertex order follows the direction of the left-hand fingers when the thumb is pointing away from the center). Except for axis-parallel facets in 5-d and higher, topological orientation determines the geometric orientation of the facet's hyperplane.

A nonsimplicial facet is due to merging two or more facets. The facet's ridge set determine a simplicial decomposition of the facet. Each ridge is a 1-face (i.e., it has two vertices and two neighboring facets). The orientation of a ridge is determined by the order of the neighboring facets. The flag, facet->toporient,is ignored.

A nonsimplicial facet has a centrum for testing convexity. A centrum is a point on the facet's hyperplane that is near the center of the facet. Except for large facets, it is the arithmetic average of the facet's vertices.

A nonsimplicial facet is an approximation that is defined by offsets from the facet's hyperplane. When Qhull finishes, the outer plane is above all points while the inner plane is below the facet's vertices. This guarantees that any exact convex hull passes between the inner and outer planes. The outer plane is defined by facet->maxoutside while the inner plane is computed from the facet's vertices.

Qhull 3.1 includes triangulation of non-simplicial facets ('Qt'). These facets, called tricoplanar, share the same normal. centrum, and Voronoi center. One facet (keepcentrum) owns these data structures. While tricoplanar facets are more accurate than the simplicial facets from joggled input, they may have zero area or flipped orientation.

Copyright © 1995-2020 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to poly.c, poly2.c, poly.h, and libqhull.h

»Data types and global lists for polyhedrons

»poly.h constants

  • ALGORITHMfault flag to not report errors in qh_checkconvex()
  • DATAfault flag to report errors in qh_checkconvex()
  • DUPLICATEridge special value for facet->neighbor to indicate a duplicate ridge
  • MERGEridge special value for facet->neighbor to indicate a merged ridge

»Global FORALL macros

»FORALL macros

»FOREACH macros

»Indexed FOREACH macros

  • FOREACHfacet_i_ assign 'facet' and 'facet_i' to each facet in facet set
  • FOREACHneighbor_i_ assign 'neighbor' and 'neighbor_i' to each facet in facet->neighbors or vertex->neighbors
  • FOREACHpoint_i_ assign 'point' and 'point_i' to each point in points set
  • FOREACHridge_i_ assign 'ridge' and 'ridge_i' to each ridge in ridges set
  • FOREACHvertex_i_ assign 'vertex' and 'vertex_i' to each vertex in vertices set
  • FOREACHvertexreverse12_ assign 'vertex' to each vertex in vertex set; reverse the order of first two vertices

»Other macros for polyhedrons

  • getid_ return ID for a facet, ridge, or vertex
  • otherfacet_ return neighboring facet for a ridge in a facet

»Facetlist functions

»Facet functions

»Vertex, ridge, and point functions

»Hashtable functions

»Allocation and deallocation functions

»Check functions


Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

qhull-2020.2/src/libqhull/qh-qhull.htm0000644060175106010010000003107313716274264016056 0ustar bbarber libqhull.c -- top-level functions and basic data types

Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


libqhull.c -- top-level functions and basic data types

Qhull implements the Quickhull algorithm for computing the convex hull. The Quickhull algorithm combines two well-known algorithms: the 2-d quickhull algorithm and the n-d beneath-beyond algorithm. See Description of Qhull.

This section provides an index to the top-level functions and base data types. The top-level header file, libqhull.h, contains prototypes for these functions.

Copyright © 1995-2020 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to libqhull.c, libqhull.h, and unix.c

»libqhull.h and unix.c data types and constants

  • flagT Boolean flag as a bit
  • boolT boolean value, either True or False
  • CENTERtype to distinguish facet->center
  • qh_PRINT output formats for printing (qh.PRINTout)
  • qh_ALL argument flag for selecting everything
  • qh_ERR Qhull exit status codes for indicating errors
  • qh_FILEstderr Fake stderr to distinguish error output from normal output [C++ only]
  • qh_prompt version and long prompt for Qhull
  • qh_prompt2 synopsis for Qhull
  • qh_prompt3 concise prompt for Qhull
  • qh_version version stamp

»libqhull.h other macros

  • traceN print trace message if qh.IStracing >= N.
  • QHULL_UNUSED declare an unused variable to avoid warnings.

»Quickhull routines in call order

»Top-level routines for initializing and terminating Qhull (in other modules)

»Top-level routines for reading and modifying the input (in other modules)

»Top-level routines for calling Qhull (in other modules)

»Top-level routines for returning results (in other modules)

»Top-level routines for testing and debugging (in other modules)


Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

qhull-2020.2/src/libqhull/qh-set.htm0000644060175106010010000003167713716274264015536 0ustar bbarber qset.c -- set data type and operations

Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


qset.c -- set data type and operations

Qhull's data structures are constructed from sets. The functions and macros in qset.c construct, iterate, and modify these sets. They are the most frequently called functions in Qhull. For this reason, efficiency is the primary concern.

In Qhull, a set is represented by an unordered array of pointers with a maximum size and a NULL terminator (setT). Most sets correspond to mathematical sets (i.e., the pointers are unique). Some sets are sorted to enforce uniqueness. Some sets are ordered. For example, the order of vertices in a ridge determine the ridge's orientation. If you reverse the order of adjacent vertices, the orientation reverses. Some sets are not mathematical sets. They may be indexed as an array and they may include NULL pointers.

The most common operation on a set is to iterate its members. This is done with a 'FOREACH...' macro. Each set has a custom macro. For example, 'FOREACHvertex_' iterates over a set of vertices. Each vertex is assigned to the variable 'vertex' from the pointer 'vertexp'.

Most sets are constructed by appending elements to the set. The last element of a set is either NULL or the index of the terminating NULL for a partially full set. If a set is full, appending an element copies the set to a larger array.

Copyright © 1995-2020 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to qset.c and qset.h

»Data types and constants

  • SETelemsize size of a set element in bytes
  • setT a set with a maximum size and a current size
  • qh global sets global sets for temporary sets, etc.

»FOREACH macros

»Access and size macros

»Internal macros

  • SETsizeaddr_ return pointer to end element of a set (indicates current size)

»address macros

  • SETaddr_ return address of a set's elements
  • SETelemaddr_ return address of the n'th element of a set
  • SETref_ l.h.s. for modifying the current element in a FOREACH iteration

»Allocation and deallocation functions

»Access and predicate functions

»Add functions

»Check and print functions

»Copy, compact, and zero functions

»Delete functions

»Temporary set functions


Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

qhull-2020.2/src/libqhull/qh-stat.htm0000644060175106010010000001572413716274264015711 0ustar bbarber stat.c -- statistical operations

Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


stat.c -- statistical operations

Qhull records many statistics. These functions and macros make it inexpensive to add a statistic.

As with Qhull's global variables, the statistics data structure is accessed by a macro, 'qhstat'. If qh_QHpointer is defined, the macro is 'qh_qhstat->', otherwise the macro is 'qh_qhstat.'. Statistics may be turned off in user.h. If so, all but the 'zz' statistics are ignored.

Copyright © 1995-2020 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to stat.c and stat.h

»stat.h types

  • intrealT union of integer and real
  • qhstat global data structure for statistics

»stat.h constants

  • qh_KEEPstatistics 0 turns off most statistics
  • Z..., W... integer (Z) and real (W) statistics
  • ZZstat Z.../W... statistics that remain defined if qh_KEEPstatistics=0
  • ztype zdoc, zinc, etc. for definining statistics

»stat.h macros

  • MAYdebugx called frequently for error trapping
  • zadd_/wadd_ add value to an integer or real statistic
  • zdef_ define a statistic
  • zinc_ increment an integer statistic
  • zmax_/wmax_ update integer or real maximum statistic
  • zmin_/wmin_ update integer or real minimum statistic
  • zval_/wval_ set or return value of a statistic

»stat.c functions


Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

qhull-2020.2/src/libqhull/qh-user.htm0000644060175106010010000003544313716274264015714 0ustar bbarber user.c -- user-definable operations

Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


user.c -- user-definable operations

This section contains functions and constants that the user may want to change.

Copyright © 1995-2020 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to user.c, usermem.c, userprintf.c, userprintf_rbox.c and user.h

»Qhull library constants

»user.h data types and configuration macros

»definition constants

  • qh_DEFAULTbox define default box size for rbox, 'Qbb', and 'QbB' (Geomview expects 0.5)
  • qh_INFINITE on output, indicates Voronoi center at infinity
  • qh_ORIENTclock define convention for orienting facets
  • qh_RANDOMdist for testing qh.DISTround (sets qh.RANDOMfactor for qh.RANDOMdist, same as option 'Rn')

»joggle constants

»performance related constants

»memory constants

»conditional compilation

  • compiler defined symbols, e.g., _STDC_ and _cplusplus
  • qh_COMPUTEfurthest compute furthest distance to an outside point instead of storing it with the facet
  • qh_KEEPstatistics enable statistic gathering and reporting with option 'Ts'
  • qh_MAXcheckpoint report up to qh_MAXcheckpoint errors per facet in qh_check_point ('Tv')
  • qh_MAXoutside record outer plane for each facet
  • qh_NOmerge disable facet merging
  • qh_NOtrace disable tracing with option 'T4'
  • qh_QHpointer access global data with pointer or static structure
  • qh_QUICKhelp use abbreviated help messages, e.g., for degenerate inputs

»merge constants

  • qh_BESTcentrum if many vertices for facet, qh_findbestneighbor tests centrums instead of vertices
  • qh_BESTnonconvex if many neighbors for facet, qh_findbestneighbor only tests nonconvex ridges
  • qh_COPLANARratio what is qh.MINvisible?
  • qh_DIMreduceBuild max dimension for vertex reduction
  • qh_DIMmergeVertex max dimension for vertex merging
  • qh_DISToutside when is a point clearly outside of a facet for qh_findbestnew and qh_partitionall
  • qh_MAXnarrow max. cosine for qh.NARROWhull
  • qh_MAXcoplanarcentrum if 'Qx' and many merges, use f.maxoutside for coplanarity test instead of qh.centrum_radius
  • qh_MAXnarrow max. cosine in initial hull that sets qh.NARROWhull
  • qh_MAXnewcentrum when does qh_reducevertices_centrum() reset the centrum?
  • qh_MAXnewmerges when does qh_merge_nonconvex() call qh_reducevertices_centrums?
  • qh_RATIOconcavehorizon ratio of horizon vertex distance to qh.max_outside for concave, twisted new facets in qh_test_nonsimplicial_merge
  • qh_RATIOconvexmerge ratio of vertex distance to qh.min_vertex for clearly convex new facets in qh_test_nonsimplicial_merge
  • qh_RATIOcoplanarapex ratio of best distance for coplanar apex vs. vertex merge in qh_getpinchedmerges
  • qh_RATIOcoplanaroutside ratio to repartition a coplanar point as an outside point in qh_partitioncoplanar and qh_check_maxout
  • qh_RATIOmaxsimplex ratio for searching all points in qh_maxsimplex
  • qh_RATIOnearinside ratio for retaining inside points for qh_check_maxout
  • qh_RATIOpinchedsubridge ratio to qh.ONEmerge to accept vertices in qh_findbest_pinchedvertex
  • qh_RATIOtrypinched ratio to qh.ONEmerge to try qh_getpinchedmerges in qh_buildcone_mergepinched
  • qh_RATIOtwisted maximum ratio to qh.ONEmerge to merge twisted facets in qh_merge_twisted
  • qh_SEARCHdist when is facet coplanar with the best facet for qh_findbesthorizon
  • qh_USEfindbestnew when to use qh_findbestnew for qh_partitionpoint()
  • qh_WARNnarrow max. cosine in initial hull to warn about qh.NARROWhull
  • qh_WIDEcoplanar what is a wide facet
  • qh_WIDEduplicate merge ratio for errexit from qh_forcedmerges due to duplicate ridge
  • qh_WIDEridge merge ratio for selecting a forced dupridge merge
  • qh_WIDEmaxoutside precision ratio for maximum increase for qh.max_outside in qh_check_maxout
  • qh_WIDEmaxoutside2 precision ratio for maximum qh.max_outside in qh_check_maxout
  • qh_WIDEpinched merge ratio for distance between pinched vertices compared to current facet width for qh_getpinchedmerges and qh_next_vertexmerge
  • qh_ZEROdelaunay define facets that are ignored in Delaunay triangulations

»user.c functions

»usermem.c functions

  • qh_exit exit program, same as exit(). May be redefined as throw "QH10003.." by libqhullcpp/usermem_r-cpp.cpp
  • qh_fprintf_stderr print to stderr when qh.ferr is not defined.
  • qh_free free memory, same as free().
  • qh_malloc allocate memory, same as malloc()

»userprintf.c and userprintf_rbox,c functions

  • qh_fprintf print information from Qhull, sames as fprintf().
  • qh_fprintf_rbox print information from Rbox, sames as fprintf().


Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

qhull-2020.2/src/libqhull/qhull-exports.def0000644060175106010010000002236713723577776017142 0ustar bbarber; qhull-exports.def -- MSVC module-definition file ; ; Generated from depends.exe by cut-and-paste of exported symbols by mingw gcc ; [jan'14] 391 symbols ; Annotate as DATA qh_last_random qh_qh qh_qhstat qhmem rbox rbox_inuse ; Annotate as __declspec for outside access in win32 -- qh_qh qh_qhstat ; Same as ../libqhullp/qhull_p-exports.def without qh_save_qhull and qh_restore_qhull ; ; Referenced by CMakeLists/add_library, libqhull.pro/DEF_FILE, ; and libqhull.vcxproj/Linker/Input/Module Definition File ; ; If qh_NOmerge, use qhull_r-nomerge-exports.def ; Created by -- grep -vE 'qh_all_merges|qh_appendmergeset|qh_basevertices|qh_check_dupridge|qh_checkconnect|qh_compare_facetmerge|qh_comparevisit|qh_copynonconvex|qh_degen_redundant_facet|qh_delridge_merge|qh_find_newvertex|qh_findbest_test|qh_findbestneighbor|qh_flippedmerges|qh_forcedmerges|qh_getmergeset|qh_getmergeset_initial|qh_hashridge|qh_hashridge_find|qh_makeridges|qh_mark_dupridges|qh_maydropneighbor|qh_merge_degenredundant|qh_merge_nonconvex|qh_mergecycle|qh_mergecycle_all|qh_mergecycle_facets|qh_mergecycle_neighbors|qh_mergecycle_ridges|qh_mergecycle_vneighbors|qh_mergefacet|qh_mergefacet2d|qh_mergeneighbors|qh_mergeridges|qh_mergesimplex|qh_mergevertex_del|qh_mergevertex_neighbors|qh_mergevertices|qh_nearcoplanar|qh_nearvertex|qh_neighbor_intersections|qh_newhashtable|qh_newvertex|qh_newvertices|qh_nextridge3d|qh_reducevertices|qh_redundant_vertex|qh_remove_extravertices|qh_rename_sharedvertex|qh_renameridgevertex|qh_renamevertex|qh_test_appendmerge|qh_test_degen_neighbors|qh_test_redundant_neighbors|qh_test_vneighbors|qh_tracemerge|qh_tracemerging|qh_triangulate_facet|qh_triangulate_link|qh_triangulate_mirror|qh_triangulate_null|qh_updatetested|qh_vertexridges|qh_vertexridges_facet|qh_willdelete' qhull-exports.def >qhull-nomerge-exports.def ; ; $Id: //main/2019/qhull/src/libqhull/qhull-exports.def#5 $$Change: 3037 $ ; $DateTime: 2020/09/03 17:28:32 $$Author: bbarber $ ; ; Define qhull_VERSION in CMakeLists.txt, Makefile, qhull-exports.def, qhull_p-exports.def, qhull_r-exports.def, and qhull-warn.pri VERSION 8.0 EXPORTS qh_addhash qh_addpoint qh_all_merges qh_allstatA qh_allstatB qh_allstatC qh_allstatD qh_allstatE qh_allstatE2 qh_allstatF qh_allstatG qh_allstatH qh_allstatI qh_allstatistics qh_appendfacet qh_appendmergeset qh_appendprint qh_appendvertex qh_argv_to_command qh_argv_to_command_size qh_attachnewfacets qh_backnormal qh_basevertices qh_build_withrestart qh_buildhull qh_buildtracing qh_check_bestdist qh_check_dupridge qh_check_maxout qh_check_output qh_check_point qh_check_points qh_checkconnect qh_checkconvex qh_checkdelridge qh_checkfacet qh_checkflags qh_checkflipped qh_checkflipped_all qh_checklists qh_checkpolygon qh_checkvertex qh_checkzero qh_clear_outputflags qh_clearcenters qh_clock qh_collectstatistics qh_compare_facetarea qh_compare_facetmerge qh_compare_facetvisit qh_compare_nummerge qh_comparevisit qh_copyfilename qh_copynonconvex qh_copypoints qh_countfacets qh_createsimplex qh_crossproduct qh_degen_redundant_facet qh_deletevisible qh_delfacet qh_delridge_merge qh_delvertex qh_determinant qh_detjoggle qh_detroundoff qh_detsimplex qh_detvnorm qh_detvridge qh_detvridge3 qh_dfacet qh_distnorm qh_distplane qh_distround qh_divzero qh_dvertex qh_eachvoronoi qh_eachvoronoi_all qh_errexit qh_errexit2 qh_errexit_rbox qh_errprint qh_exit qh_facet2point qh_facet3vertex qh_facetarea qh_facetarea_simplex qh_facetcenter qh_facetintersect qh_facetvertices qh_find_newvertex qh_findbest qh_findbest_test qh_findbestfacet qh_findbesthorizon qh_findbestlower qh_findbestneighbor qh_findbestnew qh_findfacet_all qh_findgood qh_findgood_all qh_findgooddist qh_findhorizon qh_flippedmerges qh_forcedmerges qh_fprintf qh_fprintf_rbox qh_fprintf_stderr qh_free qh_freebuffers qh_freebuild qh_freeqhull qh_freeqhull2 qh_freestatistics qh_furthestnext qh_furthestout qh_gausselim qh_geomplanes qh_getangle qh_getarea qh_getcenter qh_getcentrum qh_getdistance qh_gethash qh_getmergeset qh_getmergeset_initial qh_gram_schmidt qh_hashridge qh_hashridge_find qh_infiniteloop qh_init_A qh_init_B qh_init_qhull_command qh_initbuild qh_initflags qh_initialhull qh_initialvertices qh_initqhull_buffers qh_initqhull_globals qh_initqhull_mem qh_initqhull_outputflags qh_initqhull_start qh_initqhull_start2 qh_initstatistics qh_initthresholds qh_inthresholds qh_isvertex qh_joggle_restart qh_joggleinput ; Mark as DATA, otherwise links a separate qh_last_random. No __declspec. qh_last_random DATA qh_lib_check qh_makenew_nonsimplicial qh_makenew_simplicial qh_makenewfacet qh_makenewfacets qh_makenewplanes qh_makeridges qh_malloc qh_mark_dupridges qh_markkeep qh_markvoronoi qh_matchdupridge qh_matchneighbor qh_matchnewfacets qh_matchvertices qh_maxabsval qh_maxmin qh_maxouter qh_maxsimplex qh_maydropneighbor qh_memalloc qh_memfree qh_memfreeshort qh_meminit qh_meminitbuffers qh_memsetup qh_memsize qh_memstatistics qh_memtotal qh_merge_degenredundant qh_merge_nonconvex qh_mergecycle qh_mergecycle_all qh_mergecycle_facets qh_mergecycle_neighbors qh_mergecycle_ridges qh_mergecycle_vneighbors qh_mergefacet qh_mergefacet2d qh_mergeneighbors qh_mergeridges qh_mergesimplex qh_mergevertex_del qh_mergevertex_neighbors qh_mergevertices qh_minabsval qh_mindiff qh_nearcoplanar qh_nearvertex qh_neighbor_intersections qh_new_qhull qh_newfacet qh_newhashtable qh_newridge qh_newstats qh_newvertex qh_newvertices qh_nextfacet2d qh_nextfurthest qh_nextridge3d qh_normalize qh_normalize2 qh_nostatistic qh_option qh_order_vertexneighbors qh_orientoutside qh_out1 qh_out2n qh_out3n qh_outcoplanar qh_outerinner qh_partitionall qh_partitioncoplanar qh_partitionpoint qh_partitionvisible qh_point qh_point_add qh_pointdist qh_pointfacet qh_pointid qh_pointvertex qh_postmerge qh_premerge qh_prepare_output qh_prependfacet qh_printafacet qh_printallstatistics qh_printbegin qh_printcenter qh_printcentrum qh_printend qh_printend4geom qh_printextremes qh_printextremes_2d qh_printextremes_d qh_printfacet qh_printfacet2geom qh_printfacet2geom_points qh_printfacet2math qh_printfacet3geom_nonsimplicial qh_printfacet3geom_points qh_printfacet3geom_simplicial qh_printfacet3math qh_printfacet3vertex qh_printfacet4geom_nonsimplicial qh_printfacet4geom_simplicial qh_printfacetNvertex_nonsimplicial qh_printfacetNvertex_simplicial qh_printfacetheader qh_printfacetlist qh_printfacetridges qh_printfacets qh_printhashtable qh_printhelp_degenerate qh_printhelp_internal qh_printhelp_narrowhull qh_printhelp_singular qh_printhelp_topology qh_printhelp_wide qh_printhyperplaneintersection qh_printline3geom qh_printlists qh_printmatrix qh_printneighborhood qh_printpoint qh_printpoint3 qh_printpointid qh_printpoints qh_printpoints_out qh_printpointvect qh_printpointvect2 qh_printridge qh_printspheres qh_printstatistics qh_printstatlevel qh_printstats qh_printsummary qh_printvdiagram qh_printvdiagram2 qh_printvertex qh_printvertexlist qh_printvertices qh_printvneighbors qh_printvnorm qh_printvoronoi qh_printvridge qh_produce_output qh_produce_output2 qh_projectdim3 qh_projectinput qh_projectpoint qh_projectpoints ; Mark as DATA, otherwise links a separate qh_qh. qh_qh and qh_qhstat requires __declspec qh_qh DATA qh_qhstat DATA qh_qhull qh_rand qh_randomfactor qh_randommatrix qh_rboxpoints qh_readfeasible qh_readpoints qh_reducevertices qh_redundant_vertex qh_remove_extravertices qh_removefacet qh_removevertex qh_rename_sharedvertex qh_renameridgevertex qh_renamevertex qh_resetlists qh_rotateinput qh_rotatepoints qh_roundi qh_scaleinput qh_scalelast qh_scalepoints qh_setaddnth qh_setaddsorted qh_setappend qh_setappend2ndlast qh_setappend_set qh_setcheck qh_setcompact qh_setcopy qh_setdel qh_setdelaunay qh_setdellast qh_setdelnth qh_setdelnthsorted qh_setdelsorted qh_setduplicate qh_setequal qh_setequal_except qh_setequal_skip qh_setfacetplane qh_setfeasible qh_setfree qh_setfree2 qh_setfreelong qh_sethalfspace qh_sethalfspace_all qh_sethyperplane_det qh_sethyperplane_gauss qh_setin qh_setindex qh_setlarger qh_setlarger_quick qh_setlast qh_setnew qh_setnew_delnthsorted qh_setprint qh_setreplace qh_setsize qh_settemp qh_settempfree qh_settempfree_all qh_settemppop qh_settemppush qh_settruncate qh_setunique qh_setvoronoi_all qh_setzero qh_sharpnewfacets qh_skipfacet qh_skipfilename qh_srand qh_stddev qh_strtod qh_strtol qh_test_appendmerge qh_test_degen_neighbors qh_test_redundant_neighbors qh_test_vneighbors qh_tracemerge qh_tracemerging qh_triangulate qh_triangulate_facet qh_triangulate_link qh_triangulate_mirror qh_triangulate_null qh_updatetested qh_update_vertexneighbors qh_update_vertexneighbors_cone qh_user_memsizes qh_version qh_version2 qh_vertexintersect qh_vertexintersect_new qh_vertexneighbors qh_vertexridges qh_vertexridges_facet qh_vertexsubset qh_voronoi_center qh_willdelete ; Mark as DATA, otherwise links a separate qhmem. No __declspec qhmem DATA rbox DATA rbox_inuse DATA qhull-2020.2/src/libqhull/qhull-nomerge-exports.def0000644060175106010010000001512113723600075020535 0ustar bbarber; qhull-nomerge-exports.def -- msvc module-definition file ; ; Generated from depends.exe by cut-and-paste of exported symbols by mingw gcc ; [jan'14] 391 symbols ; Annotate as DATA qh_last_random qh_qh qh_qhstat qhmem rbox rbox_inuse ; Annotate as __declspec for outside access in win32 -- qh_qh qh_qhstat ; Same as ../libqhullp/qhull_p-nomerge-exports.def without qh_save_qhull and qh_restore_qhull ; ; $Id: //main/2019/qhull/src/libqhull/qhull-nomerge-exports.def#5 $$Change: 3037 $ ; $DateTime: 2020/09/03 17:28:32 $$Author: bbarber $ ; ; Define qhull_VERSION in CMakeLists.txt, Makefile, qhull-exports.def, qhull_p-exports.def, qhull_r-exports.def, and qhull-warn.pri VERSION 8.0 EXPORTS qh_addhash qh_addpoint qh_allstatA qh_allstatB qh_allstatC qh_allstatD qh_allstatE qh_allstatE2 qh_allstatF qh_allstatG qh_allstatH qh_allstatI qh_allstatistics qh_appendfacet qh_appendprint qh_appendvertex qh_argv_to_command qh_argv_to_command_size qh_attachnewfacets qh_backnormal qh_build_withrestart qh_buildhull qh_buildtracing qh_check_bestdist qh_check_maxout qh_check_output qh_check_point qh_check_points qh_checkconvex qh_checkdelridge qh_checkfacet qh_checkflags qh_checkflipped qh_checkflipped_all qh_checkpolygon qh_checkvertex qh_checkzero qh_clear_outputflags qh_clearcenters qh_clock qh_collectstatistics qh_compare_facetarea qh_compare_facetvisit qh_compare_nummerge qh_copyfilename qh_copypoints qh_countfacets qh_createsimplex qh_crossproduct qh_deletevisible qh_delfacet qh_delvertex qh_determinant qh_detjoggle qh_detroundoff qh_detsimplex qh_detvnorm qh_detvridge qh_detvridge3 qh_dfacet qh_distnorm qh_distplane qh_distround qh_divzero qh_dvertex qh_eachvoronoi qh_eachvoronoi_all qh_errexit qh_errexit2 qh_errexit_rbox qh_errprint qh_exit qh_facet2point qh_facet3vertex qh_facetarea qh_facetarea_simplex qh_facetcenter qh_facetintersect qh_facetvertices qh_findbest qh_findbestfacet qh_findbesthorizon qh_findbestlower qh_findbestnew qh_findfacet_all qh_findgood qh_findgood_all qh_findgooddist qh_findhorizon qh_fprintf qh_fprintf_rbox qh_fprintf_stderr qh_free qh_freebuffers qh_freebuild qh_freeqhull qh_freeqhull2 qh_freestatistics qh_furthestnext qh_furthestout qh_gausselim qh_geomplanes qh_getangle qh_getarea qh_getcenter qh_getcentrum qh_getdistance qh_gethash qh_gram_schmidt qh_infiniteloop qh_init_A qh_init_B qh_init_qhull_command qh_initbuild qh_initflags qh_initialhull qh_initialvertices qh_initqhull_buffers qh_initqhull_globals qh_initqhull_mem qh_initqhull_outputflags qh_initqhull_start qh_initqhull_start2 qh_initstatistics qh_initthresholds qh_inthresholds qh_isvertex qh_joggle_restart qh_joggleinput ; Mark as DATA, otherwise links a separate qh_last_random. No __declspec. qh_last_random DATA qh_lib_check qh_makenew_nonsimplicial qh_makenew_simplicial qh_makenewfacet qh_makenewfacets qh_makenewplanes qh_malloc qh_markkeep qh_markvoronoi qh_matchdupridge qh_matchneighbor qh_matchnewfacets qh_matchvertices qh_maxabsval qh_maxmin qh_maxouter qh_maxsimplex qh_memalloc qh_memfree qh_memfreeshort qh_meminit qh_meminitbuffers qh_memsetup qh_memsize qh_memstatistics qh_memtotal qh_minabsval qh_mindiff qh_new_qhull qh_newfacet qh_newridge qh_newstats qh_nextfacet2d qh_nextfurthest qh_normalize qh_normalize2 qh_nostatistic qh_option qh_order_vertexneighbors qh_orientoutside qh_out1 qh_out2n qh_out3n qh_outcoplanar qh_outerinner qh_partitionall qh_partitioncoplanar qh_partitionpoint qh_partitionvisible qh_point qh_point_add qh_pointdist qh_pointfacet qh_pointid qh_pointvertex qh_postmerge qh_premerge qh_prepare_output qh_prependfacet qh_printafacet qh_printallstatistics qh_printbegin qh_printcenter qh_printcentrum qh_printend qh_printend4geom qh_printextremes qh_printextremes_2d qh_printextremes_d qh_printfacet qh_printfacet2geom qh_printfacet2geom_points qh_printfacet2math qh_printfacet3geom_nonsimplicial qh_printfacet3geom_points qh_printfacet3geom_simplicial qh_printfacet3math qh_printfacet3vertex qh_printfacet4geom_nonsimplicial qh_printfacet4geom_simplicial qh_printfacetNvertex_nonsimplicial qh_printfacetNvertex_simplicial qh_printfacetheader qh_printfacetlist qh_printfacetridges qh_printfacets qh_printhashtable qh_printhelp_degenerate qh_printhelp_internal qh_printhelp_narrowhull qh_printhelp_singular qh_printhelp_topology qh_printhelp_wide qh_printhyperplaneintersection qh_printline3geom qh_printlists qh_printmatrix qh_printneighborhood qh_printpoint qh_printpoint3 qh_printpointid qh_printpoints qh_printpoints_out qh_printpointvect qh_printpointvect2 qh_printridge qh_printspheres qh_printstatistics qh_printstatlevel qh_printstats qh_printsummary qh_printvdiagram qh_printvdiagram2 qh_printvertex qh_printvertexlist qh_printvertices qh_printvneighbors qh_printvnorm qh_printvoronoi qh_printvridge qh_produce_output qh_produce_output2 qh_projectdim3 qh_projectinput qh_projectpoint qh_projectpoints ; Mark as DATA, otherwise links a separate qh_qh. qh_qh and qh_qhstat requires __declspec qh_qh DATA qh_qhstat DATA qh_qhull qh_rand qh_randomfactor qh_randommatrix qh_rboxpoints qh_readfeasible qh_readpoints qh_removefacet qh_removevertex qh_resetlists qh_rotateinput qh_rotatepoints qh_roundi qh_scaleinput qh_scalelast qh_scalepoints qh_setaddnth qh_setaddsorted qh_setappend qh_setappend2ndlast qh_setappend_set qh_setcheck qh_setcompact qh_setcopy qh_setdel qh_setdelaunay qh_setdellast qh_setdelnth qh_setdelnthsorted qh_setdelsorted qh_setduplicate qh_setequal qh_setequal_except qh_setequal_skip qh_setfacetplane qh_setfeasible qh_setfree qh_setfree2 qh_setfreelong qh_sethalfspace qh_sethalfspace_all qh_sethyperplane_det qh_sethyperplane_gauss qh_setin qh_setindex qh_setlarger qh_setlarger_quick qh_setlast qh_setnew qh_setnew_delnthsorted qh_setprint qh_setreplace qh_setsize qh_settemp qh_settempfree qh_settempfree_all qh_settemppop qh_settemppush qh_settruncate qh_setunique qh_setvoronoi_all qh_setzero qh_sharpnewfacets qh_skipfacet qh_skipfilename qh_srand qh_stddev qh_strtod qh_strtol qh_triangulate qh_update_vertexneighbors qh_update_vertexneighbors_cone qh_user_memsizes qh_version qh_version2 qh_vertexintersect qh_vertexintersect_new qh_vertexneighbors qh_vertexsubset qh_voronoi_center ; Mark as DATA, otherwise links a separate qhmem. No __declspec qhmem DATA rbox DATA rbox_inuse DATA qhull-2020.2/src/libqhull/qhull_a.h0000644060175106010010000001171013661631132015371 0ustar bbarber/*
  ---------------------------------

   qhull_a.h
   all header files for compiling qhull with non-reentrant code

   see qh-qhull.htm

   see libqhull.h for user-level definitions

   see user.h for user-definable constants

   defines internal functions for libqhull.c global.c

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull/qhull_a.h#2 $$Change: 2953 $
   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $

   Notes:  grep for ((" and (" to catch fprintf("lkasdjf");
           full parens around (x?y:z)
           use '#include "libqhull/qhull_a.h"' to avoid name clashes
*/

#ifndef qhDEFqhulla
#define qhDEFqhulla 1

#include "libqhull.h"  /* Includes user.h and data types */

#include "stat.h"
#include "random.h"
#include "mem.h"
#include "qset.h"
#include "geom.h"
#include "merge.h"
#include "poly.h"
#include "io.h"

#include 
#include 
#include 
#include     /* some compilers will not need float.h */
#include 
#include 
#include 
#include 
#include 
/*** uncomment here and qset.c
     if string.h does not define memcpy()
#include 
*/

#if qh_CLOCKtype == 2  /* defined in user.h from libqhull.h */
#include 
#include 
#include 
#endif

#ifdef _MSC_VER  /* Microsoft Visual C++ -- warning level 4 */
#pragma warning( disable : 4100)  /* unreferenced formal parameter */
#pragma warning( disable : 4127)  /* conditional expression is constant */
#pragma warning( disable : 4706)  /* assignment within conditional function */
#pragma warning( disable : 4996)  /* function was declared deprecated(strcpy, localtime, etc.) */
#endif

/* ======= -macros- =========== */

/*----------------------------------

  traceN((qh ferr, 0Nnnn, "format\n", vars));
    calls qh_fprintf if qh.IStracing >= N

    Add debugging traps to the end of qh_fprintf

  notes:
    removing tracing reduces code size but doesn't change execution speed
*/
#ifndef qh_NOtrace
#define trace0(args) {if (qh IStracing) qh_fprintf args;}
#define trace1(args) {if (qh IStracing >= 1) qh_fprintf args;}
#define trace2(args) {if (qh IStracing >= 2) qh_fprintf args;}
#define trace3(args) {if (qh IStracing >= 3) qh_fprintf args;}
#define trace4(args) {if (qh IStracing >= 4) qh_fprintf args;}
#define trace5(args) {if (qh IStracing >= 5) qh_fprintf args;}
#else /* qh_NOtrace */
#define trace0(args) {}
#define trace1(args) {}
#define trace2(args) {}
#define trace3(args) {}
#define trace4(args) {}
#define trace5(args) {}
#endif /* qh_NOtrace */

/*----------------------------------

  Define an unused variable to avoid compiler warnings

  Derived from Qt's corelib/global/qglobal.h

*/

#if defined(__cplusplus) && defined(__INTEL_COMPILER) && !defined(QHULL_OS_WIN)
template 
inline void qhullUnused(T &x) { (void)x; }
#  define QHULL_UNUSED(x) qhullUnused(x);
#else
#  define QHULL_UNUSED(x) (void)x;
#endif

/***** -libqhull.c prototypes (alphabetical after qhull) ********************/

void    qh_qhull(void);
boolT   qh_addpoint(pointT *furthest, facetT *facet, boolT checkdist);
void    qh_build_withrestart(void);
vertexT *qh_buildcone(pointT *furthest, facetT *facet, int goodhorizon, facetT **retryfacet);
boolT   qh_buildcone_mergepinched(vertexT *apex, facetT *facet, facetT **retryfacet);
boolT   qh_buildcone_onlygood(vertexT *apex, int goodhorizon);
void    qh_buildhull(void);
void    qh_buildtracing(pointT *furthest, facetT *facet);
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, boolT allnew);
void    qh_partitionpoint(pointT *point, facetT *facet);
void    qh_partitionvisible(boolT allpoints, int *numpoints);
void    qh_joggle_restart(const char *reason);
void    qh_printsummary(FILE *fp);

/***** -global.c internal prototypes (alphabetical) ***********************/

void    qh_appendprint(qh_PRINT format);
void    qh_freebuild(boolT allmem);
void    qh_freebuffers(void);
void    qh_initbuffers(coordT *points, int numpoints, int dim, boolT ismalloc);

/***** -stat.c internal prototypes (alphabetical) ***********************/

void    qh_allstatA(void);
void    qh_allstatB(void);
void    qh_allstatC(void);
void    qh_allstatD(void);
void    qh_allstatE(void);
void    qh_allstatE2(void);
void    qh_allstatF(void);
void    qh_allstatG(void);
void    qh_allstatH(void);
void    qh_freebuffers(void);
void    qh_initbuffers(coordT *points, int numpoints, int dim, boolT ismalloc);

#endif /* qhDEFqhulla */
qhull-2020.2/src/libqhull/qhull_p-exports.def0000644060175106010010000002243613710365751017436 0ustar  bbarber; qhull_p-exports.def -- msvc module-definition file
;
;   Generated from depends.exe by cut-and-paste of exported symbols by mingw gcc
;   [jan'14] 391 symbols 
;   Annotate as DATA qh_last_random qh_qh qh_qhstat qhmem rbox rbox_inuse
;   Annotate as __declspec for outside access in win32 -- qh_qh qh_qhstat
;   Same as ../libqhull/qhull-exports.def with qh_save_qhull and qh_restore_qhull
;
;   Referenced by CMakeLists/add_library, libqhull_p.pro/DEF_FILE, 
;   and libqhull_p.vcxproj/Linker/Input/Module Definition File
;
;   If qh_NOmerge, use qhull_p-nomerge-exports.def
;      Created by -- grep -vE 'qh_all_merges|qh_appendmergeset|qh_basevertices|qh_check_dupridge|qh_checkconnect|qh_compare_facetmerge|qh_comparevisit|qh_copynonconvex|qh_degen_redundant_facet|qh_delridge_merge|qh_find_newvertex|qh_findbest_test|qh_findbestneighbor|qh_flippedmerges|qh_forcedmerges|qh_getmergeset|qh_getmergeset_initial|qh_hashridge|qh_hashridge_find|qh_makeridges|qh_mark_dupridges|qh_maydropneighbor|qh_merge_degenredundant|qh_merge_nonconvex|qh_mergecycle|qh_mergecycle_all|qh_mergecycle_facets|qh_mergecycle_neighbors|qh_mergecycle_ridges|qh_mergecycle_vneighbors|qh_mergefacet|qh_mergefacet2d|qh_mergeneighbors|qh_mergeridges|qh_mergesimplex|qh_mergevertex_del|qh_mergevertex_neighbors|qh_mergevertices|qh_nearcoplanar|qh_nearvertex|qh_neighbor_intersections|qh_newhashtable|qh_newvertex|qh_newvertices|qh_nextridge3d|qh_reducevertices|qh_redundant_vertex|qh_remove_extravertices|qh_rename_sharedvertex|qh_renameridgevertex|qh_renamevertex|qh_test_appendmerge|qh_test_degen_neighbors|qh_test_redundant_neighbors|qh_test_vneighbors|qh_tracemerge|qh_tracemerging|qh_triangulate_facet|qh_triangulate_link|qh_triangulate_mirror|qh_triangulate_null|qh_updatetested|qh_vertexridges|qh_vertexridges_facet|qh_willdelete' qhull_p-exports.def >qhull_p-nomerge-exports.def
;
; $Id: //main/2019/qhull/src/libqhull/qhull_p-exports.def#5 $$Change: 2967 $
; $DateTime: 2020/06/05 16:33:18 $$Author: bbarber $
;
; Define qhull_VERSION in CMakeLists.txt, Makefile, qhull-exports.def, qhull_p-exports.def, qhull_r-exports.def, and qhull-warn.pri
VERSION 8.0
EXPORTS
qh_addhash
qh_addpoint
qh_all_merges
qh_allstatA
qh_allstatB
qh_allstatC
qh_allstatD
qh_allstatE
qh_allstatE2
qh_allstatF
qh_allstatG
qh_allstatH
qh_allstatI
qh_allstatistics
qh_appendfacet
qh_appendmergeset
qh_appendprint
qh_appendvertex
qh_argv_to_command
qh_argv_to_command_size
qh_attachnewfacets
qh_backnormal
qh_basevertices
qh_build_withrestart
qh_buildhull
qh_buildtracing
qh_check_bestdist
qh_check_dupridge
qh_check_maxout
qh_check_output
qh_check_point
qh_check_points
qh_checkconnect
qh_checkconvex
qh_checkdelridge
qh_checkfacet
qh_checkflags
qh_checkflipped
qh_checkflipped_all
qh_checklists
qh_checkpolygon
qh_checkvertex
qh_checkzero
qh_clear_outputflags
qh_clearcenters
qh_clock
qh_collectstatistics
qh_compare_facetarea
qh_compare_facetmerge
qh_compare_facetvisit
qh_compare_nummerge
qh_comparevisit
qh_copyfilename
qh_copynonconvex
qh_copypoints
qh_countfacets
qh_createsimplex
qh_crossproduct
qh_degen_redundant_facet
qh_deletevisible
qh_delfacet
qh_delridge_merge
qh_delvertex
qh_determinant
qh_detjoggle
qh_detroundoff
qh_detsimplex
qh_detvnorm
qh_detvridge
qh_detvridge3
qh_dfacet
qh_distnorm
qh_distplane
qh_distround
qh_divzero
qh_dvertex
qh_eachvoronoi
qh_eachvoronoi_all
qh_errexit
qh_errexit2
qh_errexit_rbox
qh_errprint
qh_exit
qh_facet2point
qh_facet3vertex
qh_facetarea
qh_facetarea_simplex
qh_facetcenter
qh_facetintersect
qh_facetvertices
qh_find_newvertex
qh_findbest
qh_findbest_test
qh_findbestfacet
qh_findbesthorizon
qh_findbestlower
qh_findbestneighbor
qh_findbestnew
qh_findfacet_all
qh_findgood
qh_findgood_all
qh_findgooddist
qh_findhorizon
qh_flippedmerges
qh_forcedmerges
qh_fprintf
qh_fprintf_rbox
qh_fprintf_stderr
qh_free
qh_freebuffers
qh_freebuild
qh_freeqhull
qh_freeqhull2
qh_freestatistics
qh_furthestnext
qh_furthestout
qh_gausselim
qh_geomplanes
qh_getangle
qh_getarea
qh_getcenter
qh_getcentrum
qh_getdistance
qh_gethash
qh_getmergeset
qh_getmergeset_initial
qh_gram_schmidt
qh_hashridge
qh_hashridge_find
qh_infiniteloop
qh_init_A
qh_init_B
qh_init_qhull_command
qh_initbuild
qh_initflags
qh_initialhull
qh_initialvertices
qh_initqhull_buffers
qh_initqhull_globals
qh_initqhull_mem
qh_initqhull_outputflags
qh_initqhull_start
qh_initqhull_start2
qh_initstatistics
qh_initthresholds
qh_inthresholds
qh_isvertex
qh_joggle_restart
qh_joggleinput
; Mark as DATA, otherwise links a separate qh_last_random.  No __declspec.
qh_last_random      DATA
qh_lib_check
qh_makenew_nonsimplicial
qh_makenew_simplicial
qh_makenewfacet
qh_makenewfacets
qh_makenewplanes
qh_makeridges
qh_malloc
qh_mark_dupridges
qh_markkeep
qh_markvoronoi
qh_matchdupridge
qh_matchneighbor
qh_matchnewfacets
qh_matchvertices
qh_maxabsval
qh_maxmin
qh_maxouter
qh_maxsimplex
qh_maydropneighbor
qh_memalloc
qh_memfree
qh_memfreeshort
qh_meminit
qh_meminitbuffers
qh_memsetup
qh_memsize
qh_memstatistics
qh_memtotal
qh_merge_degenredundant
qh_merge_nonconvex
qh_mergecycle
qh_mergecycle_all
qh_mergecycle_facets
qh_mergecycle_neighbors
qh_mergecycle_ridges
qh_mergecycle_vneighbors
qh_mergefacet
qh_mergefacet2d
qh_mergeneighbors
qh_mergeridges
qh_mergesimplex
qh_mergevertex_del
qh_mergevertex_neighbors
qh_mergevertices
qh_minabsval
qh_mindiff
qh_nearcoplanar
qh_nearvertex
qh_neighbor_intersections
qh_new_qhull
qh_newfacet
qh_newhashtable
qh_newridge
qh_newstats
qh_newvertex
qh_newvertices
qh_nextfacet2d
qh_nextfurthest
qh_nextridge3d
qh_normalize
qh_normalize2
qh_nostatistic
qh_option
qh_order_vertexneighbors
qh_orientoutside
qh_out1
qh_out2n
qh_out3n
qh_outcoplanar
qh_outerinner
qh_partitionall
qh_partitioncoplanar
qh_partitionpoint
qh_partitionvisible
qh_point
qh_point_add
qh_pointdist
qh_pointfacet
qh_pointid
qh_pointvertex
qh_postmerge
qh_premerge
qh_prepare_output
qh_prependfacet
qh_printafacet
qh_printallstatistics
qh_printbegin
qh_printcenter
qh_printcentrum
qh_printend
qh_printend4geom
qh_printextremes
qh_printextremes_2d
qh_printextremes_d
qh_printfacet
qh_printfacet2geom
qh_printfacet2geom_points
qh_printfacet2math
qh_printfacet3geom_nonsimplicial
qh_printfacet3geom_points
qh_printfacet3geom_simplicial
qh_printfacet3math
qh_printfacet3vertex
qh_printfacet4geom_nonsimplicial
qh_printfacet4geom_simplicial
qh_printfacetNvertex_nonsimplicial
qh_printfacetNvertex_simplicial
qh_printfacetheader
qh_printfacetlist
qh_printfacetridges
qh_printfacets
qh_printhashtable
qh_printhelp_degenerate
qh_printhelp_internal
qh_printhelp_narrowhull
qh_printhelp_singular
qh_printhelp_topology
qh_printhelp_wide
qh_printhyperplaneintersection
qh_printline3geom
qh_printlists
qh_printmatrix
qh_printneighborhood
qh_printpoint
qh_printpoint3
qh_printpointid
qh_printpoints
qh_printpoints_out
qh_printpointvect
qh_printpointvect2
qh_printridge
qh_printspheres
qh_printstatistics
qh_printstatlevel
qh_printstats
qh_printsummary
qh_printvdiagram
qh_printvdiagram2
qh_printvertex
qh_printvertexlist
qh_printvertices
qh_printvneighbors
qh_printvnorm
qh_printvoronoi
qh_printvridge
qh_produce_output
qh_produce_output2
qh_projectdim3
qh_projectinput
qh_projectpoint
qh_projectpoints
; Mark as DATA, otherwise links a separate qh_qh.  qh_qh and qh_qhstat requires __declspec
qh_qh               DATA
qh_qhstat           DATA
qh_qhull
qh_rand
qh_randomfactor
qh_randommatrix
qh_rboxpoints
qh_readfeasible
qh_readpoints
qh_reducevertices
qh_redundant_vertex
qh_remove_extravertices
qh_removefacet
qh_removevertex
qh_rename_sharedvertex
qh_renameridgevertex
qh_renamevertex
qh_resetlists
qh_restore_qhull
qh_rotateinput
qh_rotatepoints
qh_roundi
qh_save_qhull
qh_scaleinput
qh_scalelast
qh_scalepoints
qh_setaddnth
qh_setaddsorted
qh_setappend
qh_setappend2ndlast
qh_setappend_set
qh_setcheck
qh_setcompact
qh_setcopy
qh_setdel
qh_setdelaunay
qh_setdellast
qh_setdelnth
qh_setdelnthsorted
qh_setdelsorted
qh_setduplicate
qh_setequal
qh_setequal_except
qh_setequal_skip
qh_setfacetplane
qh_setfeasible
qh_setfree
qh_setfree2
qh_setfreelong
qh_sethalfspace
qh_sethalfspace_all
qh_sethyperplane_det
qh_sethyperplane_gauss
qh_setin
qh_setindex
qh_setlarger
qh_setlarger_quick
qh_setlast
qh_setnew
qh_setnew_delnthsorted
qh_setprint
qh_setreplace
qh_setsize
qh_settemp
qh_settempfree
qh_settempfree_all
qh_settemppop
qh_settemppush
qh_settruncate
qh_setunique
qh_setvoronoi_all
qh_setzero
qh_sharpnewfacets
qh_skipfacet
qh_skipfilename
qh_srand
qh_stddev
qh_strtod
qh_strtol
qh_test_appendmerge
qh_test_degen_neighbors
qh_test_redundant_neighbors
qh_test_vneighbors
qh_tracemerge
qh_tracemerging
qh_triangulate
qh_triangulate_facet
qh_triangulate_link
qh_triangulate_mirror
qh_triangulate_null
qh_updatetested
qh_update_vertexneighbors
qh_update_vertexneighbors_cone
qh_user_memsizes
qh_version
qh_version2
qh_vertexintersect
qh_vertexintersect_new
qh_vertexneighbors
qh_vertexridges
qh_vertexridges_facet
qh_vertexsubset
qh_voronoi_center
qh_willdelete
; Mark as DATA, otherwise links a separate qhmem.  No __declspec
qhmem                   DATA
rbox                    DATA
rbox_inuse              DATA
qhull-2020.2/src/libqhull/qhull_p-nomerge-exports.def0000644060175106010010000001516013710365751021064 0ustar  bbarber; qhull_p-nomerge-exports.def -- msvc module-definition file
;
;   Generated from depends.exe by cut-and-paste of exported symbols by mingw gcc
;   [jan'14] 391 symbols 
;   Annotate as DATA qh_last_random qh_qh qh_qhstat qhmem rbox rbox_inuse
;   Annotate as __declspec for outside access in win32 -- qh_qh qh_qhstat
;   Same as ../libqhull/qhull-nomerge-exports.def with qh_save_qhull and qh_restore_qhull
;
; $Id: //main/2019/qhull/src/libqhull/qhull_p-nomerge-exports.def#5 $$Change: 2967 $
; $DateTime: 2020/06/05 16:33:18 $$Author: bbarber $
; 
; Define qhull_VERSION in CMakeLists.txt, Makefile, qhull-exports.def, qhull_p-exports.def, qhull_r-exports.def, and qhull-warn.pri
VERSION 8.0
EXPORTS
qh_addhash
qh_addpoint
qh_allstatA
qh_allstatB
qh_allstatC
qh_allstatD
qh_allstatE
qh_allstatE2
qh_allstatF
qh_allstatG
qh_allstatH
qh_allstatI
qh_allstatistics
qh_appendfacet
qh_appendprint
qh_appendvertex
qh_argv_to_command
qh_argv_to_command_size
qh_attachnewfacets
qh_backnormal
qh_build_withrestart
qh_buildhull
qh_buildtracing
qh_check_bestdist
qh_check_maxout
qh_check_output
qh_check_point
qh_check_points
qh_checkconvex
qh_checkdelridge
qh_checkfacet
qh_checkflags
qh_checkflipped
qh_checkflipped_all
qh_checkpolygon
qh_checkvertex
qh_checkzero
qh_clear_outputflags
qh_clearcenters
qh_clock
qh_collectstatistics
qh_compare_facetarea
qh_compare_facetvisit
qh_compare_nummerge
qh_copyfilename
qh_copypoints
qh_countfacets
qh_createsimplex
qh_crossproduct
qh_deletevisible
qh_delfacet
qh_delvertex
qh_determinant
qh_detjoggle
qh_detroundoff
qh_detsimplex
qh_detvnorm
qh_detvridge
qh_detvridge3
qh_dfacet
qh_distnorm
qh_distplane
qh_distround
qh_divzero
qh_dvertex
qh_eachvoronoi
qh_eachvoronoi_all
qh_errexit
qh_errexit2
qh_errexit_rbox
qh_errprint
qh_exit
qh_facet2point
qh_facet3vertex
qh_facetarea
qh_facetarea_simplex
qh_facetcenter
qh_facetintersect
qh_facetvertices
qh_findbest
qh_findbestfacet
qh_findbesthorizon
qh_findbestlower
qh_findbestnew
qh_findfacet_all
qh_findgood
qh_findgood_all
qh_findgooddist
qh_findhorizon
qh_fprintf
qh_fprintf_rbox
qh_fprintf_stderr
qh_free
qh_freebuffers
qh_freebuild
qh_freeqhull
qh_freeqhull2
qh_freestatistics
qh_furthestnext
qh_furthestout
qh_gausselim
qh_geomplanes
qh_getangle
qh_getarea
qh_getcenter
qh_getcentrum
qh_getdistance
qh_gethash
qh_gram_schmidt
qh_infiniteloop
qh_init_A
qh_init_B
qh_init_qhull_command
qh_initbuild
qh_initflags
qh_initialhull
qh_initialvertices
qh_initqhull_buffers
qh_initqhull_globals
qh_initqhull_mem
qh_initqhull_outputflags
qh_initqhull_start
qh_initqhull_start2
qh_initstatistics
qh_initthresholds
qh_inthresholds
qh_isvertex
qh_joggle_restart
qh_joggleinput
; Mark as DATA, otherwise links a separate qh_last_random.  No __declspec.
qh_last_random      DATA
qh_lib_check
qh_makenew_nonsimplicial
qh_makenew_simplicial
qh_makenewfacet
qh_makenewfacets
qh_makenewplanes
qh_malloc
qh_markkeep
qh_markvoronoi
qh_matchdupridge
qh_matchneighbor
qh_matchnewfacets
qh_matchvertices
qh_maxabsval
qh_maxmin
qh_maxouter
qh_maxsimplex
qh_memalloc
qh_memfree
qh_memfreeshort
qh_meminit
qh_meminitbuffers
qh_memsetup
qh_memsize
qh_memstatistics
qh_memtotal
qh_minabsval
qh_mindiff
qh_new_qhull
qh_newfacet
qh_newridge
qh_newstats
qh_nextfacet2d
qh_nextfurthest
qh_normalize
qh_normalize2
qh_nostatistic
qh_option
qh_order_vertexneighbors
qh_orientoutside
qh_out1
qh_out2n
qh_out3n
qh_outcoplanar
qh_outerinner
qh_partitionall
qh_partitioncoplanar
qh_partitionpoint
qh_partitionvisible
qh_point
qh_point_add
qh_pointdist
qh_pointfacet
qh_pointid
qh_pointvertex
qh_postmerge
qh_premerge
qh_prepare_output
qh_prependfacet
qh_printafacet
qh_printallstatistics
qh_printbegin
qh_printcenter
qh_printcentrum
qh_printend
qh_printend4geom
qh_printextremes
qh_printextremes_2d
qh_printextremes_d
qh_printfacet
qh_printfacet2geom
qh_printfacet2geom_points
qh_printfacet2math
qh_printfacet3geom_nonsimplicial
qh_printfacet3geom_points
qh_printfacet3geom_simplicial
qh_printfacet3math
qh_printfacet3vertex
qh_printfacet4geom_nonsimplicial
qh_printfacet4geom_simplicial
qh_printfacetNvertex_nonsimplicial
qh_printfacetNvertex_simplicial
qh_printfacetheader
qh_printfacetlist
qh_printfacetridges
qh_printfacets
qh_printhashtable
qh_printhelp_degenerate
qh_printhelp_internal
qh_printhelp_narrowhull
qh_printhelp_singular
qh_printhelp_topology
qh_printhelp_wide
qh_printhyperplaneintersection
qh_printline3geom
qh_printlists
qh_printmatrix
qh_printneighborhood
qh_printpoint
qh_printpoint3
qh_printpointid
qh_printpoints
qh_printpoints_out
qh_printpointvect
qh_printpointvect2
qh_printridge
qh_printspheres
qh_printstatistics
qh_printstatlevel
qh_printstats
qh_printsummary
qh_printvdiagram
qh_printvdiagram2
qh_printvertex
qh_printvertexlist
qh_printvertices
qh_printvneighbors
qh_printvnorm
qh_printvoronoi
qh_printvridge
qh_produce_output
qh_produce_output2
qh_projectdim3
qh_projectinput
qh_projectpoint
qh_projectpoints
; Mark as DATA, otherwise links a separate qh_qh.  qh_qh and qh_qhstat requires __declspec
qh_qh               DATA
qh_qhstat           DATA
qh_qhull
qh_rand
qh_randomfactor
qh_randommatrix
qh_rboxpoints
qh_readfeasible
qh_readpoints
qh_removefacet
qh_removevertex
qh_resetlists
qh_restore_qhull
qh_rotateinput
qh_rotatepoints
qh_roundi
qh_save_qhull
qh_scaleinput
qh_scalelast
qh_scalepoints
qh_setaddnth
qh_setaddsorted
qh_setappend
qh_setappend2ndlast
qh_setappend_set
qh_setcheck
qh_setcompact
qh_setcopy
qh_setdel
qh_setdelaunay
qh_setdellast
qh_setdelnth
qh_setdelnthsorted
qh_setdelsorted
qh_setduplicate
qh_setequal
qh_setequal_except
qh_setequal_skip
qh_setfacetplane
qh_setfeasible
qh_setfree
qh_setfree2
qh_setfreelong
qh_sethalfspace
qh_sethalfspace_all
qh_sethyperplane_det
qh_sethyperplane_gauss
qh_setin
qh_setindex
qh_setlarger
qh_setlarger_quick
qh_setlast
qh_setnew
qh_setnew_delnthsorted
qh_setprint
qh_setreplace
qh_setsize
qh_settemp
qh_settempfree
qh_settempfree_all
qh_settemppop
qh_settemppush
qh_settruncate
qh_setunique
qh_setvoronoi_all
qh_setzero
qh_sharpnewfacets
qh_skipfacet
qh_skipfilename
qh_srand
qh_stddev
qh_strtod
qh_strtol
qh_triangulate
qh_update_vertexneighbors
qh_update_vertexneighbors_cone
qh_user_memsizes
qh_version
qh_version2
qh_vertexintersect
qh_vertexintersect_new
qh_vertexneighbors
qh_vertexsubset
qh_voronoi_center
; Mark as DATA, otherwise links a separate qhmem.  No __declspec
qhmem                   DATA
rbox                    DATA
rbox_inuse              DATA
qhull-2020.2/src/libqhull/qset.c0000644060175106010010000010454213661631132014721 0ustar  bbarber/*
  ---------------------------------

   qset.c
   implements set manipulations needed for quickhull

   see qh-set.htm and qset.h

   Be careful of strict aliasing (two pointers of different types
   that reference the same location).  The last slot of a set is
   either the actual size of the set plus 1, or the NULL terminator
   of the set (i.e., setelemT).

   Do not reference 'qh' since it brings in qhT unnecessarily

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull/qset.c#7 $$Change: 2953 $
   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
*/

#include "libqhull.h" /* for qhT and QHULL_CRTDBG */
#include "qset.h"
#include "mem.h"
#include 
#include 
/*** uncomment here and qhull_a.h
     if string.h does not define memcpy()
#include 
*/

#ifndef qhDEFlibqhull
typedef struct ridgeT ridgeT;
typedef struct facetT facetT;
void    qh_errexit(int exitcode, facetT *, ridgeT *);
void    qh_fprintf(FILE *fp, int msgcode, const char *fmt, ... );
#  ifdef _MSC_VER  /* Microsoft Visual C++ -- warning level 4 */
#  pragma warning( disable : 4127)  /* conditional expression is constant */
#  pragma warning( disable : 4706)  /* assignment within conditional function */
#  endif
#endif

/*=============== internal macros ===========================*/

/*============ functions in alphabetical order ===================*/

/*----------------------------------

  qh_setaddnth( setp, nth, newelem )
    adds newelem as n'th element of sorted or unsorted *setp

  notes:
    *setp and newelem must be defined
    *setp may be a temp set
    nth=0 is first element
    errors if nth is out of bounds

  design:
    expand *setp if empty or full
    move tail of *setp up one
    insert newelem
*/
void qh_setaddnth(setT **setp, int nth, void *newelem) {
  int oldsize, i;
  setelemT *sizep;          /* avoid strict aliasing */
  setelemT *oldp, *newp;

  if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {
    qh_setlarger(setp);
    sizep= SETsizeaddr_(*setp);
  }
  oldsize= sizep->i - 1;
  if (nth < 0 || nth > oldsize) {
    qh_fprintf(qhmem.ferr, 6171, "qhull internal error (qh_setaddnth): nth %d is out-of-bounds for set:\n", nth);
    qh_setprint(qhmem.ferr, "", *setp);
    qh_errexit(qhmem_ERRqhull, NULL, NULL);
  }
  sizep->i++;
  oldp= (setelemT *)SETelemaddr_(*setp, oldsize, void);   /* NULL */
  newp= oldp+1;
  for (i=oldsize-nth+1; i--; )  /* move at least NULL  */
    (newp--)->p= (oldp--)->p;       /* may overwrite *sizep */
  newp->p= newelem;
} /* setaddnth */


/*----------------------------------

  setaddsorted( setp, newelem )
    adds an newelem into sorted *setp

  notes:
    *setp and newelem must be defined
    *setp may be a temp set
    nop if newelem already in set

  design:
    find newelem's position in *setp
    insert newelem
*/
void qh_setaddsorted(setT **setp, void *newelem) {
  int newindex=0;
  void *elem, **elemp;

  FOREACHelem_(*setp) {          /* could use binary search instead */
    if (elem < newelem)
      newindex++;
    else if (elem == newelem)
      return;
    else
      break;
  }
  qh_setaddnth(setp, newindex, newelem);
} /* setaddsorted */


/*---------------------------------

  qh_setappend( setp, newelem )
    append newelem to *setp

  notes:
    *setp may be a temp set
    *setp and newelem may be NULL

  design:
    expand *setp if empty or full
    append newelem to *setp

*/
void qh_setappend(setT **setp, void *newelem) {
  setelemT *sizep;  /* Avoid strict aliasing.  Writing to *endp may overwrite *sizep */
  setelemT *endp;
  int count;

  if (!newelem)
    return;
  if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {
    qh_setlarger(setp);
    sizep= SETsizeaddr_(*setp);
  }
  count= (sizep->i)++ - 1;
  endp= (setelemT *)SETelemaddr_(*setp, count, void);
  (endp++)->p= newelem;
  endp->p= NULL;
} /* setappend */

/*---------------------------------

  qh_setappend_set( setp, setA )
    appends setA to *setp

  notes:
    *setp can not be a temp set
    *setp and setA may be NULL

  design:
    setup for copy
    expand *setp if it is too small
    append all elements of setA to *setp
*/
void qh_setappend_set(setT **setp, setT *setA) {
  int sizeA, size;
  setT *oldset;
  setelemT *sizep;

  if (!setA)
    return;
  SETreturnsize_(setA, sizeA);
  if (!*setp)
    *setp= qh_setnew(sizeA);
  sizep= SETsizeaddr_(*setp);
  if (!(size= sizep->i))
    size= (*setp)->maxsize;
  else
    size--;
  if (size + sizeA > (*setp)->maxsize) {
    oldset= *setp;
    *setp= qh_setcopy(oldset, sizeA);
    qh_setfree(&oldset);
    sizep= SETsizeaddr_(*setp);
  }
  if (sizeA > 0) {
    sizep->i= size+sizeA+1;   /* memcpy may overwrite */
    memcpy((char *)&((*setp)->e[size].p), (char *)&(setA->e[0].p), (size_t)(sizeA+1) * SETelemsize);
  }
} /* setappend_set */


/*---------------------------------

  qh_setappend2ndlast( setp, newelem )
    makes newelem the next to the last element in *setp

  notes:
    *setp must have at least one element
    newelem must be defined
    *setp may be a temp set

  design:
    expand *setp if empty or full
    move last element of *setp up one
    insert newelem
*/
void qh_setappend2ndlast(setT **setp, void *newelem) {
    setelemT *sizep;  /* Avoid strict aliasing.  Writing to *endp may overwrite *sizep */
    setelemT *endp, *lastp;
    int count;

    if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {
        qh_setlarger(setp);
        sizep= SETsizeaddr_(*setp);
    }
    count= (sizep->i)++ - 1;
    endp= (setelemT *)SETelemaddr_(*setp, count, void); /* NULL */
    lastp= endp-1;
    *(endp++)= *lastp;
    endp->p= NULL;    /* may overwrite *sizep */
    lastp->p= newelem;
} /* setappend2ndlast */

/*---------------------------------

  qh_setcheck( set, typename, id )
    check set for validity
    report errors with typename and id

  design:
    checks that maxsize, actual size, and NULL terminator agree
*/
void qh_setcheck(setT *set, const char *tname, unsigned int id) {
  int maxsize, size;
  int waserr= 0;

  if (!set)
    return;
  SETreturnsize_(set, size);
  maxsize= set->maxsize;
  if (size > maxsize || !maxsize) {
    qh_fprintf(qhmem.ferr, 6172, "qhull internal error (qh_setcheck): actual size %d of %s%d is greater than max size %d\n",
             size, tname, id, maxsize);
    waserr= 1;
  }else if (set->e[size].p) {
    qh_fprintf(qhmem.ferr, 6173, "qhull internal error (qh_setcheck): %s%d(size %d max %d) is not null terminated.\n",
             tname, id, size-1, maxsize);
    waserr= 1;
  }
  if (waserr) {
    qh_setprint(qhmem.ferr, "ERRONEOUS", set);
    qh_errexit(qhmem_ERRqhull, NULL, NULL);
  }
} /* setcheck */


/*---------------------------------

  qh_setcompact( set )
    remove internal NULLs from an unsorted set

  returns:
    updated set

  notes:
    set may be NULL
    it would be faster to swap tail of set into holes, like qh_setdel

  design:
    setup pointers into set
    skip NULLs while copying elements to start of set
    update the actual size
*/
void qh_setcompact(setT *set) {
  int size;
  void **destp, **elemp, **endp, **firstp;

  if (!set)
    return;
  SETreturnsize_(set, size);
  destp= elemp= firstp= SETaddr_(set, void);
  endp= destp + size;
  while (1) {
    if (!(*destp++= *elemp++)) {
      destp--;
      if (elemp > endp)
        break;
    }
  }
  qh_settruncate(set, (int)(destp-firstp));   /* WARN64 */
} /* setcompact */


/*---------------------------------

  qh_setcopy( set, extra )
    make a copy of a sorted or unsorted set with extra slots

  returns:
    new set

  design:
    create a newset with extra slots
    copy the elements to the newset

*/
setT *qh_setcopy(setT *set, int extra) {
  setT *newset;
  int size;

  if (extra < 0)
    extra= 0;
  SETreturnsize_(set, size);
  newset= qh_setnew(size+extra);
  SETsizeaddr_(newset)->i= size+1;    /* memcpy may overwrite */
  memcpy((char *)&(newset->e[0].p), (char *)&(set->e[0].p), (size_t)(size+1) * SETelemsize);
  return(newset);
} /* setcopy */


/*---------------------------------

  qh_setdel(set, oldelem )
    delete oldelem from an unsorted set

  returns:
    returns oldelem if found
    returns NULL otherwise

  notes:
    set may be NULL
    oldelem must not be NULL;
    only deletes one copy of oldelem in set

  design:
    locate oldelem
    update actual size if it was full
    move the last element to the oldelem's location
*/
void *qh_setdel(setT *set, void *oldelem) {
  setelemT *sizep;
  setelemT *elemp;
  setelemT *lastp;

  if (!set)
    return NULL;
  elemp= (setelemT *)SETaddr_(set, void);
  while (elemp->p != oldelem && elemp->p)
    elemp++;
  if (elemp->p) {
    sizep= SETsizeaddr_(set);
    if (!(sizep->i)--)         /*  if was a full set */
      sizep->i= set->maxsize;  /*     *sizep= (maxsize-1)+ 1 */
    lastp= (setelemT *)SETelemaddr_(set, sizep->i-1, void);
    elemp->p= lastp->p;      /* may overwrite itself */
    lastp->p= NULL;
    return oldelem;
  }
  return NULL;
} /* setdel */


/*---------------------------------

  qh_setdellast( set )
    return last element of set or NULL

  notes:
    deletes element from set
    set may be NULL

  design:
    return NULL if empty
    if full set
      delete last element and set actual size
    else
      delete last element and update actual size
*/
void *qh_setdellast(setT *set) {
  int setsize;  /* actually, actual_size + 1 */
  int maxsize;
  setelemT *sizep;
  void *returnvalue;

  if (!set || !(set->e[0].p))
    return NULL;
  sizep= SETsizeaddr_(set);
  if ((setsize= sizep->i)) {
    returnvalue= set->e[setsize - 2].p;
    set->e[setsize - 2].p= NULL;
    sizep->i--;
  }else {
    maxsize= set->maxsize;
    returnvalue= set->e[maxsize - 1].p;
    set->e[maxsize - 1].p= NULL;
    sizep->i= maxsize;
  }
  return returnvalue;
} /* setdellast */


/*---------------------------------

  qh_setdelnth( set, nth )
    deletes nth element from unsorted set
    0 is first element

  returns:
    returns the element (needs type conversion)

  notes:
    errors if nth invalid

  design:
    setup points and check nth
    delete nth element and overwrite with last element
*/
void *qh_setdelnth(setT *set, int nth) {
  void *elem;
  setelemT *sizep;
  setelemT *elemp, *lastp;

  sizep= SETsizeaddr_(set);
  if ((sizep->i--)==0)         /*  if was a full set */
    sizep->i= set->maxsize;    /*    *sizep= (maxsize-1)+ 1 */
  if (nth < 0 || nth >= sizep->i) {
    qh_fprintf(qhmem.ferr, 6174, "qhull internal error (qh_setdelnth): nth %d is out-of-bounds for set:\n", nth);
    qh_setprint(qhmem.ferr, "", set);
    qh_errexit(qhmem_ERRqhull, NULL, NULL);
  }
  elemp= (setelemT *)SETelemaddr_(set, nth, void); /* nth valid by QH6174 */
  lastp= (setelemT *)SETelemaddr_(set, sizep->i-1, void);
  elem= elemp->p;
  elemp->p= lastp->p;      /* may overwrite itself */
  lastp->p= NULL;
  return elem;
} /* setdelnth */

/*---------------------------------

  qh_setdelnthsorted( set, nth )
    deletes nth element from sorted set

  returns:
    returns the element (use type conversion)

  notes:
    errors if nth invalid

  see also:
    setnew_delnthsorted

  design:
    setup points and check nth
    copy remaining elements down one
    update actual size
*/
void *qh_setdelnthsorted(setT *set, int nth) {
  void *elem;
  setelemT *sizep;
  setelemT *newp, *oldp;

  sizep= SETsizeaddr_(set);
  if (nth < 0 || (sizep->i && nth >= sizep->i-1) || nth >= set->maxsize) {
    qh_fprintf(qhmem.ferr, 6175, "qhull internal error (qh_setdelnthsorted): nth %d is out-of-bounds for set:\n", nth);
    qh_setprint(qhmem.ferr, "", set);
    qh_errexit(qhmem_ERRqhull, NULL, NULL);
  }
  newp= (setelemT *)SETelemaddr_(set, nth, void);
  elem= newp->p;
  oldp= newp+1;
  while (((newp++)->p= (oldp++)->p))
    ; /* copy remaining elements and NULL */
  if ((sizep->i--)==0)         /*  if was a full set */
    sizep->i= set->maxsize;  /*     *sizep= (max size-1)+ 1 */
  return elem;
} /* setdelnthsorted */


/*---------------------------------

  qh_setdelsorted( set, oldelem )
    deletes oldelem from sorted set

  returns:
    returns oldelem if it was deleted

  notes:
    set may be NULL

  design:
    locate oldelem in set
    copy remaining elements down one
    update actual size
*/
void *qh_setdelsorted(setT *set, void *oldelem) {
  setelemT *sizep;
  setelemT *newp, *oldp;

  if (!set)
    return NULL;
  newp= (setelemT *)SETaddr_(set, void);
  while(newp->p != oldelem && newp->p)
    newp++;
  if (newp->p) {
    oldp= newp+1;
    while (((newp++)->p= (oldp++)->p))
      ; /* copy remaining elements */
    sizep= SETsizeaddr_(set);
    if ((sizep->i--)==0)    /*  if was a full set */
      sizep->i= set->maxsize;  /*     *sizep= (max size-1)+ 1 */
    return oldelem;
  }
  return NULL;
} /* setdelsorted */


/*---------------------------------

  qh_setduplicate( set, elemsize )
    duplicate a set of elemsize elements

  notes:
    use setcopy if retaining old elements

  design:
    create a new set
    for each elem of the old set
      create a newelem
      append newelem to newset
*/
setT *qh_setduplicate(setT *set, int elemsize) {
  void          *elem, **elemp, *newElem;
  setT          *newSet;
  int           size;

  if (!(size= qh_setsize(set)))
    return NULL;
  newSet= qh_setnew(size);
  FOREACHelem_(set) {
    newElem= qh_memalloc(elemsize);
    memcpy(newElem, elem, (size_t)elemsize);
    qh_setappend(&newSet, newElem);
  }
  return newSet;
} /* setduplicate */


/*---------------------------------

  qh_setendpointer( set )
    Returns pointer to NULL terminator of a set's elements
    set can not be NULL

*/
void **qh_setendpointer(setT *set) {

  setelemT *sizep= SETsizeaddr_(set);
  int n= sizep->i;
  return (n ? &set->e[n-1].p : &sizep->p);
} /* qh_setendpointer */

/*---------------------------------

  qh_setequal( setA, setB )
    returns 1 if two sorted sets are equal, otherwise returns 0

  notes:
    either set may be NULL

  design:
    check size of each set
    setup pointers
    compare elements of each set
*/
int qh_setequal(setT *setA, setT *setB) {
  void **elemAp, **elemBp;
  int sizeA= 0, sizeB= 0;

  if (setA) {
    SETreturnsize_(setA, sizeA);
  }
  if (setB) {
    SETreturnsize_(setB, sizeB);
  }
  if (sizeA != sizeB)
    return 0;
  if (!sizeA)
    return 1;
  elemAp= SETaddr_(setA, void);
  elemBp= SETaddr_(setB, void);
  if (!memcmp((char *)elemAp, (char *)elemBp, (size_t)(sizeA * SETelemsize)))
    return 1;
  return 0;
} /* setequal */


/*---------------------------------

  qh_setequal_except( setA, skipelemA, setB, skipelemB )
    returns 1 if sorted setA and setB are equal except for skipelemA & B

  returns:
    false if either skipelemA or skipelemB are missing

  notes:
    neither set may be NULL

    if skipelemB is NULL,
      can skip any one element of setB

  design:
    setup pointers
    search for skipelemA, skipelemB, and mismatches
    check results
*/
int qh_setequal_except(setT *setA, void *skipelemA, setT *setB, void *skipelemB) {
  void **elemA, **elemB;
  int skip=0;

  elemA= SETaddr_(setA, void);
  elemB= SETaddr_(setB, void);
  while (1) {
    if (*elemA == skipelemA) {
      skip++;
      elemA++;
    }
    if (skipelemB) {
      if (*elemB == skipelemB) {
        skip++;
        elemB++;
      }
    }else if (*elemA != *elemB) {
      skip++;
      if (!(skipelemB= *elemB++))
        return 0;
    }
    if (!*elemA)
      break;
    if (*elemA++ != *elemB++)
      return 0;
  }
  if (skip != 2 || *elemB)
    return 0;
  return 1;
} /* setequal_except */


/*---------------------------------

  qh_setequal_skip( setA, skipA, setB, skipB )
    returns 1 if sorted setA and setB are equal except for elements skipA & B

  returns:
    false if different size

  notes:
    neither set may be NULL

  design:
    setup pointers
    search for mismatches while skipping skipA and skipB
*/
int qh_setequal_skip(setT *setA, int skipA, setT *setB, int skipB) {
  void **elemA, **elemB, **skipAp, **skipBp;

  elemA= SETaddr_(setA, void);
  elemB= SETaddr_(setB, void);
  skipAp= SETelemaddr_(setA, skipA, void);
  skipBp= SETelemaddr_(setB, skipB, void);
  while (1) {
    if (elemA == skipAp)
      elemA++;
    if (elemB == skipBp)
      elemB++;
    if (!*elemA)
      break;
    if (*elemA++ != *elemB++)
      return 0;
  }
  if (*elemB)
    return 0;
  return 1;
} /* setequal_skip */


/*---------------------------------

  qh_setfree( setp )
    frees the space occupied by a sorted or unsorted set

  returns:
    sets setp to NULL

  notes:
    set may be NULL

  design:
    free array
    free set
*/
void qh_setfree(setT **setp) {
  int size;
  void **freelistp;  /* used if !qh_NOmem by qh_memfree_() */

  if (*setp) {
    size= (int)sizeof(setT) + ((*setp)->maxsize)*SETelemsize;
    if (size <= qhmem.LASTsize) {
      qh_memfree_(*setp, size, freelistp);
    }else
      qh_memfree(*setp, size);
    *setp= NULL;
  }
} /* setfree */


/*---------------------------------

  qh_setfree2( setp, elemsize )
    frees the space occupied by a set and its elements

  notes:
    set may be NULL

  design:
    free each element
    free set
*/
void qh_setfree2(setT **setp, int elemsize) {
  void          *elem, **elemp;

  FOREACHelem_(*setp)
    qh_memfree(elem, elemsize);
  qh_setfree(setp);
} /* setfree2 */



/*---------------------------------

  qh_setfreelong( setp )
    frees a set only if it's in long memory

  returns:
    sets setp to NULL if it is freed

  notes:
    set may be NULL

  design:
    if set is large
      free it
*/
void qh_setfreelong(setT **setp) {
  int size;

  if (*setp) {
    size= (int)sizeof(setT) + ((*setp)->maxsize)*SETelemsize;
    if (size > qhmem.LASTsize) {
      qh_memfree(*setp, size);
      *setp= NULL;
    }
  }
} /* setfreelong */


/*---------------------------------

  qh_setin( set, setelem )
    returns 1 if setelem is in a set, 0 otherwise

  notes:
    set may be NULL or unsorted

  design:
    scans set for setelem
*/
int qh_setin(setT *set, void *setelem) {
  void *elem, **elemp;

  FOREACHelem_(set) {
    if (elem == setelem)
      return 1;
  }
  return 0;
} /* setin */


/*---------------------------------

  qh_setindex(set, atelem )
    returns the index of atelem in set.
    returns -1, if not in set or maxsize wrong

  notes:
    set may be NULL and may contain nulls.
    NOerrors returned (qh_pointid, QhullPoint::id)

  design:
    checks maxsize
    scans set for atelem
*/
int qh_setindex(setT *set, void *atelem) {
  void **elem;
  int size, i;

  if (!set)
    return -1;
  SETreturnsize_(set, size);
  if (size > set->maxsize)
    return -1;
  elem= SETaddr_(set, void);
  for (i=0; i < size; i++) {
    if (*elem++ == atelem)
      return i;
  }
  return -1;
} /* setindex */


/*---------------------------------

  qh_setlarger( oldsetp )
    returns a larger set that contains all elements of *oldsetp

  notes:
    if long memory,
      the new set is 2x larger
    if qhmem.LASTsize is between 1.5x and 2x
      the new set is qhmem.LASTsize
    otherwise use quick memory,
      the new set is 2x larger, rounded up to next qh_memsize
       
    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 setsize= 1, newsize;
  setT *newset, *set, **setp, *oldset;
  setelemT *sizep;
  setelemT *newp, *oldp;

  if (*oldsetp) {
    oldset= *oldsetp;
    SETreturnsize_(oldset, setsize);
    qhmem.cntlarger++;
    qhmem.totlarger += setsize+1;
    qh_setlarger_quick(setsize, &newsize);
    newset= qh_setnew(newsize);
    oldp= (setelemT *)SETaddr_(oldset, void);
    newp= (setelemT *)SETaddr_(newset, void);
    memcpy((char *)newp, (char *)oldp, (size_t)(setsize+1) * SETelemsize);
    sizep= SETsizeaddr_(newset);
    sizep->i= setsize+1;
    FOREACHset_((setT *)qhmem.tempstack) {
      if (set == oldset)
        *(setp-1)= newset;
    }
    qh_setfree(oldsetp);
  }else
    newset= qh_setnew(3);
  *oldsetp= newset;
} /* setlarger */


/*---------------------------------

  qh_setlarger_quick( setsize, newsize )
    determine newsize for setsize
    returns True if newsize fits in quick memory

  design:
    if 2x fits into quick memory
      return True, 2x
    if x+4 does not fit into quick memory
      return False, 2x
    if x+x/3 fits into quick memory
      return True, the last quick set
    otherwise
      return False, 2x
*/
int qh_setlarger_quick(int setsize, int *newsize) {
    int lastquickset;

    *newsize= 2 * setsize;
    lastquickset= (qhmem.LASTsize - (int)sizeof(setT)) / SETelemsize; /* matches size computation in qh_setnew */
    if (*newsize <= lastquickset)
      return 1;
    if (setsize + 4 > lastquickset)
      return 0;
    if (setsize + setsize/3 <= lastquickset) {
      *newsize= lastquickset;
      return 1;
    }
    return 0;
} /* setlarger_quick */

/*---------------------------------

  qh_setlast( set )
    return last element of set or NULL (use type conversion)

  notes:
    set may be NULL

  design:
    return last element
*/
void *qh_setlast(setT *set) {
  int size;

  if (set) {
    size= SETsizeaddr_(set)->i;
    if (!size)
      return SETelem_(set, set->maxsize - 1);
    else if (size > 1)
      return SETelem_(set, size - 2);
  }
  return NULL;
} /* setlast */


/*---------------------------------

  qh_setnew( setsize )
    creates and allocates space for a set

  notes:
    setsize means the number of elements (!including the NULL terminator)
    use qh_settemp/qh_setfreetemp if set is temporary

  design:
    allocate memory for set
    roundup memory if small set
    initialize as empty set
*/
setT *qh_setnew(int setsize) {
  setT *set;
  int sizereceived; /* used if !qh_NOmem */
  int size;
  void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */

  if (!setsize)
    setsize++;
  size= (int)sizeof(setT) + setsize * SETelemsize; /* setT includes NULL terminator, see qh.LASTquickset */
  if (size>0 && size <= qhmem.LASTsize) {
    qh_memalloc_(size, freelistp, set, setT);
#ifndef qh_NOmem
    sizereceived= qhmem.sizetable[ qhmem.indextable[size]];
    if (sizereceived > size)
      setsize += (sizereceived - size)/SETelemsize;
#endif
  }else
    set= (setT *)qh_memalloc(size);
  set->maxsize= setsize;
  set->e[setsize].i= 1;
  set->e[0].p= NULL;
  return(set);
} /* setnew */


/*---------------------------------

  qh_setnew_delnthsorted( set, size, nth, prepend )
    creates a sorted set not containing nth element
    if prepend, the first prepend elements are undefined

  notes:
    set must be defined
    checks nth
    see also: setdelnthsorted

  design:
    create new set
    setup pointers and allocate room for prepend'ed entries
    append head of old set to new set
    append tail of old set to new set
*/
setT *qh_setnew_delnthsorted(setT *set, int size, int nth, int prepend) {
  setT *newset;
  void **oldp, **newp;
  int tailsize= size - nth -1, newsize;

  if (tailsize < 0) {
    qh_fprintf(qhmem.ferr, 6176, "qhull internal error (qh_setnew_delnthsorted): nth %d is out-of-bounds for set:\n", nth);
    qh_setprint(qhmem.ferr, "", set);
    qh_errexit(qhmem_ERRqhull, NULL, NULL);
  }
  newsize= size-1 + prepend;
  newset= qh_setnew(newsize);
  newset->e[newset->maxsize].i= newsize+1;  /* may be overwritten */
  oldp= SETaddr_(set, void);
  newp= SETaddr_(newset, void) + prepend;
  switch (nth) {
  case 0:
    break;
  case 1:
    *(newp++)= *oldp++;
    break;
  case 2:
    *(newp++)= *oldp++;
    *(newp++)= *oldp++;
    break;
  case 3:
    *(newp++)= *oldp++;
    *(newp++)= *oldp++;
    *(newp++)= *oldp++;
    break;
  case 4:
    *(newp++)= *oldp++;
    *(newp++)= *oldp++;
    *(newp++)= *oldp++;
    *(newp++)= *oldp++;
    break;
  default:
    memcpy((char *)newp, (char *)oldp, (size_t)nth * SETelemsize);
    newp += nth;
    oldp += nth;
    break;
  }
  oldp++;
  switch (tailsize) {
  case 0:
    break;
  case 1:
    *(newp++)= *oldp++;
    break;
  case 2:
    *(newp++)= *oldp++;
    *(newp++)= *oldp++;
    break;
  case 3:
    *(newp++)= *oldp++;
    *(newp++)= *oldp++;
    *(newp++)= *oldp++;
    break;
  case 4:
    *(newp++)= *oldp++;
    *(newp++)= *oldp++;
    *(newp++)= *oldp++;
    *(newp++)= *oldp++;
    break;
  default:
    memcpy((char *)newp, (char *)oldp, (size_t)tailsize * SETelemsize);
    newp += tailsize;
  }
  *newp= NULL;
  return(newset);
} /* setnew_delnthsorted */


/*---------------------------------

  qh_setprint( fp, string, set )
    print set elements to fp with identifying string

  notes:
    never errors
*/
void qh_setprint(FILE *fp, const char* string, setT *set) {
  int size, k;

  if (!set)
    qh_fprintf(fp, 9346, "%s set is null\n", string);
  else {
    SETreturnsize_(set, size);
    qh_fprintf(fp, 9347, "%s set=%p maxsize=%d size=%d elems=",
             string, set, set->maxsize, size);
    if (size > set->maxsize)
      size= set->maxsize+1;
    for (k=0; k < size; k++)
      qh_fprintf(fp, 9348, " %p", set->e[k].p);
    qh_fprintf(fp, 9349, "\n");
  }
} /* setprint */

/*---------------------------------

  qh_setreplace( set, oldelem, newelem )
    replaces oldelem in set with newelem

  notes:
    errors if oldelem not in the set
    newelem may be NULL, but it turns the set into an indexed set (no FOREACH)

  design:
    find oldelem
    replace with newelem
*/
void qh_setreplace(setT *set, void *oldelem, void *newelem) {
  void **elemp;

  elemp= SETaddr_(set, void);
  while (*elemp != oldelem && *elemp)
    elemp++;
  if (*elemp)
    *elemp= newelem;
  else {
    qh_fprintf(qhmem.ferr, 6177, "qhull internal error (qh_setreplace): elem %p not found in set\n",
       oldelem);
    qh_setprint(qhmem.ferr, "", set);
    qh_errexit(qhmem_ERRqhull, NULL, NULL);
  }
} /* setreplace */


/*---------------------------------

  qh_setsize( set )
    returns the size of a set

  notes:
    errors if set's maxsize is incorrect
    same as SETreturnsize_(set)
    same code for qh_setsize [qset.c] and QhullSetBase::count
    if first element is NULL, SETempty_() is True but qh_setsize may be greater than 0

  design:
    determine actual size of set from maxsize
*/
int qh_setsize(setT *set) {
  int size;
  setelemT *sizep;

  if (!set)
    return(0);
  sizep= SETsizeaddr_(set);
  if ((size= sizep->i)) {
    size--;
    if (size > set->maxsize) {
      qh_fprintf(qhmem.ferr, 6178, "qhull internal error (qh_setsize): current set size %d is greater than maximum size %d\n",
               size, set->maxsize);
      qh_setprint(qhmem.ferr, "set: ", set);
      qh_errexit(qhmem_ERRqhull, NULL, NULL);
    }
  }else
    size= set->maxsize;
  return size;
} /* setsize */

/*---------------------------------

  qh_settemp( setsize )
    return a stacked, temporary set of up to setsize elements

  notes:
    use settempfree or settempfree_all to release from qhmem.tempstack
    see also qh_setnew

  design:
    allocate set
    append to qhmem.tempstack

*/
setT *qh_settemp(int setsize) {
  setT *newset;

  newset= qh_setnew(setsize);
  qh_setappend(&qhmem.tempstack, newset);
  if (qhmem.IStracing >= 5)
    qh_fprintf(qhmem.ferr, 8123, "qh_settemp: temp set %p of %d elements, depth %d\n",
       newset, newset->maxsize, qh_setsize(qhmem.tempstack));
  return newset;
} /* settemp */

/*---------------------------------

  qh_settempfree( set )
    free temporary set at top of qhmem.tempstack

  notes:
    nop if set is NULL
    errors if set not from previous   qh_settemp

  to locate errors:
    use 'T2' to find source and then find mis-matching qh_settemp

  design:
    check top of qhmem.tempstack
    free it
*/
void qh_settempfree(setT **set) {
  setT *stackedset;

  if (!*set)
    return;
  stackedset= qh_settemppop();
  if (stackedset != *set) {
    qh_settemppush(stackedset);
    qh_fprintf(qhmem.ferr, 6179, "qhull internal error (qh_settempfree): set %p(size %d) was not last temporary allocated(depth %d, set %p, size %d)\n",
             *set, qh_setsize(*set), qh_setsize(qhmem.tempstack)+1,
             stackedset, qh_setsize(stackedset));
    qh_errexit(qhmem_ERRqhull, NULL, NULL);
  }
  qh_setfree(set);
} /* settempfree */

/*---------------------------------

  qh_settempfree_all( )
    free all temporary sets in qhmem.tempstack

  design:
    for each set in tempstack
      free set
    free qhmem.tempstack
*/
void qh_settempfree_all(void) {
  setT *set, **setp;

  FOREACHset_(qhmem.tempstack)
    qh_setfree(&set);
  qh_setfree(&qhmem.tempstack);
} /* settempfree_all */

/*---------------------------------

  qh_settemppop( )
    pop and return temporary set from qhmem.tempstack

  notes:
    the returned set is permanent

  design:
    pop and check top of qhmem.tempstack
*/
setT *qh_settemppop(void) {
  setT *stackedset;

  stackedset= (setT *)qh_setdellast(qhmem.tempstack);
  if (!stackedset) {
    qh_fprintf(qhmem.ferr, 6180, "qhull internal error (qh_settemppop): pop from empty temporary stack\n");
    qh_errexit(qhmem_ERRqhull, NULL, NULL);
  }
  if (qhmem.IStracing >= 5)
    qh_fprintf(qhmem.ferr, 8124, "qh_settemppop: depth %d temp set %p of %d elements\n",
       qh_setsize(qhmem.tempstack)+1, stackedset, qh_setsize(stackedset));
  return stackedset;
} /* settemppop */

/*---------------------------------

  qh_settemppush( set )
    push temporary set unto qhmem.tempstack (makes it temporary)

  notes:
    duplicates settemp() for tracing

  design:
    append set to tempstack
*/
void qh_settemppush(setT *set) {
  if (!set) {
    qh_fprintf(qhmem.ferr, 6267, "qhull error (qh_settemppush): can not push a NULL temp\n");
    qh_errexit(qhmem_ERRqhull, NULL, NULL);
  }
  qh_setappend(&qhmem.tempstack, set);
  if (qhmem.IStracing >= 5)
    qh_fprintf(qhmem.ferr, 8125, "qh_settemppush: depth %d temp set %p of %d elements\n",
      qh_setsize(qhmem.tempstack), set, qh_setsize(set));
} /* settemppush */


/*---------------------------------

  qh_settruncate( set, size )
    truncate set to size elements

  notes:
    set must be defined

  see:
    SETtruncate_

  design:
    check size
    update actual size of set
*/
void qh_settruncate(setT *set, int size) {

  if (size < 0 || size > set->maxsize) {
    qh_fprintf(qhmem.ferr, 6181, "qhull internal error (qh_settruncate): size %d out of bounds for set:\n", size);
    qh_setprint(qhmem.ferr, "", set);
    qh_errexit(qhmem_ERRqhull, NULL, NULL);
  }
  set->e[set->maxsize].i= size+1;   /* maybe overwritten */
  set->e[size].p= NULL;
} /* settruncate */

/*---------------------------------

  qh_setunique( set, elem )
    add elem to unsorted set unless it is already in set

  notes:
    returns 1 if it is appended

  design:
    if elem not in set
      append elem to set
*/
int qh_setunique(setT **set, void *elem) {

  if (!qh_setin(*set, elem)) {
    qh_setappend(set, elem);
    return 1;
  }
  return 0;
} /* setunique */

/*---------------------------------

  qh_setzero( set, index, size )
    zero elements from index on
    set actual size of set to size

  notes:
    set must be defined
    the set becomes an indexed set (can not use FOREACH...)

  see also:
    qh_settruncate

  design:
    check index and size
    update actual size
    zero elements starting at e[index]
*/
void qh_setzero(setT *set, int idx, int size) {
  int count;

  if (idx < 0 || idx >= size || size > set->maxsize) {
    qh_fprintf(qhmem.ferr, 6182, "qhull internal error (qh_setzero): index %d or size %d out of bounds for set:\n", idx, size);
    qh_setprint(qhmem.ferr, "", set);
    qh_errexit(qhmem_ERRqhull, NULL, NULL);
  }
  set->e[set->maxsize].i=  size+1;  /* may be overwritten */
  count= size - idx + 1;   /* +1 for NULL terminator */
  memset((char *)SETelemaddr_(set, idx, void), 0, (size_t)count * SETelemsize);
} /* setzero */


qhull-2020.2/src/libqhull/qset.h0000644060175106010010000003542113661631132014725 0ustar  bbarber/*
  ---------------------------------

   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-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull/qset.h#4 $$Change: 2953 $
   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
*/

#ifndef qhDEFset
#define qhDEFset 1

#include 

/*================= -structures- ===============*/

#ifndef DEFsetT
#define DEFsetT 1
typedef struct setT setT;   /* a set is a sorted or unsorted array of pointers */
#endif

/* [jan'15] Decided not to use countT.  Most sets are small.  The code uses signed tests */

/*------------------------------------------

setT
  a set or list of pointers with maximum size and actual size.

variations:
  unsorted, unique   -- a list of unique pointers with NULL terminator
                           user guarantees uniqueness
  sorted             -- a sorted list of unique pointers with NULL terminator
                           qset.c guarantees uniqueness
  unsorted           -- a list of pointers terminated with NULL
  indexed            -- an array of pointers with NULL elements

structure for set of n elements:

        --------------
        |  maxsize
        --------------
        |  e[0] - a pointer, may be NULL for indexed sets
        --------------
        |  e[1]

        --------------
        |  ...
        --------------
        |  e[n-1]
        --------------
        |  e[n] = NULL
        --------------
        |  ...
        --------------
        |  e[maxsize] - n+1 or NULL (determines actual size of set)
        --------------

*/

/*-- setelemT -- internal type to allow both pointers and indices
*/
typedef union setelemT setelemT;
union setelemT {
  void    *p;
  int   i;         /* integer used for e[maxSize] */
};

struct setT {
  int maxsize;          /* maximum number of elements (except NULL) */
  setelemT e[1];        /* array of pointers, tail is NULL */
                        /* last slot (unless NULL) is actual size+1
                           e[maxsize]==NULL or e[e[maxsize]-1]==NULL */
                        /* this may generate a warning since e[] contains
                           maxsize elements */
};

/*=========== -constants- =========================*/

/*-------------------------------------

  SETelemsize
    size of a set element in bytes
*/
#define SETelemsize ((int)sizeof(setelemT))


/*=========== -macros- =========================*/

/*-------------------------------------

   FOREACHsetelement_(type, set, variable)
     define FOREACH iterator

   declare:
     assumes *variable and **variablep are declared
     no space in "variable)" [DEC Alpha cc compiler]

   each iteration:
     variable is set element
     variablep is one beyond variable.

   to repeat an element:
     variablep--; / *repeat* /

   at exit:
     variable is NULL at end of loop

   example:
     #define FOREACHfacet_(facets) FOREACHsetelement_(facetT, facets, facet)

   notes:
     use FOREACHsetelement_i_() if need index or include NULLs
     assumes set is not modified

   WARNING:
     nested loops can't use the same variable (define another FOREACH)

     needs braces if nested inside another FOREACH
     this includes intervening blocks, e.g. FOREACH...{ if () FOREACH...} )
*/
#define FOREACHsetelement_(type, set, variable) \
        if (((variable= NULL), set)) for (\
          variable##p= (type **)&((set)->e[0].p); \
          (variable= *variable##p++);)

/*------------------------------------------

   FOREACHsetelement_i_(type, set, variable)
     define indexed FOREACH iterator

   declare:
     type *variable, variable_n, variable_i;

   each iteration:
     variable is set element, may be NULL
     variable_i is index, variable_n is qh_setsize()

   to repeat an element:
     variable_i--; variable_n-- repeats for deleted element

   at exit:
     variable==NULL and variable_i==variable_n

   example:
     #define FOREACHfacet_i_(facets) FOREACHsetelement_i_(facetT, facets, facet)

   WARNING:
     nested loops can't use the same variable (define another FOREACH)

     needs braces if nested inside another FOREACH
     this includes intervening blocks, e.g. FOREACH...{ if () FOREACH...} )
*/
#define FOREACHsetelement_i_(type, set, variable) \
        if (((variable= NULL), set)) for (\
          variable##_i= 0, variable= (type *)((set)->e[0].p), \
                   variable##_n= qh_setsize(set);\
          variable##_i < variable##_n;\
          variable= (type *)((set)->e[++variable##_i].p) )

/*----------------------------------------

   FOREACHsetelementreverse_(type, set, variable)-
     define FOREACH iterator in reverse order

   declare:
     assumes *variable and **variablep are declared
     also declare 'int variabletemp'

   each iteration:
     variable is set element

   to repeat an element:
     variabletemp++; / *repeat* /

   at exit:
     variable is NULL

   example:
     #define FOREACHvertexreverse_(vertices) FOREACHsetelementreverse_(vertexT, vertices, vertex)

   notes:
     use FOREACHsetelementreverse12_() to reverse first two elements
     WARNING: needs braces if nested inside another FOREACH
*/
#define FOREACHsetelementreverse_(type, set, variable) \
        if (((variable= NULL), set)) for (\
           variable##temp= qh_setsize(set)-1, variable= qh_setlast(set);\
           variable; variable= \
           ((--variable##temp >= 0) ? SETelemt_(set, variable##temp, type) : NULL))

/*-------------------------------------

   FOREACHsetelementreverse12_(type, set, variable)-
     define FOREACH iterator with e[1] and e[0] reversed

   declare:
     assumes *variable and **variablep are declared

   each iteration:
     variable is set element
     variablep is one after variable.

   to repeat an element:
     variablep--; / *repeat* /

   at exit:
     variable is NULL at end of loop

   example
     #define FOREACHvertexreverse12_(vertices) FOREACHsetelementreverse12_(vertexT, vertices, vertex)

   notes:
     WARNING: needs braces if nested inside another FOREACH
*/
#define FOREACHsetelementreverse12_(type, set, variable) \
        if (((variable= NULL), set)) for (\
          variable##p= (type **)&((set)->e[1].p); \
          (variable= *variable##p); \
          variable##p == ((type **)&((set)->e[0].p))?variable##p += 2: \
              (variable##p == ((type **)&((set)->e[1].p))?variable##p--:variable##p++))

/*-------------------------------------

   FOREACHelem_( set )-
     iterate elements in a set

   declare:
     void *elem, *elemp;

   each iteration:
     elem is set element
     elemp is one beyond

   to repeat an element:
     elemp--; / *repeat* /

   at exit:
     elem == NULL at end of loop

   example:
     FOREACHelem_(set) {

   notes:
     assumes set is not modified
     WARNING: needs braces if nested inside another FOREACH
*/
#define FOREACHelem_(set) FOREACHsetelement_(void, set, elem)

/*-------------------------------------

   FOREACHset_( set )-
     iterate a set of sets

   declare:
     setT *set, **setp;

   each iteration:
     set is set element
     setp is one beyond

   to repeat an element:
     setp--; / *repeat* /

   at exit:
     set == NULL at end of loop

   example
     FOREACHset_(sets) {

   notes:
     WARNING: needs braces if nested inside another FOREACH
*/
#define FOREACHset_(sets) FOREACHsetelement_(setT, sets, set)

/*-------------------------------------------

   SETindex_( set, elem )
     return index of elem in set

   notes:
     for use with FOREACH iteration
     WARN64 -- Maximum set size is 2G

   example:
     i= SETindex_(ridges, ridge)
*/
#define SETindex_(set, elem) ((int)((void **)elem##p - (void **)&(set)->e[1].p))

/*-----------------------------------------

   SETref_( elem )
     l.h.s. for modifying the current element in a FOREACH iteration

   example:
     SETref_(ridge)= anotherridge;
*/
#define SETref_(elem) (elem##p[-1])

/*-----------------------------------------

   SETelem_(set, n)
     return the n'th element of set

   notes:
      assumes that n is valid [0..size] and that set is defined
      use SETelemt_() for type cast
*/
#define SETelem_(set, n)           ((set)->e[n].p)

/*-----------------------------------------

   SETelemt_(set, n, type)
     return the n'th element of set as a type

   notes:
      assumes that n is valid [0..size] and that set is defined
*/
#define SETelemt_(set, n, type)    ((type *)((set)->e[n].p))

/*-----------------------------------------

   SETelemaddr_(set, n, type)
     return address of the n'th element of a set

   notes:
      assumes that n is valid [0..size] and set is defined
*/
#define SETelemaddr_(set, n, type) ((type **)(&((set)->e[n].p)))

/*-----------------------------------------

   SETfirst_(set)
     return first element of set

*/
#define SETfirst_(set)             ((set)->e[0].p)

/*-----------------------------------------

   SETfirstt_(set, type)
     return first element of set as a type

*/
#define SETfirstt_(set, type)      ((type *)((set)->e[0].p))

/*-----------------------------------------

   SETsecond_(set)
     return second element of set

*/
#define SETsecond_(set)            ((set)->e[1].p)

/*-----------------------------------------

   SETsecondt_(set, type)
     return second element of set as a type
*/
#define SETsecondt_(set, type)     ((type *)((set)->e[1].p))

/*-----------------------------------------

   SETaddr_(set, type)
       return address of set's elements
*/
#define SETaddr_(set,type)         ((type **)(&((set)->e[0].p)))

/*-----------------------------------------

   SETreturnsize_(set, size)
     return size of a set

   notes:
      set must be defined
      use qh_setsize(set) unless speed is critical
*/
#define SETreturnsize_(set, size) (((size)= ((set)->e[(set)->maxsize].i))?(--(size)):((size)= (set)->maxsize))

/*-----------------------------------------

   SETempty_(set)
     return true(1) if set is empty (i.e., FOREACHsetelement_ is empty)

   notes:
      set may be NULL
      qh_setsize may be non-zero if first element is NULL
*/
#define SETempty_(set)            (!set || (SETfirst_(set) ? 0 : 1))

/*---------------------------------

  SETsizeaddr_(set)
    return pointer to 'actual size+1' of set (set CANNOT be NULL!!)
    Its type is setelemT* for strict aliasing
    All SETelemaddr_ must be cast to setelemT


  notes:
    *SETsizeaddr==NULL or e[*SETsizeaddr-1].p==NULL
*/
#define SETsizeaddr_(set) (&((set)->e[(set)->maxsize]))

/*-----------------------------------------

   SETtruncate_(set, size)
     truncate set to size

   see:
     qh_settruncate()

*/
#define SETtruncate_(set, size) {set->e[set->maxsize].i= size+1; /* maybe overwritten */ \
      set->e[size].p= NULL;}

/*======= prototypes in alphabetical order ============*/

void  qh_setaddsorted(setT **setp, void *elem);
void  qh_setaddnth(setT **setp, int nth, void *newelem);
void  qh_setappend(setT **setp, void *elem);
void  qh_setappend_set(setT **setp, setT *setA);
void  qh_setappend2ndlast(setT **setp, void *elem);
void  qh_setcheck(setT *set, const char *tname, unsigned 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);
void **qh_setendpointer(setT *set);
int   qh_setequal(setT *setA, setT *setB);
int   qh_setequal_except(setT *setA, void *skipelemA, setT *setB, void *skipelemB);
int   qh_setequal_skip(setT *setA, int skipA, setT *setB, int skipB);
void  qh_setfree(setT **set);
void  qh_setfree2(setT **setp, int elemsize);
void  qh_setfreelong(setT **set);
int   qh_setin(setT *set, void *setelem);
int   qh_setindex(setT *set, void *setelem);
void  qh_setlarger(setT **setp);
int   qh_setlarger_quick(int setsize, int *newsize);
void *qh_setlast(setT *set);
setT *qh_setnew(int size);
setT *qh_setnew_delnthsorted(setT *set, int size, int nth, int prepend);
void  qh_setprint(FILE *fp, const char* string, setT *set);
void  qh_setreplace(setT *set, void *oldelem, void *newelem);
int   qh_setsize(setT *set);
setT *qh_settemp(int setsize);
void  qh_settempfree(setT **set);
void  qh_settempfree_all(void);
setT *qh_settemppop(void);
void  qh_settemppush(setT *set);
void  qh_settruncate(setT *set, int size);
int   qh_setunique(setT **set, void *elem);
void  qh_setzero(setT *set, int idx, int size);

#endif /* qhDEFset */
qhull-2020.2/src/libqhull/random.c0000644060175106010010000001460613505243373015231 0ustar  bbarber/*
  ---------------------------------

   random.c and utilities
     Park & Miller's minimimal standard random number generator
     argc/argv conversion

     Used by rbox.  Do not use 'qh' 
*/

#include "libqhull.h"
#include "random.h"

#include 
#include 
#include 

#ifdef _MSC_VER  /* Microsoft Visual C++ -- warning level 4 */
#pragma warning( disable : 4706)  /* assignment within conditional function */
#pragma warning( disable : 4996)  /* function was declared deprecated(strcpy, localtime, etc.) */
#endif

/*---------------------------------

  qh_argv_to_command( argc, argv, command, max_size )

    build command from argc/argv
    max_size is at least

  returns:
    a space-delimited string of options (just as typed)
    returns false if max_size is too short

  notes:
    silently removes
    makes option string easy to input and output
    matches qh_argv_to_command_size
    argc may be 0
*/
int qh_argv_to_command(int argc, char *argv[], char* command, int max_size) {
  int i, remaining;
  char *s;
  *command= '\0';  /* max_size > 0 */

  if (argc) {
    if ((s= strrchr( argv[0], '\\')) /* get filename w/o .exe extension */
    || (s= strrchr( argv[0], '/')))
        s++;
    else
        s= argv[0];
    if ((int)strlen(s) < max_size)   /* WARN64 */
        strcpy(command, s);
    else
        goto error_argv;
    if ((s= strstr(command, ".EXE"))
    ||  (s= strstr(command, ".exe")))
        *s= '\0';
  }
  for (i=1; i < argc; i++) {
    s= argv[i];
    remaining= max_size - (int)strlen(command) - (int)strlen(s) - 2;   /* WARN64 */
    if (!*s || strchr(s, ' ')) {
      char *t= command + strlen(command);
      remaining -= 2;
      if (remaining < 0) {
        goto error_argv;
      }
      *t++= ' ';
      *t++= '"';
      while (*s) {
        if (*s == '"') {
          if (--remaining < 0)
            goto error_argv;
          *t++= '\\';
        }
        *t++= *s++;
      }
      *t++= '"';
      *t= '\0';
    }else if (remaining < 0) {
      goto error_argv;
    }else {
      strcat(command, " ");
      strcat(command, s);
    }
  }
  return 1;

error_argv:
  return 0;
} /* argv_to_command */

/*---------------------------------

  qh_argv_to_command_size( argc, argv )

    return size to allocate for qh_argv_to_command()

  notes:
    only called from rbox with qh_errexit not enabled
    caller should report error if returned size is less than 1
    argc may be 0
    actual size is usually shorter
*/
int qh_argv_to_command_size(int argc, char *argv[]) {
    int count= 1; /* null-terminator if argc==0 */
    int i;
    char *s;

    for (i=0; i0 && strchr(argv[i], ' ')) {
        count += 2;  /* quote delimiters */
        for (s=argv[i]; *s; s++) {
          if (*s == '"') {
            count++;
          }
        }
      }
    }
    return count;
} /* argv_to_command_size */

/*---------------------------------

  qh_rand()
  qh_srand( seed )
    generate pseudo-random number between 1 and 2^31 -2

  notes:
    For qhull and rbox, called from qh_RANDOMint(),etc. [user.h]

    From Park & Miller's minimal 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
*/

/* Global variables and constants */

int qh_last_random= 1;  /* define as global variable instead of using qh */

#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 qh_rand(void) {
    int lo, hi, test;
    int seed= qh_last_random;

    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_last_random= 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_last_random= 1;
    else if (seed >= qh_rand_m)
        qh_last_random= qh_rand_m - 1;
    else
        qh_last_random= seed;
} /* qh_srand */

/*---------------------------------

qh_randomfactor( scale, offset )
  return a random factor r * scale + offset

notes:
  qh.RANDOMa/b are defined in global.c
*/
realT qh_randomfactor(realT scale, realT offset) {
    realT randr;

    randr= qh_RANDOMint;
    return randr * scale + offset;
} /* randomfactor */

/*---------------------------------

  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 */

/*---------------------------------

  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);     /* WARN64 */
  if (s< (*endp) && (*endp)[-1] == ' ')
    (*endp)--;
  return result;
} /* strtol */
qhull-2020.2/src/libqhull/random.h0000644060175106010010000000166013661631132015227 0ustar  bbarber/*
  ---------------------------------

  random.h
    header file for random and utility routines

   see qh-geom.htm and random.c

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull/random.h#2 $$Change: 2953 $
   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
*/

#ifndef qhDEFrandom
#define qhDEFrandom 1

#include "libqhull.h"

/*============= prototypes in alphabetical order ======= */

int     qh_argv_to_command(int argc, char *argv[], char* command, int max_size);
int     qh_argv_to_command_size(int argc, char *argv[]);
int     qh_rand(void);
void    qh_srand(int seed);
realT   qh_randomfactor(realT scale, realT offset);
void    qh_randommatrix(realT *buffer, int dim, realT **row);
int     qh_strtol(const char *s, char **endp);
double  qh_strtod(const char *s, char **endp);

#endif /* qhDEFrandom */



qhull-2020.2/src/libqhull/rboxlib.c0000644060175106010010000006317713664273254015430 0ustar  bbarber/*
  ---------------------------------

   rboxlib.c
     Generate input points

   notes:
     For documentation, see prompt[] of rbox.c
     50 points generated for 'rbox D4'

   WARNING:
     incorrect range if qh_RANDOMmax is defined wrong (user.h)
*/

#include "libqhull.h"  /* First for user.h */
#include "random.h"

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#ifdef _MSC_VER  /* Microsoft Visual C++ */
#pragma warning( disable : 4706)  /* assignment within conditional expression. */
#pragma warning( disable : 4996)  /* this function (strncat,sprintf,strcpy) or variable may be unsafe. */
#endif

#define MAXdim 200
#define PI 3.1415926535897932384

/* ------------------------------ prototypes ----------------*/
int qh_roundi(double a);
void qh_out1(double a);
void qh_out2n(double a, double b);
void qh_out3n(double a, double b, double c);
void qh_outcoord(int iscdd, double *coord, int dim);
void qh_outcoincident(int coincidentpoints, double radius, int iscdd, double *coord, int dim);
void qh_rboxpoints2(char* rbox_command, double **simplex);

void    qh_fprintf_rbox(FILE *fp, int msgcode, const char *fmt, ... );
void    qh_free(void *mem);
void   *qh_malloc(size_t size);
int     qh_rand(void);
void    qh_srand(int seed);


/* ------------------------------ globals -------------------*/

/* No state is carried between rbox requests */
typedef struct rboxT rboxT;
struct rboxT {
  FILE *fout;
  FILE *ferr;
  int isinteger;
  double out_offset;
  jmp_buf errexit;        /* exit label for rboxpoints, defined by setjmp(), called by qh_errexit_rbox() */
  char  jmpXtra[40];      /* extra bytes in case jmp_buf is defined wrong by compiler */
};


int rbox_inuse= 0;
rboxT rbox;

/*---------------------------------

  qh_rboxpoints( fout, ferr, rbox_command )
    Generate points to fout according to rbox options
    Report errors on ferr

  returns:
    0 (qh_ERRnone) on success
    1 (qh_ERRinput) on input error
    4 (qh_ERRmem) on memory error
    5 (qh_ERRqhull) on internal error

  notes:
    To avoid using stdio, redefine qh_malloc, qh_free, and qh_fprintf_rbox (user.c)
    Split out qh_rboxpoints2() to avoid -Wclobbered

  design:
    Straight line code (consider defining a struct and functions):

    Parse arguments into variables
    Determine the number of points
    Generate the points
*/
int qh_rboxpoints(FILE* fout, FILE* ferr, char* rbox_command) {
  int exitcode;
  double *simplex;

  if (rbox_inuse) {
    qh_fprintf_stderr(6188, "rbox error: rbox in use by another process.  Please lock calls to rbox or use libqhull_r/rboxlib_r.c\n");
    return qh_ERRqhull;
  }
  rbox_inuse= True;
  rbox.ferr= ferr;
  rbox.fout= fout;
  
  simplex= NULL;
  exitcode= setjmp(rbox.errexit);
  if (exitcode) {
    /* same code for error exit and normal return.  qh.NOerrexit is set */
    if (simplex)
      qh_free(simplex);
    rbox_inuse= False;
    return exitcode;
  }
  qh_rboxpoints2(rbox_command, &simplex);
  /* same code for error exit and normal return */
  if (simplex)
    qh_free(simplex);
  rbox_inuse= False;
  return qh_ERRnone;
} /* rboxpoints */

void qh_rboxpoints2(char* rbox_command, double **simplex) {
  int i,j,k;
  int gendim;
  int coincidentcount=0, coincidenttotal=0, coincidentpoints=0;
  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;
  int israndom=0, istime=0;
  int isbox=0, issimplex=0, issimplex2=0, ismesh=0;
  double width=0.0, gap=0.0, radius=0.0, coincidentradius=0.0;
  double coord[MAXdim], offset, meshm=3.0, meshn=4.0, meshr=5.0;
  double *coordp, *simplexp;
  int nthroot, mult[MAXdim];
  double norm, factor, randr, rangap, tempr, 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[250], seedbuf[50];
  char *s=command, *t, *first_point=NULL;
  time_t timedata;

  *command= '\0';
  strncat(command, rbox_command, sizeof(command)-sizeof(seedbuf)-strlen(command)-1);

  while (*s && !isspace(*s))  /* skip program name */
    s++;
  while (*s) {
    while (*s && isspace(*s))
      s++;
    if (*s == '-')
      s++;
    if (!*s)
      break;
    if (isdigit(*s)) {
      numpoints= qh_strtol(s, &s);
      continue;
    }
    /* ============= read flags =============== */
    switch (*s++) {
    case 'c':
      addcube= 1;
      t= s;
      while (isspace(*t))
        t++;
      if (*t == 'G')
        cube= qh_strtod(++t, &s);
      break;
    case 'd':
      adddiamond= 1;
      t= s;
      while (isspace(*t))
        t++;
      if (*t == 'G')
        diamond= qh_strtod(++t, &s);
      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(*s)) {
        seed= qh_strtol(s, &s);
        israndom= 0;
      }else
        israndom= 1;
      break;
    case 'x':
      issimplex= 1;
      break;
    case 'y':
      issimplex2= 1;
      break;
    case 'z':
      rbox.isinteger= 1;
      break;
    case 'B':
      box= qh_strtod(s, &s);
      isbox= 1;
      break;
    case 'C':
      if (*s)
        coincidentpoints=  qh_strtol(s, &s);
      if (*s == ',') {
        ++s;
        coincidentradius=  qh_strtod(s, &s);
      }
      if (*s == ',') {
        ++s;
        coincidenttotal=  qh_strtol(s, &s);
      }
      if (*s && !isspace(*s)) {
        qh_fprintf_rbox(rbox.ferr, 7080, "rbox error: arguments for 'Cn,r,m' are not 'int', 'float', and 'int'.  Remaining string is '%s'\n", s);
        qh_errexit_rbox(qh_ERRinput);
      }
      if (coincidentpoints==0){
        qh_fprintf_rbox(rbox.ferr, 6268, "rbox error: missing arguments for 'Cn,r,m' where n is the number of coincident points, r is the radius (default 0.0), and m is the number of points\n");
        qh_errexit_rbox(qh_ERRinput);
      }
      if (coincidentpoints<0 || coincidenttotal<0 || coincidentradius<0.0){
        qh_fprintf_rbox(rbox.ferr, 6269, "rbox error: negative arguments for 'Cn,m,r' where n (%d) is the number of coincident points, m (%d) is the number of points, and r (%.2g) is the radius (default 0.0)\n", coincidentpoints, coincidenttotal, coincidentradius);
        qh_errexit_rbox(qh_ERRinput);
      }
      break;
    case 'D':
      dim= qh_strtol(s, &s);
      if (dim < 1
      || dim > MAXdim) {
        qh_fprintf_rbox(rbox.ferr, 6189, "rbox error: dimension, D%d, out of bounds (>=%d or <=0)\n", dim, MAXdim);
        qh_errexit_rbox(qh_ERRinput);
      }
      break;
    case 'G':
      if (isdigit(*s))
        gap= qh_strtod(s, &s);
      else
        gap= 0.5;
      isgap= 1;
      break;
    case 'L':
      if (isdigit(*s))
        radius= qh_strtod(s, &s);
      else
        radius= 10;
      islens= 1;
      break;
    case 'M':
      ismesh= 1;
      if (*s)
        meshn= qh_strtod(s, &s);
      if (*s == ',') {
        ++s;
        meshm= qh_strtod(s, &s);
      }else
        meshm= 0.0;
      if (*s == ',') {
        ++s;
        meshr= qh_strtod(s, &s);
      }else
        meshr= sqrt(meshn*meshn + meshm*meshm);
      if (*s && !isspace(*s)) {
        qh_fprintf_rbox(rbox.ferr, 7069, "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':
      rbox.out_offset= qh_strtod(s, &s);
      break;
    case 'P':
      if (!first_point)
        first_point= s - 1;
      addpoints++;
      while (*s && !isspace(*s))   /* read points later */
        s++;
      break;
    case 'W':
      width= qh_strtod(s, &s);
      iswidth= 1;
      break;
    case 'Z':
      if (isdigit(*s))
        radius= qh_strtod(s, &s);
      else
        radius= 1.0;
      isaxis= 1;
      break;
    default:
      qh_fprintf_rbox(rbox.ferr, 6352, "rbox error: unknown flag at '%s'.\nExecute 'rbox' without arguments for documentation.\n", s - 1);
      qh_errexit_rbox(qh_ERRinput);
    }
    if (*s && !isspace(*s)) {
      qh_fprintf_rbox(rbox.ferr, 6353, "rbox error: missing space between flags at %s.\n", s);
      qh_errexit_rbox(qh_ERRinput);
    }
  }

  /* ============= defaults, constants, and sizes =============== */
  if (rbox.isinteger && !isbox)
    box= qh_DEFAULTzbox;
  if (addcube) {
    tempr= floor(ldexp(1.0,dim)+0.5);
    cubesize= (int)tempr;
    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) {
        qh_fprintf_rbox(rbox.ferr, 6190, "rbox error: can not combine 'Ln' with 'Zn'\n");
        qh_errexit_rbox(qh_ERRinput);
    }
    if (radius <= 1.0) {
        qh_fprintf_rbox(rbox.ferr, 6191, "rbox error: lens radius %.2g should be greater than 1.0\n",
               radius);
        qh_errexit_rbox(qh_ERRinput);
    }
    lensangle= asin(1.0/radius);
    lensbase= radius * cos(lensangle);
  }

  if (!numpoints) {
    if (issimplex2)
        ; /* ok */
    else if (isregular + issimplex + islens + issphere + isaxis + isspiral + iswidth + ismesh) {
        qh_fprintf_rbox(rbox.ferr, 6192, "rbox error: missing count\n");
        qh_errexit_rbox(qh_ERRinput);
    }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)) {
    qh_fprintf_rbox(rbox.ferr, 6193, "rbox error: can only specify one of 'l', 's', 'x', 'Ln', or 'Mn,m,r' ('Ln s' is ok).\n");
    qh_errexit_rbox(qh_ERRinput);
  }
  if (coincidentpoints>0 && (numpoints == 0 || coincidenttotal > numpoints)) {
    qh_fprintf_rbox(rbox.ferr, 6270, "rbox error: 'Cn,r,m' requested n coincident points for each of m points.  Either there is no points or m (%d) is greater than the number of points (%d).\n", coincidenttotal, numpoints);
    qh_errexit_rbox(qh_ERRinput);
  }
  if (coincidentpoints > 0 && isregular) {
    qh_fprintf_rbox(rbox.ferr, 6423, "rbox error: 'Cn,r,m' is not implemented for regular points ('r')\n");
    qh_errexit_rbox(qh_ERRinput);
  }

  if (coincidenttotal == 0)
    coincidenttotal= numpoints;

  /* ============= 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;
  totpoints += coincidentpoints*coincidenttotal;

  /* ============= 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 if (israndom) {
    seed= (int)time(&timedata);
    sprintf(seedbuf, " t%d", seed);  /* appends an extra t, not worth removing */
    strncat(command, seedbuf, sizeof(command) - strlen(command) - 1);
    t= strstr(command, " t ");
    if (t)
      strcpy(t+1, t+3); /* remove " t " */
  } /* else, seed explicitly set to n */
  qh_RANDOMseed_(seed);

  /* ============= print header =============== */

  if (iscdd)
      qh_fprintf_rbox(rbox.fout, 9391, "%s\nbegin\n        %d %d %s\n",
      NOcommand ? "" : command,
      totpoints, dim+1,
      rbox.isinteger ? "integer" : "real");
  else if (NOcommand)
      qh_fprintf_rbox(rbox.fout, 9392, "%d\n%d\n", dim, totpoints);
  else
      /* qh_fprintf_rbox special cases 9393 to append 'command' to the RboxPoints.comment() */
      qh_fprintf_rbox(rbox.fout, 9393, "%d %s\n%d\n", dim, command, totpoints);

  /* ============= explicit points =============== */
  if ((s= first_point)) {
    while (s && *s) { /* 'P' */
      count= 0;
      if (iscdd)
        qh_out1(1.0);
      while (*++s) {
        qh_out1(qh_strtod(s, &s));
        count++;
        if (isspace(*s) || !*s)
          break;
        if (*s != ',') {
          qh_fprintf_rbox(rbox.ferr, 6194, "rbox error: missing comma after coordinate in %s\n\n", s);
          qh_errexit_rbox(qh_ERRinput);
        }
      }
      if (count < dim) {
        for (k=dim-count; k--; )
          qh_out1(0.0);
      }else if (count > dim) {
        qh_fprintf_rbox(rbox.ferr, 6195, "rbox error: %d coordinates instead of %d coordinates in %s\n\n",
                  count, dim, s);
        qh_errexit_rbox(qh_ERRinput);
      }
      qh_fprintf_rbox(rbox.fout, 9394, "\n");
      while ((s= strchr(s, 'P'))) {
        if (isspace(s[-1]))
          break;
      }
    }
  }

  /* ============= simplex distribution =============== */
  if (issimplex+issimplex2) {
    if (!(*simplex= (double *)qh_malloc( (size_t)(dim * (dim+1)) * sizeof(double)))) {
      qh_fprintf_rbox(rbox.ferr, 6196, "rbox error: insufficient memory for simplex\n");
      qh_errexit_rbox(qh_ERRmem); /* qh_ERRmem */
    }
    simplexp= *simplex;
    if (isregular) {
      for (i=0; i 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;
      }
      /* ============= scale point to box =============== */
      for (k=0; k=0; k--) {
        if (j & ( 1 << k))
          qh_out1(cube);
        else
          qh_out1(-cube);
      }
      qh_fprintf_rbox(rbox.fout, 9400, "\n");
    }
  }

  /* ============= write diamond vertices =============== */
  if (adddiamond) {
    for (j=0; j=0; k--) {
        if (j/2 != k)
          qh_out1(0.0);
        else if (j & 0x1)
          qh_out1(diamond);
        else
          qh_out1(-diamond);
      }
      qh_fprintf_rbox(rbox.fout, 9401, "\n");
    }
  }

  if (iscdd)
    qh_fprintf_rbox(rbox.fout, 9402, "end\nhull\n");
} /* rboxpoints2 */

/*------------------------------------------------
outxxx - output functions for qh_rboxpoints
*/
int qh_roundi(double a) {
  if (a < 0.0) {
    if (a - 0.5 < INT_MIN) {
      qh_fprintf_rbox(rbox.ferr, 6200, "rbox input error: negative coordinate %2.2g is too large.  Reduce 'Bn'\n", a);
      qh_errexit_rbox(qh_ERRinput);
    }
    return (int)(a - 0.5);
  }else {
    if (a + 0.5 > INT_MAX) {
      qh_fprintf_rbox(rbox.ferr, 6201, "rbox input error: coordinate %2.2g is too large.  Reduce 'Bn'\n", a);
      qh_errexit_rbox(qh_ERRinput);
    }
    return (int)(a + 0.5);
  }
} /* qh_roundi */

void qh_out1(double a) {

  if (rbox.isinteger)
    qh_fprintf_rbox(rbox.fout, 9403, "%d ", qh_roundi(a+rbox.out_offset));
  else
    qh_fprintf_rbox(rbox.fout, 9404, qh_REAL_1, a+rbox.out_offset);
} /* qh_out1 */

void qh_out2n(double a, double b) {

  if (rbox.isinteger)
    qh_fprintf_rbox(rbox.fout, 9405, "%d %d\n", qh_roundi(a+rbox.out_offset), qh_roundi(b+rbox.out_offset));
  else
    qh_fprintf_rbox(rbox.fout, 9406, qh_REAL_2n, a+rbox.out_offset, b+rbox.out_offset);
} /* qh_out2n */

void qh_out3n(double a, double b, double c) {

  if (rbox.isinteger)
    qh_fprintf_rbox(rbox.fout, 9407, "%d %d %d\n", qh_roundi(a+rbox.out_offset), qh_roundi(b+rbox.out_offset), qh_roundi(c+rbox.out_offset));
  else
    qh_fprintf_rbox(rbox.fout, 9408, qh_REAL_3n, a+rbox.out_offset, b+rbox.out_offset, c+rbox.out_offset);
} /* qh_out3n */

void qh_outcoord(int iscdd, double *coord, int dim) {
    double *p= coord;
    int k;

    if (iscdd)
      qh_out1(1.0);
    for (k=0; k < dim; k++)
      qh_out1(*(p++));
    qh_fprintf_rbox(rbox.fout, 9396, "\n");
} /* qh_outcoord */

void qh_outcoincident(int coincidentpoints, double radius, int iscdd, double *coord, int dim) {
  double *p;
  double randr, delta;
  int i,k;
  double randmax= qh_RANDOMmax;

  for (i=0; i
  ---------------------------------

   stat.c
   contains all statistics that are collected for qhull

   see qh-stat.htm and stat.h

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull/stat.c#9 $$Change: 2953 $
   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
*/

#include "qhull_a.h"

/*============ global data structure ==========*/

#if qh_QHpointer
qhstatT *qh_qhstat=NULL;  /* global data structure */
#else
qhstatT qh_qhstat;   /* add "={0}" if this causes a compiler error */
#endif

/*========== functions in alphabetic order ================*/

/*---------------------------------

  qh_allstatA()
    define statistics in groups of 20

  notes:
    (otherwise, 'gcc -O2' uses too much memory)
    uses qhstat.next
*/
void qh_allstatA(void) {

   /* zdef_(type,name,doc,average) */
  zzdef_(zdoc, Zdoc2, "precision statistics", -1);
  zdef_(zinc, Znewvertex, NULL, -1);
  zdef_(wadd, Wnewvertex, "ave. distance of a new vertex to a facet", 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;  /* usually call qh_joggle_restart, printed if Q0 or QJn */
  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, "dupridges with multiple neighbors", -1);
  zzdef_(zinc, Zflipridge, "dupridges with flip facet into good neighbor", -1);
  zzdef_(zinc, Zflipridge2, "dupridges with flip facet into good flip neighbor", -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, "simplicial facets that were non-simplicial", -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 cosine (angle) of facet normals for all ridges", Zangle);
  zdef_(wmax, Wanglemax, "  maximum cosine of facet normals (flatest) across a ridge", -1);
  zdef_(wmin, Wanglemin, "  minimum cosine of facet normals (sharpest) 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,  "  count", -1);
  zdef_(zinc, Zsearchpoints, "searches of all points for initial simplex", -1);
  zdef_(zinc, Zdetfacetarea, "determinants for facet area", -1);
  zdef_(zinc, Znoarea, "  determinants not computed because vertex too low", -1);
  zdef_(zinc, Zdetsimplex, "determinants for initial hull or voronoi vertices", -1);
  zdef_(zinc, Znotmax, "points ignored (!above max_outside)", -1);
  zdef_(zinc, Zpinchedapex, "points ignored (pinched apex)", -1);
  zdef_(zinc, Znotgood, "points ignored (!above a good facet)", -1);
  zdef_(zinc, Znotgoodnew, "points ignored (didn't create a good new facet)", -1);
  zdef_(zinc, Zgoodfacet, "good facets found", -1);
  zzdef_(zinc, Znumvisibility, "distance tests for facet visibility", -1);
  zdef_(zinc, Zdistvertex, "distance tests to report minimum vertex", -1);
  zzdef_(zinc, Ztotcheck, "points checked for facets' outer planes", -1);
  zzdef_(zinc, Zcheckpart, "  ave. distance tests per check", Ztotcheck);
}
void qh_allstatD(void) {
  zdef_(zinc, Zvisit, "resets of visit_id", -1);
  zdef_(zinc, Zvvisit, "  resets of vertex_visit", -1);
  zdef_(zmax, Zvisit2max, "  max visit_id/2", -1);
  zdef_(zmax, Zvvisit2max, "  max vertex_visit/2", -1);

  zdef_(zdoc, Zdoc4, "partitioning statistics (see previous for outer planes)", -1);
  zzdef_(zadd, Zdelvertextot, "total vertices deleted", -1);
  zdef_(zmax, Zdelvertexmax, "    maximum vertices deleted per iteration", -1);
  zdef_(zinc, Zfindbest, "calls to findbest", -1);
  zdef_(zadd, Zfindbesttot, " ave. facets tested", Zfindbest);
  zdef_(zmax, Zfindbestmax, " max. facets tested", -1);
  zdef_(zadd, Zfindcoplanar, " ave. coplanar search", Zfindbest);
  zdef_(zinc, Zfindnew, "calls to findbestnew", -1);
  zdef_(zadd, Zfindnewtot, " ave. facets tested", Zfindnew);
  zdef_(zmax, Zfindnewmax, " max. facets tested", -1);
  zdef_(zinc, Zfindnewjump, " ave. clearly better", Zfindnew);
  zdef_(zinc, Zfindnewsharp, " calls due to qh_sharpnewfacets", -1);
  zdef_(zinc, Zfindhorizon, "calls to findhorizon", -1);
  zdef_(zadd, Zfindhorizontot, " ave. facets tested", Zfindhorizon);
  zdef_(zmax, Zfindhorizonmax, " max. facets tested", -1);
  zdef_(zinc, Zfindjump,       " ave. clearly better", Zfindhorizon);
  zdef_(zinc, Znewbesthorizon, " new bestfacets during qh_findbesthorizon", -1);
  zdef_(zinc, Zpartangle, "angle tests for repartitioned coplanar points", -1);
  zdef_(zinc, Zpartcorner, "  repartitioned coplanar points above a corner facet", -1);
  zdef_(zinc, Zparthidden, "  repartitioned coplanar points above a hidden facet", -1);
  zdef_(zinc, Zparttwisted, "  repartitioned coplanar points above a twisted facet", -1);
}
void qh_allstatE(void) {
  zdef_(zinc, Zpartinside, "inside points", -1);
  zdef_(zinc, Zpartnear, "  near inside points kept with a facet", -1);
  zdef_(zinc, Zcoplanarinside, "  inside points that were coplanar with a facet", -1);
  zdef_(zinc, Zbestlower, "calls to findbestlower", -1);
  zdef_(zinc, Zbestlowerv, "  with search of vertex neighbors", -1);
  zdef_(zinc, Zbestlowerall, "  with rare search of all facets", -1);
  zdef_(zmax, Zbestloweralln, "  facets per search of all facets", -1);
  zdef_(wadd, Wmaxout, "difference in max_outside at final check", -1);
  zzdef_(zinc, Zpartitionall, "distance tests for initial partition", -1);
  zdef_(zinc, Ztotpartition, "partitions of a point", -1);
  zzdef_(zinc, Zpartition, "distance tests for partitioning", -1);
  zzdef_(zinc, Zdistcheck, "distance tests for checking flipped facets", -1);
  zzdef_(zinc, Zdistconvex, "distance tests for checking convexity", -1);
  zdef_(zinc, Zdistgood, "distance tests for checking good point", -1);
  zdef_(zinc, Zdistio, "distance tests for output", -1);
  zdef_(zinc, Zdiststat, "distance tests for statistics", -1);
  zzdef_(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, Zvertextests, "distance tests for vertex 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 or vertices in getmergeset", -1);
  zdef_(zinc, Zconcaveridge, "concave ridges in getmergeset", -1);
  zdef_(zinc, Zconcavecoplanarridge, "concave-coplanar ridges in getmergeset", -1);
  zdef_(zinc, Ztwistedridge, "twisted 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 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, Zmergeintocoplanar, "new facets merged into coplanar horizon", -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, Zredundant, "merges due to redundant neighbors", -1);
  zdef_(zinc, Zredundantmerge, "  detected by qh_test_nonsimplicial_merge instead of qh_test_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, Zconcavecoplanar, "merges due to concave-coplanar facets", -1);
  zdef_(wadd, Wconcavecoplanartot, "  average merge distance", Zconcavecoplanar);
  zdef_(wmax, Wconcavecoplanarmax, "  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 dupridges", -1);
  zdef_(wadd, Wduplicatetot, "  average merge distance", Zduplicate);
  zdef_(wmax, Wduplicatemax, "  maximum merge distance", -1);
  zdef_(zinc, Ztwisted, "merges due to twisted facets", -1);
  zdef_(wadd, Wtwistedtot, "  average merge distance", Ztwisted);
  zdef_(wmax, Wtwistedmax, "  maximum merge distance", -1);
}
void qh_allstatH(void) {
  zdef_(zdoc, Zdoc8, "statistics for vertex merges", -1);
  zzdef_(zinc, Zpinchduplicate, "merge pinched vertices for a duplicate ridge", -1);
  zzdef_(zinc, Zpinchedvertex, "merge pinched vertices for a dupridge", -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, Znewvertexridge, "  found new vertex in ridge", -1);
  zdef_(zinc, Zdelridge, "deleted ridges due to renamed vertices", -1);
  zdef_(zinc, Zdropneighbor, "dropped neighbors due to renamed vertices", -1);
  zdef_(zinc, Zdropdegen, "merge 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, Zretryadd, "retry qh_addpoint after merge pinched vertex", -1);
  zdef_(zadd, Zretryaddtot, "  tot. merge pinched vertex due to dupridge", -1);
  zdef_(zmax, Zretryaddmax, "  max. merge pinched vertex for a qh_addpoint", -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, outside and coplanar sets, and qhT",-1);
  zdef_(zadd, Zmemridges, "for ridges and their vertex sets", -1);
} /* allstat */

void qh_allstatI(void) {
  qhstat vridges= qhstat next; /* printed in qh_produce_output2 if non-zero Zridge or Zridgemid */
  zzdef_(zdoc, Zdoc11, "Voronoi ridge statistics", -1);
  zzdef_(zinc, Zridge, "non-simplicial Voronoi vertices for all ridges", -1);
  zzdef_(wadd, Wridge, "  ave. distance to ridge", Zridge);
  zzdef_(wmax, Wridgemax, "  max. distance to ridge", -1);
  zzdef_(zinc, Zridgemid, "bounded ridges", -1);
  zzdef_(wadd, Wridgemid, "  ave. distance of midpoint to ridge", Zridgemid);
  zzdef_(wmax, Wridgemidmax, "  max. distance of midpoint to ridge", -1);
  zzdef_(zinc, Zridgeok, "bounded ridges with ok normal", -1);
  zzdef_(wadd, Wridgeok, "  ave. angle to ridge", Zridgeok);
  zzdef_(wmax, Wridgeokmax, "  max. angle to ridge", -1);
  zzdef_(zinc, Zridge0, "bounded ridges with near-zero normal", -1);
  zzdef_(wadd, Wridge0, "  ave. angle to ridge", Zridge0);
  zzdef_(wmax, Wridge0max, "  max. angle to ridge", -1);

  zdef_(zdoc, Zdoc12, "Triangulation statistics ('Qt')", -1);
  zdef_(zinc, Ztricoplanar, "non-simplicial facets triangulated", -1);
  zdef_(zadd, Ztricoplanartot, "  ave. new facets created (may be deleted)", Ztricoplanar);
  zdef_(zmax, Ztricoplanarmax, "  max. new facets created", -1);
  zdef_(zinc, Ztrinull, "null new facets deleted (duplicated vertex)", -1);
  zdef_(zinc, Ztrimirror, "mirrored pairs of new facets deleted (same vertices)", -1);
  zdef_(zinc, Ztridegen, "degenerate new facets in output (same ridge)", -1);
} /* allstat */

/*---------------------------------

  qh_allstatistics()
    reset printed flag for all statistics
*/
void qh_allstatistics(void) {
  int i;

  for(i=ZEND; i--; )
    qhstat printed[i]= False;
} /* allstatistics */

#if qh_KEEPstatistics
/*---------------------------------

  qh_collectstatistics()
    collect statistics for qh.facet_list

*/
void qh_collectstatistics(void) {
  facetT *facet, *neighbor, **neighborp;
  vertexT *vertex, **vertexp;
  realT dotproduct, dist;
  int sizneighbors, sizridges, sizvertices, i;

  qh old_randomdist= qh RANDOMdist;
  qh RANDOMdist= False;
  zval_(Zmempoints)= qh num_points * qh normal_size + (int)sizeof(qhT) + (int)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);
  if (!qh_checklists(qh facet_list)) {
    qh_fprintf(qh ferr, 6373, "qhull internal error: qh_checklists failed on qh_collectstatistics\n");
    if (!qh ERREXITcalled)
      qh_errexit(qh_ERRqhull, NULL, NULL);
  }
  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, (int)sizeof(facetT) + qh normal_size + 2*(int)sizeof(setT)
       + SETelemsize * (sizneighbors + sizvertices));
    if (facet->ridges) {
      zadd_(Zmemridges,
        (int)sizeof(setT) + SETelemsize * sizridges + sizridges *
         ((int)sizeof(ridgeT) + (int)sizeof(setT) + SETelemsize * (qh hull_dim-1))/2);
    }
    if (facet->outsideset)
      zadd_(Zmempoints, (int)sizeof(setT) + SETelemsize * qh_setsize(facet->outsideset));
    if (facet->coplanarset)
      zadd_(Zmempoints, (int)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, (int)sizeof(vertexT));
    if (vertex->neighbors) {
      sizneighbors= qh_setsize(vertex->neighbors);
      zadd_(Znumvneighbors, sizneighbors);
      zmax_(Zmaxvneighbors, sizneighbors);
      zadd_(Zmemvertices, (int)sizeof(vertexT) + SETelemsize * sizneighbors);
    }
  }
  qh RANDOMdist= qh old_randomdist;
} /* collectstatistics */
#endif /* qh_KEEPstatistics */

/*---------------------------------

  qh_freestatistics(  )
    free memory used for statistics
*/
void qh_freestatistics(void) {

#if qh_QHpointer
  qh_free(qh_qhstat);
  qh_qhstat= NULL;
#endif
} /* freestatistics */

/*---------------------------------

  qh_initstatistics( )
    allocate and initialize statistics

  notes:
    uses qh_malloc() instead of qh_memalloc() since mem.c not set up yet
    NOerrors -- qh_initstatistics can not use qh_errexit(), qh_fprintf, or qh.ferr
    On first call, only qhmem.ferr is defined.  qh_memalloc is not setup.
    Also invoked by QhullQh().
*/
void qh_initstatistics(void) {
  int i;
  realT realx;
  int intx;
  
#if qh_QHpointer
  if(qh_qhstat){  /* qh_initstatistics may be called from Qhull::resetStatistics() */
    qh_free(qh_qhstat);
    qh_qhstat= 0;
  }
  if (!(qh_qhstat= (qhstatT *)qh_malloc(sizeof(qhstatT)))) {
    qh_fprintf_stderr(6183, "qhull error (qh_initstatistics): insufficient memory\n");
    qh_exit(qh_ERRmem);  /* can not use qh_errexit() */
  }
#endif

  qh_allstatistics();
  qhstat next= 0;
  qh_allstatA();
  qh_allstatB();
  qh_allstatC();
  qh_allstatD();
  qh_allstatE();
  qh_allstatE2();
  qh_allstatF();
  qh_allstatG();
  qh_allstatH();
  qh_allstatI();
  if (qhstat next > (int)sizeof(qhstat id)) {
    qh_fprintf_stderr(6184, "qhull internal error (qh_initstatistics): increase size of qhstat.id[].  qhstat.next %d should be <= sizeof(qhstat id) %d\n", 
          qhstat next, (int)sizeof(qhstat id));
#if 0 /* for locating error, Znumridges should be duplicated */
    for(i=0; i < ZEND; i++) {
      int j;
      for(j=i+1; j < ZEND; j++) {
        if (qhstat id[i] == qhstat id[j]) {
          qh_fprintf_stderr(6185, "qhull error (qh_initstatistics): duplicated statistic %d at indices %d and %d\n",
              qhstat id[i], i, j);
        }
      }
    }
#endif
    qh_exit(qh_ERRqhull);  /* can not use qh_errexit() */
  }
  qhstat init[zinc].i= 0;
  qhstat init[zadd].i= 0;
  qhstat init[zmin].i= INT_MAX;
  qhstat init[zmax].i= INT_MIN;
  qhstat init[wadd].r= 0;
  qhstat init[wmin].r= REALmax;
  qhstat init[wmax].r= -REALmax;
  for(i=0; i < ZEND; i++) {
    if (qhstat type[i] > ZTYPEreal) {
      realx= qhstat init[(unsigned char)(qhstat type[i])].r;
      qhstat stats[i].r= realx;
    }else if (qhstat type[i] != zdoc) {
      intx= qhstat init[(unsigned char)(qhstat type[i])].i;
      qhstat stats[i].i= intx;
    }
  }
} /* initstatistics */

/*---------------------------------

  qh_newstats( )
    returns True if statistics for zdoc

  returns:
    next zdoc
*/
boolT qh_newstats(int idx, int *nextindex) {
  boolT isnew= False;
  int start, i;

  if (qhstat type[qhstat id[idx]] == zdoc)
    start= idx+1;
  else
    start= idx;
  for(i= start; i < qhstat next && qhstat type[qhstat id[i]] != zdoc; i++) {
    if (!qh_nostatistic(qhstat id[i]) && !qhstat printed[qhstat id[i]])
        isnew= True;
  }
  *nextindex= i;
  return isnew;
} /* newstats */

/*---------------------------------

  qh_nostatistic( index )
    true if no statistic to print
*/
boolT qh_nostatistic(int i) {

  if ((qhstat type[i] > ZTYPEreal
       &&qhstat stats[i].r == qhstat init[(unsigned char)(qhstat type[i])].r)
      || (qhstat type[i] < ZTYPEreal
          &&qhstat stats[i].i == qhstat init[(unsigned char)(qhstat type[i])].i))
    return True;
  return False;
} /* nostatistic */

#if qh_KEEPstatistics
/*---------------------------------

  qh_printallstatistics( fp, string )
    print all statistics with header 'string'
*/
void qh_printallstatistics(FILE *fp, const char *string) {

  qh_allstatistics();
  qh_collectstatistics();
  qh_printstatistics(fp, string);
  qh_memstatistics(fp);
}


/*---------------------------------

  qh_printstatistics( fp, string )
    print statistics to a file with header 'string'
    skips statistics with qhstat.printed[] (reset with qh_allstatistics)

  see:
    qh_printallstatistics()
*/
void qh_printstatistics(FILE *fp, const char *string) {
  int i, k;
  realT ave; /* ignored */

  if (qh num_points != qh num_vertices || zval_(Zpbalance) == 0) {
    wval_(Wpbalance)= 0.0;
    wval_(Wpbalance2)= 0.0;
  }else
    wval_(Wpbalance2)= qh_stddev(zval_(Zpbalance), wval_(Wpbalance),
                                 wval_(Wpbalance2), &ave);
  if (zval_(Zprocessed) == 0)
    wval_(Wnewbalance2)= 0.0;
  else
    wval_(Wnewbalance2)= qh_stddev(zval_(Zprocessed), wval_(Wnewbalance),
                                 wval_(Wnewbalance2), &ave);
  qh_fprintf(fp, 9350, "\n\
%s\n\
qhull invoked by: %s | %s\n  %s with options:\n%s\n", 
    string, qh rbox_command, qh qhull_command, qh_version, qh qhull_options);

  qh_fprintf(fp, 9351, "\nprecision constants:\n\
 %6.2g max. abs. coordinate in the (transformed) input ('Qbd:n')\n\
 %6.2g max. roundoff error for distance computation ('En')\n\
 %6.2g max. roundoff error for angle computations\n\
 %6.2g min. distance for outside points ('Wn')\n\
 %6.2g min. distance for visible facets ('Vn')\n\
 %6.2g max. distance for coplanar facets ('Un')\n\
 %6.2g max. facet width for recomputing centrum and area\n\
",
  qh MAXabs_coord, qh DISTround, qh ANGLEround, qh MINoutside,
        qh MINvisible, qh MAXcoplanar, qh WIDEfacet);
  if (qh KEEPnearinside)
    qh_fprintf(fp, 9352, "\
 %6.2g max. distance for near-inside points\n", qh NEARinside);
  if (qh premerge_cos < REALmax/2) qh_fprintf(fp, 9353, "\
 %6.2g max. cosine for pre-merge angle\n", qh premerge_cos);
  if (qh PREmerge) qh_fprintf(fp, 9354, "\
 %6.2g radius of pre-merge centrum\n", qh premerge_centrum);
  if (qh postmerge_cos < REALmax/2) qh_fprintf(fp, 9355, "\
 %6.2g max. cosine for post-merge angle\n", qh postmerge_cos);
  if (qh POSTmerge) qh_fprintf(fp, 9356, "\
 %6.2g radius of post-merge centrum\n", qh postmerge_centrum);
  qh_fprintf(fp, 9357, "\
 %6.2g max. distance for merging two simplicial facets\n\
 %6.2g max. roundoff error for arithmetic operations\n\
 %6.2g min. denominator for division\n\
  zero diagonal for Gauss: ", qh ONEmerge, REALepsilon, qh MINdenom);
  for(k=0; k < qh hull_dim; k++)
    qh_fprintf(fp, 9358, "%6.2e ", qh NEARzero[k]);
  qh_fprintf(fp, 9359, "\n\n");
  for(i=0 ; i < qhstat next; )
    qh_printstats(fp, i, &i);
} /* printstatistics */
#endif /* qh_KEEPstatistics */

/*---------------------------------

  qh_printstatlevel( fp, id )
    print level information for a statistic

  notes:
    nop if id >= ZEND, printed, or same as initial value
*/
void qh_printstatlevel(FILE *fp, int id) {

  if (id >= ZEND || qhstat printed[id])
    return;
  if (qhstat type[id] == zdoc) {
    qh_fprintf(fp, 9360, "%s\n", qhstat doc[id]);
    return;
  }
  if (qh_nostatistic(id) || !qhstat doc[id])
    return;
  qhstat printed[id]= True;
  if (qhstat count[id] != -1
      && qhstat stats[(unsigned char)(qhstat count[id])].i == 0)
    qh_fprintf(fp, 9361, " *0 cnt*");
  else if (qhstat type[id] >= ZTYPEreal && qhstat count[id] == -1)
    qh_fprintf(fp, 9362, "%7.2g", qhstat stats[id].r);
  else if (qhstat type[id] >= ZTYPEreal && qhstat count[id] != -1)
    qh_fprintf(fp, 9363, "%7.2g", qhstat stats[id].r/ qhstat stats[(unsigned char)(qhstat count[id])].i);
  else if (qhstat type[id] < ZTYPEreal && qhstat count[id] == -1)
    qh_fprintf(fp, 9364, "%7d", qhstat stats[id].i);
  else if (qhstat type[id] < ZTYPEreal && qhstat count[id] != -1)
    qh_fprintf(fp, 9365, "%7.3g", (realT) qhstat stats[id].i / qhstat stats[(unsigned char)(qhstat count[id])].i);
  qh_fprintf(fp, 9366, " %s\n", qhstat doc[id]);
} /* printstatlevel */


/*---------------------------------

  qh_printstats( fp, index, nextindex )
    print statistics for a zdoc group

  returns:
    next zdoc if non-null
*/
void qh_printstats(FILE *fp, int idx, int *nextindex) {
  int j, nexti;

  if (qh_newstats(idx, &nexti)) {
    qh_fprintf(fp, 9367, "\n");
    for (j=idx; j--------------------------------

  qh_stddev( num, tot, tot2, ave )
    compute the standard deviation and average from statistics

    tot2 is the sum of the squares
  notes:
    computes r.m.s.:
      (x-ave)^2
      == x^2 - 2x tot/num +   (tot/num)^2
      == tot2 - 2 tot tot/num + tot tot/num
      == tot2 - tot ave
*/
realT qh_stddev(int num, realT tot, realT tot2, realT *ave) {
  realT stddev;

  if (num <= 0) {
    qh_fprintf(qh ferr, 7101, "qhull warning (qh_stddev): expecting num > 0.  Got num %d, tot %4.4g, tot2 %4.4g.  Returning 0.0\n",
      num, tot, tot2);
    return 0.0;
  }
  *ave= tot/num;
  stddev= sqrt(fabs(tot2/num - *ave * *ave));
  return stddev;
} /* stddev */
#else
realT qh_stddev(int num, realT tot, realT tot2, realT *ave) { /* for qhull-exports.def */
  QHULL_UNUSED(num)
  QHULL_UNUSED(tot)
  QHULL_UNUSED(tot2)
  QHULL_UNUSED(ave)

  return 0.0;
}
#endif /* qh_KEEPstatistics */

#if !qh_KEEPstatistics
void    qh_collectstatistics(void) {}
void    qh_printallstatistics(FILE *fp, const char *string) {}
void    qh_printstatistics(FILE *fp, const char *string) {}
#endif

qhull-2020.2/src/libqhull/stat.h0000644060175106010010000003256313661631132014730 0ustar  bbarber/*
  ---------------------------------

   stat.h
     contains all statistics that are collected for qhull

   see qh-stat.htm and stat.c

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull/stat.h#4 $$Change: 2953 $
   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $

   recompile qhull if you change this file

   Integer statistics are Z* while real statistics are W*.

   define MAYdebugx to call a routine at every statistic event

*/

#ifndef qhDEFstat
#define qhDEFstat 1

/* Depends on realT.  Do not include "libqhull_r" to avoid circular dependency */

/*---------------------------------

  qh_KEEPstatistics
    0 turns off statistic reporting and gathering (except zzdef/zzinc/zzadd/zzval/wwval)

  set qh_KEEPstatistics in user.h to 0 to turn off statistics
*/
#ifndef qh_KEEPstatistics
#define qh_KEEPstatistics 1
#endif

/*---------------------------------

  Zxxx for integers, Wxxx for reals

  notes:
    be sure that all statistics are defined in stat.c
      otherwise initialization may core dump
    can pick up all statistics by:
      grep '[zw].*_[(][ZW]' *.c >z.x
    remove trailers with query">-
    remove leaders with  query-replace-regexp [ ^I]+  (
*/
#if qh_KEEPstatistics
enum qh_statistics {     /* alphabetical after Z/W */
    Zacoplanar,
    Wacoplanarmax,
    Wacoplanartot,
    Zangle,
    Wangle,
    Wanglemax,
    Wanglemin,
    Zangletests,
    Wareatot,
    Wareamax,
    Wareamin,
    Zavoidold,
    Wavoidoldmax,
    Wavoidoldtot,
    Zback0,
    Zbestcentrum,
    Zbestdist,
    Zbestlower,
    Zbestlowerall,
    Zbestloweralln,
    Zbestlowerv,
    Zcentrumtests,
    Zcheckpart,
    Zcomputefurthest,
    Zconcave,
    Wconcavemax,
    Wconcavetot,
    Zconcavecoplanar,
    Wconcavecoplanarmax,
    Wconcavecoplanartot,
    Zconcavecoplanarridge,
    Zconcaveridge,
    Zconcaveridges,
    Zcoplanar,
    Wcoplanarmax,
    Wcoplanartot,
    Zcoplanarangle,
    Zcoplanarcentrum,
    Zcoplanarhorizon,
    Zcoplanarinside,
    Zcoplanarpart,
    Zcoplanarridges,
    Wcpu,
    Zcyclefacetmax,
    Zcyclefacettot,
    Zcyclehorizon,
    Zcyclevertex,
    Zdegen,
    Wdegenmax,
    Wdegentot,
    Zdegenvertex,
    Zdelfacetdup,
    Zdelridge,
    Zdelvertextot,
    Zdelvertexmax,
    Zdetfacetarea,
    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,
    Zdupsame,
    Zflipped,
    Wflippedmax,
    Wflippedtot,
    Zflippedfacets,
    Zflipridge,
    Zflipridge2,
    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,
    Zmergeintocoplanar,
    Zmergeintohorizon,
    Zmergenew,
    Zmergesettot,
    Zmergesetmax,
    Zmergesettot2,
    Zmergesimplex,
    Zmergevertex,
    Wmindenom,
    Wminvertex,
    Zminnorm,
    Zmultiridge,
    Znearlysingular,
    Zredundant,
    Wnewbalance,
    Wnewbalance2,
    Znewbesthorizon,
    Znewfacettot,
    Znewfacetmax,
    Znewvertex,
    Wnewvertex,
    Wnewvertexmax,
    Znewvertexridge,
    Znoarea,
    Znonsimplicial,
    Znowsimplicial,
    Znotgood,
    Znotgoodnew,
    Znotmax,
    Znumfacets,
    Znummergemax,
    Znummergetot,
    Znumneighbors,
    Znumridges,
    Znumvertices,
    Znumvisibility,
    Znumvneighbors,
    Zonehorizon,
    Zpartangle,
    Zpartcoplanar,
    Zpartcorner,
    Zparthidden,
    Zpartinside,
    Zpartition,
    Zpartitionall,
    Zpartnear,
    Zparttwisted,
    Zpbalance,
    Wpbalance,
    Wpbalance2,
    Zpinchduplicate,
    Zpinchedapex,
    Zpinchedvertex,
    Zpostfacets,
    Zpremergetot,
    Zprocessed,
    Zremvertex,
    Zremvertexdel,
    Zredundantmerge,
    Zrenameall,
    Zrenamepinch,
    Zrenameshare,
    Zretry,
    Wretrymax,
    Zretryadd,
    Zretryaddmax,
    Zretryaddtot,
    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,
    Ztwisted,
    Wtwistedtot,
    Wtwistedmax,
    Ztwistedridge,
    Zvertextests,
    Wvertexmax,
    Wvertexmin,
    Zvertexridge,
    Zvertexridgetot,
    Zvertexridgemax,
    Zvertices,
    Zvisfacettot,
    Zvisfacetmax,
    Zvisit,
    Zvisit2max,
    Zvisvertextot,
    Zvisvertexmax,
    Zvvisit,
    Zvvisit2max,
    Zwidefacet,
    Zwidevertices,
    ZEND};

/*---------------------------------

  Zxxx/Wxxx statistics that remain defined if qh_KEEPstatistics=0

  notes:
    be sure to use zzdef, zzinc, etc. with these statistics (no double checking!)
*/
#else
enum qh_statistics {     /* for zzdef etc. macros */
  Zback0,
  Zbestdist,
  Zcentrumtests,
  Zcheckpart,
  Zconcaveridges,
  Zcoplanarhorizon,
  Zcoplanarpart,
  Zcoplanarridges,
  Zcyclefacettot,
  Zcyclehorizon,
  Zdelvertextot,
  Zdistcheck,
  Zdistconvex,
  Zdistplane,
  Zdistzero,
  Zdoc1,
  Zdoc2,
  Zdoc3,
  Zdoc11,
  Zflippedfacets,
  Zflipridge,
  Zflipridge2,
  Zgauss0,
  Zminnorm,
  Zmultiridge,
  Znearlysingular,
  Wnewvertexmax,
  Znumvisibility,
  Zpartcoplanar,
  Zpartition,
  Zpartitionall,
  Zpinchduplicate,
  Zpinchedvertex,
  Zprocessed,
  Zretry,
  Zridge,
  Wridge,
  Wridgemax,
  Zridge0,
  Wridge0,
  Wridge0max,
  Zridgemid,
  Wridgemid,
  Wridgemidmax,
  Zridgeok,
  Wridgeok,
  Wridgeokmax,
  Zsetplane,
  Ztotcheck,
  Ztotmerge,
  Zvertextests,
  ZEND};
#endif

/*---------------------------------

  ztype
    the type of a statistic sets its initial value.

  notes:
    The type should be the same as the macro for collecting the statistic
*/
enum ztypes {zdoc,zinc,zadd,zmax,zmin,ZTYPEreal,wadd,wmax,wmin,ZTYPEend};

/*========== macros and constants =============*/

/*----------------------------------

  MAYdebugx
    define as maydebug() to be called frequently for error trapping
*/
#define MAYdebugx

/*----------------------------------

  zzdef_, zdef_( type, name, doc, -1)
    define a statistic (assumes 'qhstat.next= 0;')

  zdef_( type, name, doc, count)
    define an averaged statistic
    printed as name/count
*/
#define zzdef_(stype,name,string,cnt) qhstat id[qhstat next++]=name; \
   qhstat doc[name]= string; qhstat count[name]= cnt; qhstat type[name]= stype
#if qh_KEEPstatistics
#define zdef_(stype,name,string,cnt) qhstat id[qhstat next++]=name; \
   qhstat doc[name]= string; qhstat count[name]= cnt; qhstat type[name]= stype
#else
#define zdef_(type,name,doc,count)
#endif

/*----------------------------------

  zzinc_( name ), zinc_( name)
    increment an integer statistic
*/
#define zzinc_(id) {MAYdebugx; qhstat stats[id].i++;}
#if qh_KEEPstatistics
#define zinc_(id) {MAYdebugx; qhstat stats[id].i++;}
#else
#define zinc_(id) {}
#endif

/*----------------------------------

  zzadd_( name, value ), zadd_( name, value ), wadd_( name, value )
    add value to an integer or real statistic
*/
#define zzadd_(id, val) {MAYdebugx; qhstat stats[id].i += (val);}
#define wwadd_(id, val) {MAYdebugx; qhstat stats[id].r += (val);}
#if qh_KEEPstatistics
#define zadd_(id, val) {MAYdebugx; qhstat stats[id].i += (val);}
#define wadd_(id, val) {MAYdebugx; qhstat stats[id].r += (val);}
#else
#define zadd_(id, val) {}
#define wadd_(id, val) {}
#endif

/*----------------------------------

  zzval_( name ), zval_( name ), wwval_( name )
    set or return value of a statistic
*/
#define zzval_(id) ((qhstat stats[id]).i)
#define wwval_(id) ((qhstat stats[id]).r)
#if qh_KEEPstatistics
#define zval_(id) ((qhstat stats[id]).i)
#define wval_(id) ((qhstat stats[id]).r)
#else
#define zval_(id) qhstat tempi
#define wval_(id) qhstat tempr
#endif

/*----------------------------------

  zmax_( id, val ), wmax_( id, value )
    maximize id with val
*/
#define wwmax_(id, val) {MAYdebugx; maximize_(qhstat stats[id].r,(val));}
#if qh_KEEPstatistics
#define zmax_(id, val) {MAYdebugx; maximize_(qhstat stats[id].i,(val));}
#define wmax_(id, val) {MAYdebugx; maximize_(qhstat stats[id].r,(val));}
#else
#define zmax_(id, val) {}
#define wmax_(id, val) {}
#endif

/*----------------------------------

  zmin_( id, val ), wmin_( id, value )
    minimize id with val
*/
#if qh_KEEPstatistics
#define zmin_(id, val) {MAYdebugx; minimize_(qhstat stats[id].i,(val));}
#define wmin_(id, val) {MAYdebugx; minimize_(qhstat stats[id].r,(val));}
#else
#define zmin_(id, val) {}
#define wmin_(id, val) {}
#endif

/*================== stat.h types ==============*/


/*----------------------------------

  intrealT
    union of integer and real, used for statistics
*/
typedef union intrealT intrealT;    /* union of int and realT */
union intrealT {
    int i;
    realT r;
};

/*----------------------------------

  qhstat
    global data structure for statistics, similar to qh and qhrbox

  notes:
   access to qh_qhstat is via the "qhstat" macro.  There are two choices
   qh_QHpointer = 1     access globals via a pointer
                        enables qh_saveqhull() and qh_restoreqhull()
                = 0     qh_qhstat is a static data structure
                        only one instance of qhull() can be active at a time
                        default value
   qh_QHpointer is defined in libqhull.h
   For msvc, qh_QHpointer_dllimport or qh_dllimport define qh_qh as __declspec(dllimport) [libqhull.h]

   allocated in stat.c using qh_malloc()
*/
#ifndef DEFqhstatT
#define DEFqhstatT 1
typedef struct qhstatT qhstatT;
#endif

#ifdef qh_QHpointer_dllimport
#define qhstat qh_qhstat->
__declspec(dllimport) extern qhstatT *qh_qhstat;
#elif qh_QHpointer
#define qhstat qh_qhstat->
extern qhstatT *qh_qhstat;
#elif defined(qh_dllimport)
#define qhstat qh_qhstat.
__declspec(dllimport) extern qhstatT qh_qhstat;
#else
#define qhstat qh_qhstat.
extern qhstatT qh_qhstat;
#endif
struct qhstatT {
  intrealT   stats[ZEND];     /* integer and real statistics */
  unsigned char id[ZEND+10];  /* id's in print order */
  const char *doc[ZEND];      /* array of documentation strings */
  short int  count[ZEND];     /* -1 if none, else index of count to use */
  char       type[ZEND];      /* type, see ztypes above */
  char       printed[ZEND];   /* true, if statistic has been printed */
  intrealT   init[ZTYPEend];  /* initial values by types, set initstatistics */

  int        next;            /* next index for zdef_ */
  int        precision;       /* index for precision problems, printed on qh_errexit and qh_produce_output2/Q0/QJn */
  int        vridges;         /* index for Voronoi ridges, printed on qh_produce_output2 */
  int        tempi;
  realT      tempr;
};

/*========== function prototypes ===========*/

void    qh_allstatA(void);
void    qh_allstatB(void);
void    qh_allstatC(void);
void    qh_allstatD(void);
void    qh_allstatE(void);
void    qh_allstatE2(void);
void    qh_allstatF(void);
void    qh_allstatG(void);
void    qh_allstatH(void);
void    qh_allstatI(void);
void    qh_allstatistics(void);
void    qh_collectstatistics(void);
void    qh_freestatistics(void);
void    qh_initstatistics(void);
boolT   qh_newstats(int idx, int *nextindex);
boolT   qh_nostatistic(int i);
void    qh_printallstatistics(FILE *fp, const char *string);
void    qh_printstatistics(FILE *fp, const char *string);
void    qh_printstatlevel(FILE *fp, int id);
void    qh_printstats(FILE *fp, int idx, int *nextindex);
realT   qh_stddev(int num, realT tot, realT tot2, realT *ave);

#endif   /* qhDEFstat */
qhull-2020.2/src/libqhull/user.c0000644060175106010010000005666413723004442014733 0ustar  bbarber/*
  ---------------------------------

   user.c
   user redefinable functions

   see user2.c for qh_fprintf, qh_malloc, qh_free

   see README.txt  see COPYING.txt for copyright information.

   see libqhull.h for data structures, macros, and user-callable functions.

   see user_eg.c, user_eg2.c, and unix.c 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@qhull.org

   Qhull-template 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"

#include 

/*---------------------------------

  Qhull-template
    Template for calling qhull from inside your program

  returns:
    exit code(see qh_ERR... in libqhull.h)
    all memory freed

  notes:
    This can be called any number of times.
*/
#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 html/qh-quick.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 */

  QHULL_LIB_CHECK /* Check for compatible library */

#if qh_QHpointer  /* see user.h */
  if (qh_qh){ /* should be NULL */
      qh_printf_stderr(6238, "Qhull link error.  The global variable qh_qh was not initialized to NULL by global.c.\n\
Please compile this program with -Dqh_QHpointer_dllimport and -Dqh_QHpointer,\n\
or use libqhull_r or libqhullstatic, or a different tool chain.\n\n");
      exit(1);
  }
#endif

  /* 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)
    qh_fprintf(errfile, 7079, "qhull internal warning (main): did not free %d bytes of long memory(%d pieces)\n", totlong, curlong);
}
#endif

/*---------------------------------

  qh_new_qhull( dim, numpoints, points, ismalloc, qhull_cmd, outfile, errfile )
    Run qhull
    if numpoints=0 and points=NULL, initializes qhull

  returns:
    results in qh
    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().
    do not call qh_init_A (global.c)

    Default errfile is stderr, 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()
    - use libqhull_r for reentrant Qhull
    - qh_QHpointer is deprecated.  To use it
    -   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:
    Qhull-template at the beginning of this file.
    An example of using qh_new_qhull is user_eg.c
*/
int qh_new_qhull(int dim, int numpoints, coordT *points, boolT ismalloc,
                char *qhull_cmd, FILE *outfile, FILE *errfile) {
  /* gcc may issue a "might be clobbered" warning for dim, points, and ismalloc [-Wclobbered].
     These parameters are not referenced after a longjmp() and hence not clobbered.
     See http://stackoverflow.com/questions/7721854/what-sense-do-these-clobbered-variable-warnings-make */
  int exitcode, hulldim;
  boolT new_ismalloc;
  static boolT firstcall= True;
  coordT *new_points;
  if(!errfile){
    errfile= stderr;
  }
  if (firstcall) {
    qh_meminit(errfile);
    firstcall= False;
  } else {
    qh_memcheck();
  }
  if (strncmp(qhull_cmd, "qhull ", (size_t)6) && strcmp(qhull_cmd, "qhull") != 0) {
    qh_fprintf(errfile, 6186, "qhull error (qh_new_qhull): start qhull_cmd argument with \"qhull \" or set to \"qhull\"\n");
    return qh_ERRinput;
  }
  qh_initqhull_start(NULL, outfile, errfile);
  if(numpoints==0 && points==NULL){
      trace1((qh ferr, 1047, "qh_new_qhull: initialize Qhull\n"));
      return 0;
  }
  trace1((qh ferr, 1044, "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)
        qh_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();
    }else {
      qh_prepare_output();
    }
    if (qh VERIFYoutput && !qh FORCEoutput && !qh STOPadd && !qh STOPcone && !qh STOPpoint)
      qh_check_points();
  }
  qh NOerrexit= True;
  return exitcode;
} /* new_qhull */

/*---------------------------------

  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 libqhull.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) {

  qh tracefacet= NULL;  /* avoid infinite recursion through qh_fprintf */
  qh traceridge= NULL;
  qh tracevertex= NULL;
  if (qh ERREXITcalled) {
    qh_fprintf(qh ferr, 8126, "\nqhull error while handling previous error in qh_errexit.  Exit program\n");
    qh_exit(qh_ERRother);
  }
  qh ERREXITcalled= True;
  if (!qh QHULLfinished)
    qh hulltime= qh_CPUclock - qh hulltime;
  qh_errprint("ERRONEOUS", facet, NULL, ridge, NULL);
  qh_option("_maxoutside", NULL, &qh MAXoutside);
  qh_fprintf(qh ferr, 8127, "\nWhile executing: %s | %s\n", qh rbox_command, qh qhull_command);
  qh_fprintf(qh ferr, 8128, "Options selected for Qhull %s:\n%s\n", qh_version, qh qhull_options);
  if (qh furthest_id >= 0) {
    qh_fprintf(qh ferr, 8129, "Last point added to hull was p%d.", qh furthest_id);
    if (zzval_(Ztotmerge))
      qh_fprintf(qh ferr, 8130, "  Last merge was #%d.", zzval_(Ztotmerge));
    if (qh QHULLfinished)
      qh_fprintf(qh ferr, 8131, "\nQhull has finished constructing the hull.");
    else if (qh POSTmerging)
      qh_fprintf(qh ferr, 8132, "\nQhull has started post-merging.");
    qh_fprintf(qh ferr, 8133, "\n");
  }
  if (qh FORCEoutput && (qh QHULLfinished || (!facet && !ridge)))
    qh_produce_output();
  else if (exitcode != qh_ERRinput) {
    if (exitcode != qh_ERRsingular && zzval_(Zsetplane) > qh hull_dim+1) {
      qh_fprintf(qh ferr, 8134, "\nAt error exit:\n");
      qh_printsummary(qh ferr);
      if (qh PRINTstatistics) {
        qh_collectstatistics();
        qh_allstatistics();
        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_ERRother;
  else if (exitcode == qh_ERRprec && !qh PREmerge)
    qh_printhelp_degenerate(qh ferr);
  else if (exitcode == qh_ERRqhull)
    qh_printhelp_internal(qh ferr);
  else if (exitcode == qh_ERRsingular)
    qh_printhelp_singular(qh ferr);
  else if (exitcode == qh_ERRdebug)
    qh_fprintf(qh ferr, 8016, "qhull exit due to qh_ERRdebug\n");
  else if (exitcode == qh_ERRtopology || exitcode == qh_ERRwide || exitcode == qh_ERRprec) {
    if (qh NOpremerge && !qh MERGING)
      qh_printhelp_degenerate(qh ferr);
    else if (exitcode == qh_ERRtopology)
      qh_printhelp_topology(qh ferr);
    else if (exitcode == qh_ERRwide)
      qh_printhelp_wide(qh ferr);
  }else if (exitcode > 255) {
    qh_fprintf(qh ferr, 6426, "qhull internal error (qh_errexit): exit code %d is greater than 255.  Invalid argument for exit().  Replaced with 255\n", exitcode);
    exitcode= 255;
  }
  if (qh NOerrexit) {
    qh_fprintf(qh ferr, 6187, "qhull internal error (qh_errexit): either error while reporting error QH%d, or qh.NOerrexit not cleared after setjmp(). Exit program with error status %d\n",
         qh last_errcode, exitcode);
    qh_exit(exitcode);
  }
  qh ERREXITcalled= False;
  qh NOerrexit= True;
  qh ALLOWrestart= False;  /* longjmp will undo qh_build_withrestart */
  longjmp(qh errexit, exitcode);
} /* errexit */

/*---------------------------------

  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(const char *string, facetT *atfacet, facetT *otherfacet, ridgeT *atridge, vertexT *atvertex) {
  int i;

  if (atvertex) {
    qh_fprintf(qh ferr, 8138, "%s VERTEX:\n", string);
    qh_printvertex(qh ferr, atvertex);
  }
  if (atridge) {
    qh_fprintf(qh ferr, 8137, "%s RIDGE:\n", string);
    qh_printridge(qh ferr, atridge);
    if (!atfacet)
      atfacet= atridge->top;
    if (!otherfacet)
      otherfacet= otherfacet_(atridge, atfacet);
    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) {
    qh_fprintf(qh ferr, 8135, "%s FACET:\n", string);
    qh_printfacet(qh ferr, atfacet);
  }
  if (otherfacet) {
    qh_fprintf(qh ferr, 8136, "%s OTHER FACET:\n", string);
    qh_printfacet(qh ferr, otherfacet);
  }
  if (qh fout && qh FORCEoutput && atfacet && !qh QHULLfinished && !qh IStracing) {
    qh_fprintf(qh ferr, 8139, "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 */


/*---------------------------------

  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;

  if (facetlist)
    qh_checklists(facetlist);
  qh_fprintf(qh ferr, 9424, "printfacetlist: vertices\n");
  qh_printbegin(qh ferr, qh_PRINTfacets, facetlist, facets, printall);
  if (facetlist) {
    qh_fprintf(qh ferr, 9413, "printfacetlist: facetlist\n");
    FORALLfacet_(facetlist)
      qh_printafacet(qh ferr, qh_PRINTfacets, facet, printall);
  }
  if (facets) {
    qh_fprintf(qh ferr, 9414, "printfacetlist: %d facets\n", qh_setsize(facets));
    FOREACHfacet_(facets)
      qh_printafacet(qh ferr, qh_PRINTfacets, facet, printall);
  }
  qh_fprintf(qh ferr, 9412, "printfacetlist: end\n");
  qh_printend(qh ferr, qh_PRINTfacets, facetlist, facets, printall);
} /* printfacetlist */


/*---------------------------------

  qh_printhelp_degenerate( fp )
    prints descriptive message for precision error with qh_ERRprec

  notes:
    no message if qh_QUICKhelp
*/
void qh_printhelp_degenerate(FILE *fp) {

  if (qh MERGEexact || qh PREmerge || qh JOGGLEmax < REALmax/2)
    qh_fprintf(fp, 9368, "\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@qhull.org\n");
  else if (!qh_QUICKhelp) {
    qh_fprintf(fp, 9369, "\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
    qh_fprintf(fp, 9370, "\
\n\
Qhull is currently using single precision arithmetic.  The following\n\
will probably remove the precision problems:\n\
  - recompile qhull for realT precision(#define REALfloat 0 in user.h).\n");
#endif
    if (qh DELAUNAY && !qh SCALElast && qh MAXabs_coord > 1e4)
      qh_fprintf(fp, 9371, "\
\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)
      qh_fprintf(fp, 9372, "\
When computing the Delaunay triangulation:\n\
  - use 'Qz' to add a point at-infinity.  This reduces precision problems.\n");

    qh_fprintf(fp, 9373, "\
\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);
    qh_fprintf(fp, 9374, "\
\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 */

/*---------------------------------

  qh_printhelp_internal( fp )
    prints descriptive message for qhull internal error with qh_ERRqhull

  notes:
    no message if qh_QUICKhelp
*/
void qh_printhelp_internal(FILE *fp) {

  if (!qh_QUICKhelp) {
    qh_fprintf(fp, 9426, "\n\
A Qhull internal error has occurred.  Please send the input and output to\n\
qhull_bug@qhull.org. If you can duplicate the error with logging ('T4z'), please\n\
include the log file.\n");
  }
} /* printhelp_internal */

/*---------------------------------

  qh_printhelp_narrowhull( minangle )
    Warn about a narrow hull

  notes:
    Alternatively, reduce qh_WARNnarrow in user.h

*/
void qh_printhelp_narrowhull(FILE *fp, realT minangle) {

    qh_fprintf(fp, 7089, "qhull precision warning: The initial hull is narrow.  Is the input lower\n\
dimensional (e.g., a square in 3-d instead of a cube)?  Cosine of the minimum\n\
angle is %.16f.  If so, Qhull may produce a wide facet.\n\
Options 'Qs' (search all points), 'Qbb' (scale last coordinate), or\n\
'QbB' (scale to unit box) may remove this warning.\n\
See 'Limitations' in qh-impre.htm.  Use 'Pp' to skip this warning.\n",
          -minangle);   /* convert from angle between normals to angle between facets */
} /* printhelp_narrowhull */

/*---------------------------------

  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;

  qh_fprintf(fp, 9376, "\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)
    qh_fprintf(fp, 9377, "\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, qh_IDunknown);
  qh_fprintf(fp, 9378, "\n");
  FORALLfacets {
    qh_fprintf(fp, 9379, "facet");
    FOREACHvertex_(facet->vertices)
      qh_fprintf(fp, 9380, " p%d", qh_pointid(vertex->point));
    zinc_(Zdistio);
    qh_distplane(qh interior_point, facet, &dist);
    qh_fprintf(fp, 9381, " distance= %4.2g\n", dist);
  }
  if (!qh_QUICKhelp) {
    if (qh HALFspace)
      qh_fprintf(fp, 9382, "\n\
These points are the dual of the given halfspaces.  They indicate that\n\
the intersection is degenerate.\n");
    qh_fprintf(fp, 9383,"\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)
      qh_fprintf(fp, 9384, "\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");
  }
  qh_fprintf(fp, 9385, "\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);
    }
    qh_fprintf(fp, 9386, "  %d:  %8.4g  %8.4g  difference= %4.4g\n", k, min, max, max-min);
  }
  if (!qh_QUICKhelp) {
    qh_fprintf(fp, 9387, "\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
    qh_fprintf(fp, 9388, "\
  - recompile qhull for realT precision(#define REALfloat 0 in libqhull.h).\n");
#endif
    qh_fprintf(fp, 9389, "\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\
");
  }
} /* printhelp_singular */

/*---------------------------------

  qh_printhelp_topology( fp )
    prints descriptive message for qhull topology error with qh_ERRtopology

  notes:
    no message if qh_QUICKhelp
*/
void qh_printhelp_topology(FILE *fp) {

  if (!qh_QUICKhelp) {
    qh_fprintf(fp, 9427, "\n\
A Qhull topology error has occurred.  Qhull did not recover from facet merges and vertex merges.\n\
This usually occurs when the input is nearly degenerate and substantial merging has occurred.\n\
See http://www.qhull.org/html/qh-impre.htm#limit\n");
  }
} /* printhelp_topology */

/*---------------------------------

  qh_printhelp_wide( fp )
    prints descriptive message for qhull wide facet with qh_ERRwide

  notes:
    no message if qh_QUICKhelp
*/
void qh_printhelp_wide(FILE *fp) {

  if (!qh_QUICKhelp) {
    qh_fprintf(fp, 9428, "\n\
A wide merge error has occurred.  Qhull has produced a wide facet due to facet merges and vertex merges.\n\
This usually occurs when the input is nearly degenerate and substantial merging has occurred.\n\
See http://www.qhull.org/html/qh-impre.htm#limit\n");
  }
} /* printhelp_wide */

/*---------------------------------

  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 */


qhull-2020.2/src/libqhull/user.h0000644060175106010010000011265713662356310014741 0ustar  bbarber/*
  ---------------------------------

   user.h
   user redefinable constants

   for each source file, user.h is included first

   see qh-user.htm.  see COPYING for copyright information.

   See user.c for sample code.

   before reading any code, review libqhull.h for data structure definitions
   and the "qh" macro.

Sections:
   ============= qhull library constants ======================
   ============= data types and configuration macros ==========
   ============= performance related constants ================
   ============= memory constants =============================
   ============= joggle constants =============================
   ============= conditional compilation ======================
   ============= merge constants ==============================
   ============= Microsoft DevStudio ==========================

Code flags --
  NOerrors -- the code does not call qh_errexit()
  WARN64 -- the code may be incompatible with 64-bit pointers

*/

#include 
#include 
#include 

#ifndef qhDEFuser
#define qhDEFuser 1

/* Derived from Qt's corelib/global/qglobal.h */
#if !defined(SAG_COM) && !defined(__CYGWIN__) && (defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__))
#   define QHULL_OS_WIN
#elif defined(__MWERKS__) && defined(__INTEL__) /* Metrowerks discontinued before the release of Intel Macs */
#   define QHULL_OS_WIN
#endif

/*============================================================*/
/*============= qhull library constants ======================*/
/*============================================================*/

/*----------------------------------

  FILENAMElen -- max length for TI and TO filenames

*/

#define qh_FILENAMElen 500

/*----------------------------------

  msgcode -- Unique message codes for qh_fprintf

  If add new messages, assign these values and increment in user.h and user.h
  See QhullError.h for 10000 error codes.
  Cannot use '0031' since it would be octal

  def counters =  [31/32/33/38, 1067, 2113, 3079, 4097, 5006,
     6429, 7027/7028/7035/7068/7070/7102, 8163, 9428, 10000, 11034]

  See: qh_ERR* [libqhull.h]
*/

#define MSG_TRACE0     0   /* always include if logging ('Tn') */
#define MSG_TRACE1  1000
#define MSG_TRACE2  2000
#define MSG_TRACE3  3000
#define MSG_TRACE4  4000
#define MSG_TRACE5  5000
#define MSG_ERROR   6000   /* errors written to qh.ferr */
#define MSG_WARNING 7000
#define MSG_STDERR  8000   /* log messages Written to qh.ferr */
#define MSG_OUTPUT  9000
#define MSG_QHULL_ERROR 10000 /* errors thrown by QhullError.cpp (QHULLlastError is in QhullError.h) */
#define MSG_FIX    11000   /* Document as 'QH11... FIX: ...' */
#define MSG_MAXLEN  3000   /* qh_printhelp_degenerate() in user.c */


/*----------------------------------

  qh_OPTIONline -- max length of an option line 'FO'
*/
#define qh_OPTIONline 80

/*============================================================*/
/*============= data types and configuration macros ==========*/
/*============================================================*/

/*----------------------------------

  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
   helpful 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

/*----------------------------------

  countT
    The type for counts and identifiers (e.g., the number of points, vertex identifiers)
    Currently used by C++ code-only.  Decided against using it for setT because most sets are small.

    Defined as 'int' for C-code compatibility and QH11026

    QH11026 FIX: countT may be defined as a 'unsigned int', but several code issues need to be solved first.  See countT in Changes.txt
*/

#ifndef DEFcountT
#define DEFcountT 1
typedef int countT;
#endif
#define COUNTmax INT_MAX

/*----------------------------------

  qh_POINTSmax
    Maximum number of points for qh.num_points and point allocation in qh_readpoints
*/
#define qh_POINTSmax (INT_MAX-16)

/*----------------------------------

  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.  By default,
     defines clock_t as 'long'

   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, may be converted to approximate double */
#define qh_SECticks CLOCKS_PER_SECOND

#elif defined(CLOCKS_PER_SEC)
#define qh_CPUclock    ((unsigned long)clock())  /* return CPU clock, may be converted to approximate double */
#define qh_SECticks CLOCKS_PER_SEC

#elif defined(CLK_TCK)
#define qh_CPUclock    ((unsigned long)clock())  /* return CPU clock, may be converted to approximate double */
#define qh_SECticks CLK_TCK

#else
#define qh_CPUclock    ((unsigned long)clock())  /* return CPU clock, may be converted to approximate double */
#define qh_SECticks 1E6
#endif

#elif (qh_CLOCKtype == 2)
#define qh_CPUclock    qh_clock()  /* return CPU clock, may be converted to approximate double */
#define qh_SECticks 100

#else /* qh_CLOCKtype == ? */
#error unknown clock option
#endif

/*----------------------------------

  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 int)seed);

#elif (qh_RANDOMtype == 3)
#define qh_RANDOMmax ((realT)0x7fffffffUL)  /* 31 bits, Sun */
#define qh_RANDOMint  rand()
#define qh_RANDOMseed_(seed) srand((unsigned int)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

/*----------------------------------

  qh_ORIENTclock
    0 for inward pointing normals by Geomview convention
*/
#define qh_ORIENTclock 0

/*----------------------------------

  qh_RANDOMdist
    define for random perturbation of qh_distplane and qh_setfacetplane (qh.RANDOMdist, 'QRn')

  For testing qh.DISTround.  Qhull should not depend on computations always producing the same roundoff error 

  #define qh_RANDOMdist 1e-13
*/

/*============================================================*/
/*============= joggle constants =============================*/
/*============================================================*/

/*----------------------------------

  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

/*----------------------------------

  qh_JOGGLEincrease
    factor to increase qh.JOGGLEmax on qh_JOGGLEretry or qh_JOGGLEagain
*/
#define qh_JOGGLEincrease 10.0

/*----------------------------------

  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

/*----------------------------------

  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

/*----------------------------------

  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

/*----------------------------------

  qh_JOGGLEmaxretry
    stop after qh_JOGGLEmaxretry attempts
*/
#define qh_JOGGLEmaxretry 50

/*============================================================*/
/*============= performance related constants ================*/
/*============================================================*/

/*----------------------------------

  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

/*----------------------------------

  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

/*----------------------------------

  qh_INITIALsearch
     if qh_INITIALmax, search points up to this dimension
*/
#define qh_INITIALsearch 6

/*----------------------------------

  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

/*============================================================*/
/*============= memory constants =============================*/
/*============================================================*/

/*----------------------------------

  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 [fmax_() is defined in geom.h]
              #define qh_MEMalign fmax_(__alignof__(realT),__alignof__(void *))
*/
#define qh_MEMalign ((int)(fmax_(sizeof(realT), sizeof(void *))))

/*----------------------------------

  qh_MEMbufsize
    size of additional memory buffers

  notes:
    used for qh_meminitbuffers() in global.c
*/
#define qh_MEMbufsize 0x10000       /* allocate 64K memory buffers */

/*----------------------------------

  qh_MEMinitbuf
    size of initial memory buffer

  notes:
    use for qh_meminitbuffers() in global.c
*/
#define qh_MEMinitbuf 0x20000      /* initially allocate 128K buffer */

/*----------------------------------

  qh_INFINITE
    on output, indicates Voronoi center at infinity
*/
#define qh_INFINITE  -10.101

/*----------------------------------

  qh_DEFAULTbox
    default box size (Geomview expects 0.5)

  qh_DEFAULTbox
    default box size for integer coorindate (rbox only)
*/
#define qh_DEFAULTbox 0.5
#define qh_DEFAULTzbox 1e6

/*============================================================*/
/*============= conditional compilation ======================*/
/*============================================================*/

/*----------------------------------

  __cplusplus
    defined by C++ compilers

  __MSC_VER
    defined by Microsoft Visual C++

  __MWERKS__ && __INTEL__
    defined by Metrowerks when compiling for Windows (not Intel-based Macintosh)

  __MWERKS__ && __POWERPC__
    defined by Metrowerks when compiling for PowerPC-based Macintosh

  __STDC__
    defined for strict ANSI C
*/

/*----------------------------------

  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

/*----------------------------------

  qh_KEEPstatistics
    =0 removes most of statistic gathering and reporting

  notes:
    if 0, code size is reduced by about 4%.
*/
#define qh_KEEPstatistics 1

/*----------------------------------

  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

/*----------------------------------

  qh_NOmerge
    disables facet merging if defined
    For MSVC compiles, use qhull-exports-nomerge.def instead of qhull-exports.def

  notes:
    This saves about 25% space, 30% space in combination with qh_NOtrace, 
    and 36% with qh_NOtrace and qh_KEEPstatistics 0

    Unless option 'Q0' is used
      qh_NOmerge sets 'QJ' to avoid precision errors

  see:
    qh_NOmem in mem.h

    see user.c/user_eg.c for removing io.o

  #define qh_NOmerge
*/

/*----------------------------------

  qh_NOtrace
    no tracing if defined
    disables 'Tn', 'TMn', 'TPn' and 'TWn'
    override with 'Qw' for qh_addpoint tracing and various other items

  notes:
    This saves about 15% space.
    Removes all traceN((...)) code and substantial sections of qh.IStracing code

  #define qh_NOtrace
*/

/*----------------------------------

  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()
                        [2010, gcc] costs about 4% in time and 4% in space
                        [2003, msvc] 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

  For msvc, define qh_QHpointer_dllimport or qh_dllimport for qh_qh as __declspec(dllimport) [libqhull.h]

  notes:
    [jan'16] qh_QHpointer is deprecated for Qhull.  Use libqhull_r instead.
    all global variables for qhull are in qh, qhmem, and qhstat
    qh is defined in libqhull.h
    qhmem is defined in mem.h
    qhstat is defined in stat.h

  #define qh_QHpointer 1
*/

#ifdef qh_QHpointer
#ifdef qh_dllimport
#error QH6207 Qhull error: Define qh_QHpointer_dllimport instead of qh_dllimport with qh_QHpointer
#endif
#else
#define qh_QHpointer 0
#ifdef qh_QHpointer_dllimport
#error QH6234 Qhull error: Define qh_dllimport instead of qh_QHpointer_dllimport when qh_QHpointer is not defined
#endif
#endif
#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

/*----------------------------------

  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 them.  They effect the performance of facet merging.
*/

/*----------------------------------

  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

/*----------------------------------

  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

/*----------------------------------

  qh_COPLANARratio
    for 3-d+ merging, qh.MINvisible is n*premerge_centrum

  notes:
    for non-merging, it's DISTround
*/
#define qh_COPLANARratio 3

/*----------------------------------

  qh_DIMmergeVertex
    max dimension for vertex merging (it is not effective in high-d)
*/
#define qh_DIMmergeVertex 6

/*----------------------------------

  qh_DIMreduceBuild
     max dimension for vertex reduction during build (slow in high-d)
*/
#define qh_DIMreduceBuild 5

/*----------------------------------

  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))

/*----------------------------------

  qh_MAXcheckpoint
    Report up to qh_MAXcheckpoint errors per facet in qh_check_point ('Tv')
*/
#define qh_MAXcheckpoint 10

/*----------------------------------

  qh_MAXcoplanarcentrum
    if pre-merging with qh.MERGEexact ('Qx') and f.nummerge > qh_MAXcoplanarcentrum
      use f.maxoutside instead of qh.centrum_radius for coplanarity testing

  notes:
    see qh_test_nonsimplicial_merges
    with qh.MERGEexact, a coplanar ridge is ignored until post-merging
    otherwise a large facet with many merges may take all the facets
*/
#define qh_MAXcoplanarcentrum 10

/*----------------------------------

  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

/*----------------------------------

  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

/*----------------------------------

  qh_RATIOconcavehorizon
    ratio of horizon vertex distance to max_outside for concave, twisted new facets in qh_test_nonsimplicial_merge
    if too small, end up with vertices far below merged facets
*/
#define qh_RATIOconcavehorizon 20.0

/*----------------------------------

  qh_RATIOconvexmerge
    ratio of vertex distance to qh.min_vertex for clearly convex new facets in qh_test_nonsimplicial_merge

  notes:
    must be convex for MRGtwisted
*/
#define qh_RATIOconvexmerge 10.0

/*----------------------------------

  qh_RATIOcoplanarapex
    ratio of best distance for coplanar apex vs. vertex merge in qh_getpinchedmerges

  notes:
    A coplanar apex always works, while a vertex merge may fail
*/
#define qh_RATIOcoplanarapex 3.0

/*----------------------------------

  qh_RATIOcoplanaroutside
    qh.MAXoutside ratio to repartition a coplanar point in qh_partitioncoplanar and qh_check_maxout

  notes:
    combines several tests, see qh_partitioncoplanar

*/
#define qh_RATIOcoplanaroutside 30.0

/*----------------------------------

  qh_RATIOmaxsimplex
    ratio of max determinate to estimated determinate for searching all points in qh_maxsimplex

  notes:
    As each point is added to the simplex, the max determinate is should approximate the previous determinate * qh.MAXwidth
    If maxdet is significantly less, the simplex may not be full-dimensional.
    If so, all points are searched, stopping at 10 times qh_RATIOmaxsimplex
*/
#define qh_RATIOmaxsimplex 1.0e-3

/*----------------------------------

  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, nearly incident points
*/
#define qh_RATIOnearinside 5

/*----------------------------------

  qh_RATIOpinchedsubridge
    ratio to qh.ONEmerge to accept vertices in qh_findbest_pinchedvertex
    skips search of neighboring vertices
    facet width may increase by this ratio
*/
#define qh_RATIOpinchedsubridge 10.0

/*----------------------------------

  qh_RATIOtrypinched
    ratio to qh.ONEmerge to try qh_getpinchedmerges in qh_buildcone_mergepinched
    otherwise a duplicate ridge will increase facet width by this amount
*/
#define qh_RATIOtrypinched 4.0

/*----------------------------------

  qh_RATIOtwisted
    maximum ratio to qh.ONEmerge to merge twisted facets in qh_merge_twisted
*/
#define qh_RATIOtwisted 20.0

/*----------------------------------

  qh_SEARCHdist
    When is a facet coplanar with the best facet?
    qh_findbesthorizon: all coplanar facets of the best facet need to be searched.
        increases minsearch if ischeckmax and more than 100 neighbors (is_5x_minsearch)
  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)));

/*----------------------------------

  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)

/*----------------------------------

  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

/*----------------------------------

  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

/*----------------------------------

  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

/*----------------------------------

  qh_WIDEduplicate
    merge ratio for errexit from qh_forcedmerges due to duplicate ridge
    Override with option Q12-allow-wide

  Notes:
    Merging a duplicate ridge can lead to very wide facets.
*/
#define qh_WIDEduplicate 100

/*----------------------------------

  qh_WIDEdupridge
    Merge ratio for selecting a forced dupridge merge

  Notes:
    Merging a dupridge can lead to very wide facets.
*/
#define qh_WIDEdupridge 50

/*----------------------------------

  qh_WIDEmaxoutside
    Precision ratio for maximum increase for qh.max_outside in qh_check_maxout
    Precision errors while constructing the hull, may lead to very wide facets when checked in qh_check_maxout
    Nearly incident points in 4-d and higher is the most likely culprit
    Skip qh_check_maxout with 'Q5' (no-check-outer)
    Do not error with option 'Q12' (allow-wide)
    Do not warn with options 'Q12 Pp'
*/
#define qh_WIDEmaxoutside 100

/*----------------------------------

  qh_WIDEmaxoutside2
    Precision ratio for maximum qh.max_outside in qh_check_maxout
    Skip qh_check_maxout with 'Q5' no-check-outer
    Do not error with option 'Q12' allow-wide
*/
#define qh_WIDEmaxoutside2 (10*qh_WIDEmaxoutside)


/*----------------------------------

  qh_WIDEpinched
    Merge ratio for distance between pinched vertices compared to current facet width for qh_getpinchedmerges and qh_next_vertexmerge
    Reports warning and merges duplicate ridges instead
    Enable these attempts with option Q14 merge-pinched-vertices

  notes:
    Merging pinched vertices should prevent duplicate ridges (see qh_WIDEduplicate)
    Merging the duplicate ridges may be better than merging the pinched vertices
    Found up to 45x ratio for qh_pointdist -- for ((i=1; i<20; i++)); do rbox 175 C1,6e-13 t | qhull d T4 2>&1 | tee x.1 | grep  -E 'QH|non-simplicial|Statis|pinched'; done
    Actual distance to facets is a third to a tenth of the qh_pointdist (T1)
*/
#define qh_WIDEpinched 100

/*----------------------------------

  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

/*============================================================*/
/*============= Microsoft DevStudio ==========================*/
/*============================================================*/

/*
   Finding Memory Leaks Using the CRT Library
   https://msdn.microsoft.com/en-us/library/x98tx3cf(v=vs.100).aspx

   Reports enabled in qh_lib_check for Debug window and stderr

   From 2005=>msvcr80d, 2010=>msvcr100d, 2012=>msvcr110d

   Watch: {,,msvcr80d.dll}_crtBreakAlloc  Value from {n} in the leak report
   _CrtSetBreakAlloc(689); // qh_lib_check() [global.c]

   Examples
     http://free-cad.sourceforge.net/SrcDocu/d2/d7f/MemDebug_8cpp_source.html
     https://github.com/illlust/Game/blob/master/library/MemoryLeak.cpp
*/
#if 0   /* off (0) by default for QHULL_CRTDBG */
#define QHULL_CRTDBG
#endif

#if defined(_MSC_VER) && defined(_DEBUG) && defined(QHULL_CRTDBG)
#define _CRTDBG_MAP_ALLOC
#include 
#include 
#endif

#endif /* qh_DEFuser */
qhull-2020.2/src/libqhull/usermem.c0000644060175106010010000000524613505435375015433 0ustar  bbarber/*
  ---------------------------------

   usermem.c
   user redefinable functions -- qh_exit, qh_free, and qh_malloc

   See README.txt.

   If you redefine one of these functions you must redefine all of them.
   If you recompile and load this file, then usermem.o will not be loaded
   from qhull.a or qhull.lib

   See libqhull.h for data structures, macros, and user-callable functions.
   See user.c for qhull-related, redefinable functions
   see user.h for user-definable constants
   See userprintf.c for qh_fprintf and userprintf_rbox.c for qh_fprintf_rbox

   Please report any errors that you fix to qhull@qhull.org
*/

#include "libqhull.h"

#include 
#include 

/*---------------------------------

  qh_exit( exitcode )
    exit program
    the exitcode must be 255 or less.  Zero indicates success.
    Note: Exit status ('$?') in bash reports 256 as 0

  notes:
    qh_exit() is called when qh_errexit() and longjmp() are not available.

    This is the only use of exit() in Qhull
    To replace qh_exit with 'throw', see libqhullcpp/usermem_r-cpp.cpp
*/
void qh_exit(int exitcode) {
    exit(exitcode);
} /* exit */

/*---------------------------------

  qh_fprintf_stderr( msgcode, format, list of args )
    fprintf to stderr with msgcode (non-zero)

  notes:
    qh_fprintf_stderr() is called when qh.ferr is not defined, usually due to an initialization error
    if msgcode is a MSG_ERROR (6000), caller should set qh.last_errcode (like qh_fprintf) or variable 'last_errcode'
    
    It is typically followed by qh_errexit().

    Redefine this function to avoid using stderr

    Use qh_fprintf [userprintf.c] for normal printing
*/
void qh_fprintf_stderr(int msgcode, const char *fmt, ... ) {
    va_list args;

    va_start(args, fmt);
    if(msgcode)
      fprintf(stderr, "QH%.4d ", msgcode);
    vfprintf(stderr, fmt, args);
    va_end(args);
} /* fprintf_stderr */

/*---------------------------------

  qh_free( mem )
    free memory

  notes:
    same as free()
    No calls to qh_errexit() 
*/
void qh_free(void *mem) {
    free(mem);
} /* free */

/*---------------------------------

    qh_malloc( mem )
      allocate memory

    notes:
      same as malloc()
*/
void *qh_malloc(size_t size) {
    return malloc(size);
} /* malloc */


qhull-2020.2/src/libqhull/userprintf.c0000644060175106010010000000623113505243373016145 0ustar  bbarber/*
  ---------------------------------

  userprintf.c
  user redefinable function -- qh_fprintf

  see README.txt  see COPYING.txt for copyright information.

  If you recompile and load this file, then userprintf.o will not be loaded
  from qhull.a or qhull.lib

  See libqhull.h for data structures, macros, and user-callable functions.
  See user.c for qhull-related, redefinable functions
  see user.h for user-definable constants
  See usermem.c for qh_exit(), qh_free(), and qh_malloc()
  see Qhull.cpp and RboxPoints.cpp for examples.

  qh_printf is a good location for debugging traps, checked on each log line

  Please report any errors that you fix to qhull@qhull.org
*/

#include "libqhull.h"
#include "poly.h" /* for qh.tracefacet */

#include 
#include 
#include 

/*---------------------------------

  qh_fprintf( fp, msgcode, format, list of args )
    print arguments to *fp according to format
    Use qh_fprintf_rbox() for rboxlib.c

  notes:
    sets qh.last_errcode if msgcode is error 6000..6999
    same as fprintf()
    fgets() is not trapped like fprintf()
    exit qh_fprintf via qh_errexit()
    may be called for errors in qh_initstatistics and qh_meminit
*/

void qh_fprintf(FILE *fp, int msgcode, const char *fmt, ... ) {
  va_list args;
  facetT *neighbor, **neighborp;

  if (!fp) {
    /* could use qhmem.ferr, but probably better to be cautious */
    qh_fprintf_stderr(6028, "qhull internal error (userprintf.c): fp is 0.  Perhaps the wrong qh_fprintf was called.\n");
    qh last_errcode= 6028;
    qh_errexit(qh_ERRqhull, NULL, NULL);
  }
#if qh_QHpointer
  if ((qh_qh && qh ANNOTATEoutput) || msgcode < MSG_TRACE4) {
#else
  if (msgcode < MSG_TRACE4) {
#endif
    fprintf(fp, "[QH%.4d]", msgcode);
  }else if (msgcode >= MSG_ERROR && msgcode < MSG_STDERR ) {
    fprintf(fp, "QH%.4d ", msgcode);
  }
  va_start(args, fmt);
  vfprintf(fp, fmt, args);
  va_end(args);
    
#if qh_QHpointer
  if (qh_qh) {
#else
  {
#endif
    if (msgcode >= MSG_ERROR && msgcode < MSG_WARNING)
      qh last_errcode= msgcode;
    /* Place debugging traps here. Use with trace option 'Tn' 
       Set qh.tracefacet_id, qh.traceridge_id, and/or qh.tracevertex_id in global.c
    */
    if (False) { /* in production skip test for debugging traps */
      if (qh tracefacet && qh tracefacet->tested) {
        if (qh_setsize(qh tracefacet->neighbors) < qh hull_dim)
          qh_errexit(qh_ERRdebug, qh tracefacet, qh traceridge);
        FOREACHneighbor_(qh tracefacet) {
          if (neighbor != qh_DUPLICATEridge && neighbor != qh_MERGEridge && neighbor->visible)
            qh_errexit2(qh_ERRdebug, qh tracefacet, neighbor);
        }
      } 
      if (qh traceridge && qh traceridge->top->id == 234342223) {
        qh_errexit(qh_ERRdebug, qh tracefacet, qh traceridge);
      }
      if (qh tracevertex && qh_setsize(qh tracevertex->neighbors)>3434334) {
        qh_errexit(qh_ERRdebug, qh tracefacet, qh traceridge);
      }
    }
    if (qh FLUSHprint)
      fflush(fp);
  }
} /* qh_fprintf */

qhull-2020.2/src/libqhull/userprintf_rbox.c0000644060175106010010000000317113505435503017175 0ustar  bbarber/*
  ---------------------------------

   userprintf_rbox.c
   user redefinable function -- qh_fprintf_rbox

   see README.txt  see COPYING.txt for copyright information.

   If you recompile and load this file, then userprintf_rbox.o will not be loaded
   from qhull.a or qhull.lib

   See libqhull.h for data structures, macros, and user-callable functions.
   See user.c for qhull-related, redefinable functions
   see user.h for user-definable constants
   See usermem.c for qh_exit(), qh_free(), and qh_malloc()
   see Qhull.cpp and RboxPoints.cpp for examples.

   Please report any errors that you fix to qhull@qhull.org
*/

#include "libqhull.h"

#include 
#include 
#include 

/*---------------------------------

   qh_fprintf_rbox( fp, msgcode, format, list of args )
     print arguments to *fp according to format
     Use qh_fprintf_rbox() for rboxlib.c

   notes:
     same as fprintf()
     fgets() is not trapped like fprintf()
     exit qh_fprintf_rbox via qh_errexit_rbox()
*/

void qh_fprintf_rbox(FILE *fp, int msgcode, const char *fmt, ... ) {
    va_list args;

    if (!fp) {
      qh_fprintf_stderr(6231, "qhull internal error (userprintf_rbox.c): fp is 0.  Wrong qh_fprintf_rbox called.\n");
      qh_errexit_rbox(qh_ERRqhull);
    }
    if (msgcode >= MSG_ERROR && msgcode < MSG_STDERR)
      fprintf(fp, "QH%.4d ", msgcode);
    va_start(args, fmt);
    vfprintf(fp, fmt, args);
    va_end(args);
} /* qh_fprintf_rbox */

qhull-2020.2/src/libqhullcpp/0000755060175106010010000000000013724321405014275 5ustar  bbarberqhull-2020.2/src/libqhullcpp/Coordinates.cpp0000644060175106010010000001056113710645347017267 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2009-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/Coordinates.cpp#4 $$Change: 3009 $
** $DateTime: 2020/07/30 19:25:22 $$Author: bbarber $
**
****************************************************************************/

#include "libqhullcpp/Coordinates.h"

#include "libqhullcpp/functionObjects.h"
#include "libqhullcpp/QhullError.h"

#include 
#include 
#include 

#ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
#endif

namespace orgQhull {

#//! Coordinates -- vector of coordT (normally double)

#//!\name Constructor

#//!\name Element access

// Inefficient without result-value-optimization or implicitly shared object
Coordinates Coordinates::
mid(countT idx, countT length) const
{
    countT newLength= length;
    if(length<0 || idx+length > count()){
        newLength= count()-idx;
    }
    Coordinates result;
    if(newLength>0){
        std::copy(begin()+idx, begin()+(idx+newLength), std::back_inserter(result));
    }
    return result;
}//mid

coordT Coordinates::
value(countT idx, const coordT &defaultValue) const
{
    return ((idx < 0 || idx >= count()) ? defaultValue : (*this)[idx]);
}//value

#//!\name GetSet

Coordinates Coordinates::
operator+(const Coordinates &other) const
{
    Coordinates result(*this);
    std::copy(other.begin(), other.end(), std::back_inserter(result));
    return result;
}//operator+

Coordinates & Coordinates::
operator+=(const Coordinates &other)
{
    if(&other==this){
        Coordinates clone(other);
        std::copy(clone.begin(), clone.end(), std::back_inserter(*this));
    }else{
        std::copy(other.begin(), other.end(), std::back_inserter(*this));
    }
    return *this;
}//operator+=

#//!\name Read-write

void Coordinates::
append(int pointDimension, coordT *c)
{
    if(c){
        coordT *p= c;
        for(int i= 0; i(i-begin())); // WARN64 coordinate index
            }
            ++i;
        }
    }
    return -1;
}//indexOf

countT Coordinates::
lastIndexOf(const coordT &t, countT from) const
{
    countT idx;
    if(from<0){
        from += count();
    }else if(from>=count()){
        from= count()-1;
    }
    if(from>=0){
        const_iterator i= begin()+from+1;
        while(i-- != constBegin()){
            if(*i==t){
                idx= static_cast(i-begin()); // WARN64 coordinate index
                return idx;
            }
        }
    }
    return -1;
}//lastIndexOf

void Coordinates::
removeAll(const coordT &t)
{
    std::vector::iterator i= coordinate_array.begin();
    while(i!=coordinate_array.end()){
        if(*i==t){
            i= coordinate_array.erase(i);
        }else{
            ++i;
        }
    }
}//removeAll

}//namespace orgQhull

#//!\name Global functions

using std::endl;
using std::istream;
using std::ostream;
using std::string;
using std::ws;
using orgQhull::Coordinates;

ostream &
operator<<(ostream &os, const Coordinates &cs)
{
    Coordinates::const_iterator c= cs.begin();
    for(countT i=cs.count(); i--; ){
        os << *c++ << " ";
    }
    return os;
}//operator<<

qhull-2020.2/src/libqhullcpp/Coordinates.h0000644060175106010010000003107613706662047016741 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2009-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/Coordinates.h#5 $$Change: 3001 $
** $DateTime: 2020/07/24 20:43:28 $$Author: bbarber $
**
****************************************************************************/

#ifndef QHCOORDINATES_H
#define QHCOORDINATES_H

#include "libqhull_r/qhull_ra.h"
#include "libqhullcpp/QhullError.h"

#include  // ptrdiff_t, size_t
#include 
// Requires STL vector class.  Can use with another vector class such as QList.
#include 

namespace orgQhull {

#//!\name Defined here
    //! An std::vector of point coordinates independent of dimension
    //! Used by PointCoordinates for RboxPoints and by Qhull for feasiblePoint
    //! A QhullPoint refers to previously allocated coordinates
    class Coordinates;

    //! Java-style iterators are not implemented for Coordinates.  std::vector has an expensive copy constructor and copy assignment.
    //!    A pointer to Coordinates is vulnerable to mysterious overwrites (e.g., deleting a returned value and reusing its memory)
    //! Qt's 'foreach' should not be used.  It makes a copy of the std::vector

class Coordinates {

private:
#//!\name Fields
    std::vector coordinate_array;

public:
#//!\name Subtypes

    class const_iterator;
    class iterator;
    typedef iterator Iterator;
    typedef const_iterator ConstIterator;

    typedef coordT              value_type;
    typedef const value_type   *const_pointer;
    typedef const value_type &  const_reference;
    typedef value_type *        pointer;
    typedef value_type &        reference;
    typedef ptrdiff_t           difference_type;
    typedef countT              size_type;

#//!\name Construct
                        Coordinates() : coordinate_array() {}
    explicit            Coordinates(const std::vector &other) : coordinate_array(other) {}
                        Coordinates(const Coordinates &other) : coordinate_array(other.coordinate_array) {}
    Coordinates &       operator=(const Coordinates &other) { coordinate_array= other.coordinate_array; return *this; }
    Coordinates &       operator=(const std::vector &other) { coordinate_array= other; return *this; }
                        ~Coordinates() {}

#//!\name Conversion

#ifndef QHULL_NO_STL
    std::vector toStdVector() const { return coordinate_array; }
#endif //QHULL_NO_STL
#ifdef QHULL_USES_QT
    QList       toQList() const;
#endif //QHULL_USES_QT

#//!\name GetSet
    countT              count() const { return static_cast(size()); }
    coordT *            data() { return (isEmpty() ? NULL : &at(0)); }
    const coordT *      data() const { return (isEmpty() ? NULL : &at(0)); }
    bool                isEmpty() const { return coordinate_array.empty(); }
    bool                operator==(const Coordinates &other) const  { return coordinate_array==other.coordinate_array; }
    bool                operator!=(const Coordinates &other) const  { return coordinate_array!=other.coordinate_array; }
    size_t              size() const { return coordinate_array.size(); }

#//!\name Element access
    coordT &            at(countT idx) { return coordinate_array.at(idx); }
    const coordT &      at(countT idx) const { return coordinate_array.at(idx); }
    coordT &            back() { return coordinate_array.back(); }
    const coordT &      back() const { return coordinate_array.back(); }
    coordT &            first() { return front(); }
    const coordT &      first() const { return front(); }
    coordT &            front() { return coordinate_array.front(); }
    const coordT &      front() const { return coordinate_array.front(); }
    coordT &            last() { return back(); }
    const coordT &      last() const { return back(); }
    Coordinates         mid(countT idx, countT length= -1) const; //!<\todo countT -1 indicates
    coordT &            operator[](countT idx) { return coordinate_array.operator[](idx); }
    const coordT &      operator[](countT idx) const { return coordinate_array.operator[](idx); }
    coordT              value(countT idx, const coordT &defaultValue) const;

#//!\name Iterator
    iterator            begin() { return iterator(coordinate_array.begin()); }
    const_iterator      begin() const { return const_iterator(coordinate_array.begin()); }
    const_iterator      constBegin() const { return begin(); }
    const_iterator      constEnd() const { return end(); }
    iterator            end() { return iterator(coordinate_array.end()); }
    const_iterator      end() const { return const_iterator(coordinate_array.end()); }

#//!\name GetSet
    Coordinates         operator+(const Coordinates &other) const;

#//!\name Modify
    void                append(int pointDimension, coordT *c);
    void                append(const coordT &c) { push_back(c); }
    void                clear() { coordinate_array.clear(); }
    iterator            erase(iterator idx) { return iterator(coordinate_array.erase(idx.base())); }
    iterator            erase(iterator beginIterator, iterator endIterator) { return iterator(coordinate_array.erase(beginIterator.base(), endIterator.base())); }
    void                insert(countT before, const coordT &c) { insert(begin()+before, c); }
    iterator            insert(iterator before, const coordT &c) { return iterator(coordinate_array.insert(before.base(), c)); }
    void                move(countT from, countT to) { insert(to, takeAt(from)); }
    Coordinates &       operator+=(const Coordinates &other);
    Coordinates &       operator+=(const coordT &c) { append(c); return *this; }
    Coordinates &       operator<<(const Coordinates &other) { return *this += other; }
    Coordinates &       operator<<(const coordT &c) { return *this += c; }
    void                pop_back() { coordinate_array.pop_back(); }
    void                pop_front() { removeFirst(); }
    void                prepend(const coordT &c) { insert(begin(), c); }
    void                push_back(const coordT &c) { coordinate_array.push_back(c); }
    void                push_front(const coordT &c) { insert(begin(), c); }
                        //removeAll below
    void                removeAt(countT idx) { erase(begin()+idx); }
    void                removeFirst() { erase(begin()); }
    void                removeLast() { erase(--end()); }
    void                replace(countT idx, const coordT &c) { (*this)[idx]= c; }
    void                reserve(countT i) { coordinate_array.reserve(i); }
    void                swap(countT idx, countT other);
    coordT              takeAt(countT idx);
    coordT              takeFirst() { return takeAt(0); }
    coordT              takeLast();

#//!\name Search
    bool                contains(const coordT &t) const;
    countT              count(const coordT &t) const;
    countT              indexOf(const coordT &t, countT from= 0) const;
    countT              lastIndexOf(const coordT &t, countT from= -1) const;
    void                removeAll(const coordT &t);

#//!\name Coordinates::iterator -- from QhullPoints, forwarding to coordinate_array
    // before const_iterator for conversion with comparison operators
    // Reviewed corelib/tools/qlist.h and corelib/tools/qvector.h w/o QT_STRICT_ITERATORS
    class iterator {

    private:
        std::vector::iterator i;
        friend class const_iterator;

    public:
        typedef std::random_access_iterator_tag  iterator_category;
        typedef coordT      value_type;
        typedef value_type *pointer;
        typedef value_type &reference;
        typedef ptrdiff_t   difference_type;

                        iterator() : i() {}
                        iterator(const iterator &other) : i() { i= other.i; }
        explicit        iterator(const std::vector::iterator &vi) : i() { i= vi; }
        iterator &      operator=(const iterator &other) { i= other.i; return *this; }
        std::vector::iterator &base() { return i; }
        coordT &        operator*() const { return *i; }
        // No operator->() when the base type is double
        coordT &        operator[](countT idx) const { return i[idx]; }

        bool            operator==(const iterator &other) const { return i==other.i; }
        bool            operator!=(const iterator &other) const { return i!=other.i; }
        bool            operator<(const iterator &other) const { return i(const iterator &other) const { return i>other.i; }
        bool            operator>=(const iterator &other) const { return i>=other.i; }
              // reinterpret_cast to break circular dependency
        bool            operator==(const Coordinates::const_iterator &other) const { return *this==reinterpret_cast(other); }
        bool            operator!=(const Coordinates::const_iterator &other) const { return *this!=reinterpret_cast(other); }
        bool            operator<(const Coordinates::const_iterator &other) const { return *this(other); }
        bool            operator<=(const Coordinates::const_iterator &other) const { return *this<=reinterpret_cast(other); }
        bool            operator>(const Coordinates::const_iterator &other) const { return *this>reinterpret_cast(other); }
        bool            operator>=(const Coordinates::const_iterator &other) const { return *this>=reinterpret_cast(other); }

        iterator &      operator++() { ++i; return *this; }
        iterator        operator++(int) { return iterator(i++); }
        iterator &      operator--() { --i; return *this; }
        iterator        operator--(int) { return iterator(i--); }
        iterator &      operator+=(countT idx) { i += idx; return *this; }
        iterator &      operator-=(countT idx) { i -= idx; return *this; }
        iterator        operator+(countT idx) const { return iterator(i+idx); }
        iterator        operator-(countT idx) const { return iterator(i-idx); }
        difference_type operator-(iterator other) const { return i-other.i; }
    };//Coordinates::iterator

#//!\name Coordinates::const_iterator
    class const_iterator {

    private:
        std::vector::const_iterator i;

    public:
        typedef std::random_access_iterator_tag  iterator_category;
        typedef coordT            value_type;
        typedef const value_type *pointer;
        typedef const value_type &reference;
        typedef ptrdiff_t         difference_type;

                        const_iterator() : i() {}
                        const_iterator(const const_iterator &other) : i() { i= other.i; }
                        const_iterator(const iterator &o) : i(o.i) {}
        explicit        const_iterator(const std::vector::const_iterator &vi) : i() { i= vi; }
        const_iterator &operator=(const const_iterator &other) { i= other.i; return *this; }
        const coordT &  operator*() const { return *i; }
        // No operator->() when the base type is double
        const coordT &  operator[](countT idx) const { return i[idx]; }

        bool            operator==(const const_iterator &other) const { return i==other.i; }
        bool            operator!=(const const_iterator &other) const { return i!=other.i; }
        bool            operator<(const const_iterator &other) const { return i(const const_iterator &other) const { return i>other.i; }
        bool            operator>=(const const_iterator &other) const { return i>=other.i; }

        const_iterator & operator++() { ++i; return *this; }
        const_iterator  operator++(int) { return const_iterator(i++); }
        const_iterator & operator--() { --i; return *this; }
        const_iterator  operator--(int) { return const_iterator(i--); }
        const_iterator & operator+=(countT idx) { i += idx; return *this; }
        const_iterator & operator-=(countT idx) { i -= idx; return *this; }
        const_iterator  operator+(countT idx) const { return const_iterator(i+idx); }
        const_iterator  operator-(countT idx) const { return const_iterator(i-idx); }
        difference_type operator-(const_iterator other) const { return i-other.i; }
    };//Coordinates::const_iterator

};//Coordinates

}//namespace orgQhull

#//!\name Global

std::ostream &operator<<(std::ostream &os, const orgQhull::Coordinates &c);

#endif // QHCOORDINATES_H
qhull-2020.2/src/libqhullcpp/functionObjects.h0000644060175106010010000000300313661631133017603 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/functionObjects.h#2 $$Change: 2953 $
** $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
**
****************************************************************************/

#ifndef QHFUNCTIONOBJECTS_H
#define QHFUNCTIONOBJECTS_H

#include 
#include 

namespace orgQhull {

#//!\name Defined here

    //! Sum of absolute values of the elements in a container
    class AbsoluteSumOf;
    //! Sum of the elements in a container
    class SumOf;
    //! Sum of squares of the elements in a container
    class SumSquaresOf;

#//!\name Class

//! Absolute sum of the elements in a container
class AbsoluteSumOf
{
private:
    double sum;
public:
    inline AbsoluteSumOf() : sum(0.0) {}
    inline void operator()(double v) { sum += fabs(v); }
    inline operator double() { return sum; }
};//AbsoluteSumOf

//! Sum of the elements in a container
class SumOf
{
private:
    double sum;
public:
    inline SumOf() : sum(0.0) {}
    inline void operator()(double v) { sum += v; }
    inline operator double() { return sum; }
};//SumOf


//! Sum of squares of the elements in a container
class SumSquaresOf
{
private:
    double sum;
public:
    inline SumSquaresOf() : sum(0.0) {}
    inline void operator()(double v) { sum += v*v; }
    inline operator double() { return sum; }
};//SumSquaresOf


}//orgQhull


#endif //QHFUNCTIONOBJECTS_H

qhull-2020.2/src/libqhullcpp/libqhullcpp.pro0000644060175106010010000000477313715345414017357 0ustar  bbarber# -------------------------------------------------
# libqhullcpp.pro -- Qt project for Qhull cpp shared library
#
# It uses reentrant Qhull
# -------------------------------------------------

include(../qhull-warn.pri)

DESTDIR = ../../lib
TEMPLATE = lib
# Do not create libqhullcpp as a shared library.  Qhull C++ classes may change layout and size. 
CONFIG += staticlib warn_on
CONFIG -= qt rtti
build_pass:CONFIG(debug, debug|release):{
   TARGET = qhullcpp_d
   OBJECTS_DIR = Debug
}else:build_pass:CONFIG(release, debug|release):{
   TARGET = qhullcpp
   OBJECTS_DIR = Release
}
MOC_DIR = moc

INCLUDEPATH += ../../src
INCLUDEPATH += $$PWD # for MOC_DIR

CONFIG += qhull_warn_shadow qhull_warn_conversion

SOURCES += ../libqhullcpp/Coordinates.cpp
SOURCES += ../libqhullcpp/PointCoordinates.cpp
SOURCES += ../libqhullcpp/Qhull.cpp
SOURCES += ../libqhullcpp/QhullFacet.cpp
SOURCES += ../libqhullcpp/QhullFacetList.cpp
SOURCES += ../libqhullcpp/QhullFacetSet.cpp
SOURCES += ../libqhullcpp/QhullHyperplane.cpp
SOURCES += ../libqhullcpp/QhullPoint.cpp
SOURCES += ../libqhullcpp/QhullPoints.cpp
SOURCES += ../libqhullcpp/QhullPointSet.cpp
SOURCES += ../libqhullcpp/QhullQh.cpp
SOURCES += ../libqhullcpp/QhullRidge.cpp
SOURCES += ../libqhullcpp/QhullSet.cpp
SOURCES += ../libqhullcpp/QhullStat.cpp
SOURCES += ../libqhullcpp/QhullUser.cpp
SOURCES += ../libqhullcpp/QhullVertex.cpp
SOURCES += ../libqhullcpp/QhullVertexSet.cpp
SOURCES += ../libqhullcpp/RboxPoints.cpp
SOURCES += ../libqhullcpp/RoadError.cpp
SOURCES += ../libqhullcpp/RoadLogEvent.cpp

HEADERS += ../libqhullcpp/Coordinates.h
HEADERS += ../libqhullcpp/functionObjects.h
HEADERS += ../libqhullcpp/PointCoordinates.h
HEADERS += ../libqhullcpp/Qhull.h
HEADERS += ../libqhullcpp/QhullError.h
HEADERS += ../libqhullcpp/QhullFacet.h
HEADERS += ../libqhullcpp/QhullFacetList.h
HEADERS += ../libqhullcpp/QhullFacetSet.h
HEADERS += ../libqhullcpp/QhullHyperplane.h
HEADERS += ../libqhullcpp/QhullIterator.h
HEADERS += ../libqhullcpp/QhullLinkedList.h
HEADERS += ../libqhullcpp/QhullPoint.h
HEADERS += ../libqhullcpp/QhullPoints.h
HEADERS += ../libqhullcpp/QhullPointSet.h
HEADERS += ../libqhullcpp/QhullQh.h
HEADERS += ../libqhullcpp/QhullRidge.h
HEADERS += ../libqhullcpp/QhullSet.h
HEADERS += ../libqhullcpp/QhullSets.h
HEADERS += ../libqhullcpp/QhullStat.h
HEADERS += ../libqhullcpp/QhullUser.h
HEADERS += ../libqhullcpp/QhullVertex.h
HEADERS += ../libqhullcpp/QhullVertexSet.h
HEADERS += ../libqhullcpp/RboxPoints.h
HEADERS += ../libqhullcpp/RoadError.h
HEADERS += ../libqhullcpp/RoadLogEvent.h
qhull-2020.2/src/libqhullcpp/PointCoordinates.cpp0000644060175106010010000002264113664527756020316 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2009-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/PointCoordinates.cpp#3 $$Change: 2961 $
** $DateTime: 2020/06/01 22:17:03 $$Author: bbarber $
**
****************************************************************************/

#include "libqhullcpp/PointCoordinates.h"

#include "libqhullcpp/QhullError.h"
#include "libqhullcpp/QhullPoint.h"

#include 
#include 

using std::istream;
using std::string;
using std::ws;

#ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
#pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
#endif

namespace orgQhull {

#//! PointCoordinates -- vector of PointCoordinates

#//!\name Constructors

PointCoordinates::
PointCoordinates()
: QhullPoints()
, point_coordinates()
, describe_points()
{
}

PointCoordinates::
PointCoordinates(const std::string &aComment)
: QhullPoints()
, point_coordinates()
, describe_points(aComment)
{
}

PointCoordinates::
PointCoordinates(int pointDimension, const std::string &aComment)
: QhullPoints()
, point_coordinates()
, describe_points(aComment)
{
    setDimension(pointDimension);
}

//! Qhull and QhullQh constructors are the same
PointCoordinates::
PointCoordinates(const Qhull &q)
: QhullPoints(q)
, point_coordinates()
, describe_points()
{
}

PointCoordinates::
PointCoordinates(const Qhull &q, const std::string &aComment)
: QhullPoints(q)
, point_coordinates()
, describe_points(aComment)
{
}

PointCoordinates::
PointCoordinates(const Qhull &q, int pointDimension, const std::string &aComment)
: QhullPoints(q)
, point_coordinates()
, describe_points(aComment)
{
    setDimension(pointDimension);
}

PointCoordinates::
PointCoordinates(const Qhull &q, int pointDimension, const std::string &aComment, countT coordinatesCount, const coordT *c)
: QhullPoints(q)
, point_coordinates()
, describe_points(aComment)
{
    setDimension(pointDimension);
    append(coordinatesCount, c);
}

PointCoordinates::
PointCoordinates(QhullQh *qqh)
: QhullPoints(qqh)
, point_coordinates()
, describe_points()
{
}

PointCoordinates::
PointCoordinates(QhullQh *qqh, const std::string &aComment)
: QhullPoints(qqh)
, point_coordinates()
, describe_points(aComment)
{
}

PointCoordinates::
PointCoordinates(QhullQh *qqh, int pointDimension, const std::string &aComment)
: QhullPoints(qqh)
, point_coordinates()
, describe_points(aComment)
{
    setDimension(pointDimension);
}

PointCoordinates::
PointCoordinates(QhullQh *qqh, int pointDimension, const std::string &aComment, countT coordinatesCount, const coordT *c)
: QhullPoints(qqh)
, point_coordinates()
, describe_points(aComment)
{
    setDimension(pointDimension);
    append(coordinatesCount, c);
}

PointCoordinates::
PointCoordinates(const PointCoordinates &other)
: QhullPoints(other)
, point_coordinates(other.point_coordinates)
, describe_points(other.describe_points)
{
    makeValid();  // Update point_first and point_end
}

PointCoordinates & PointCoordinates::
operator=(const PointCoordinates &other)
{
    QhullPoints::operator=(other);
    point_coordinates= other.point_coordinates;
    describe_points= other.describe_points;
    makeValid(); // Update point_first and point_end
    return *this;
}//operator=

PointCoordinates::
~PointCoordinates()
{ }

#//!\name GetSet

void PointCoordinates::
checkValid() const
{
    if(getCoordinates().data()!=data()
    || getCoordinates().count()!=coordinateCount()){
        throw QhullError(10060, "Qhull error: first point (%x) is not PointCoordinates.data() or count (%d) is not PointCoordinates.count (%d)", coordinateCount(), getCoordinates().count(), 0.0, data());
    }
}//checkValid

void PointCoordinates::
setDimension(int i)
{
    if(i<0){
        throw QhullError(10062, "Qhull error: can not set PointCoordinates dimension to %d", i);
    }
    int currentDimension= dimension(); // QhullPoints
    if(currentDimension!=0 && i!=currentDimension){
        throw QhullError(10063, "Qhull error: can not change PointCoordinates dimension (from %d to %d)", currentDimension, i);
    }
    QhullPoints::setDimension(i);
}//setDimension

#//!\name Foreach

Coordinates::ConstIterator PointCoordinates::
beginCoordinates(countT pointIndex) const
{
    return point_coordinates.begin()+indexOffset(pointIndex);
}

Coordinates::Iterator PointCoordinates::
beginCoordinates(countT pointIndex)
{
    return point_coordinates.begin()+indexOffset(pointIndex);
}

#//!\name Methods

void PointCoordinates::
append(countT coordinatesCount, const coordT *c)
{
    if(coordinatesCount<=0){
        return;
    }
    if(includesCoordinates(c)){
        throw QhullError(10065, "Qhull error: can not append a subset of PointCoordinates to itself.  The coordinates for point %d may move.", indexOf(c, QhullError::NOthrow));
    }
    reserveCoordinates(coordinatesCount);
    std::copy(c, c+coordinatesCount, std::back_inserter(point_coordinates));
    makeValid();
}//append coordT

void PointCoordinates::
append(const PointCoordinates &other)
{
    setDimension(other.dimension());
    append(other.coordinateCount(), other.data());
}//append PointCoordinates

void PointCoordinates::
append(const QhullPoint &p)
{
    setDimension(p.dimension());
    append(p.dimension(), p.coordinates());
}//append QhullPoint

void PointCoordinates::
appendComment(const std::string &s){
    if(char c= s[0] && describe_points.empty()){
        if(c=='-' || isdigit(c)){
            throw QhullError(10028, "Qhull argument error: comments can not start with a number or minus, %s", 0, 0, 0.0, s.c_str());
        }
    }
    describe_points += s;
}//appendComment

//! Read PointCoordinates from istream.  First two numbers are dimension and count.  A non-digit starts a rboxCommand.
//! Overwrites describe_points.  See qh_readpoints [io.c]
void PointCoordinates::
appendPoints(istream &in)
{
    int inDimension;
    countT inCount;
    in >> ws >> inDimension >> ws;
    if(!in.good()){
        in.clear();
        string remainder;
        getline(in, remainder);
        throw QhullError(10005, "Qhull error: input did not start with dimension or count -- %s", 0, 0, 0, remainder.c_str());
    }
    char c= static_cast(in.peek());
    if(c!='-' && !isdigit(c)){         // Comments start with a non-digit
        getline(in, describe_points);
        in >> ws;
    }
    in >> inCount >> ws;
    if(!in.good()){
        in.clear();
        string remainder;
        getline(in, remainder);
        throw QhullError(10009, "Qhull error: input did not start with dimension and count -- %d %s", inDimension, 0, 0, remainder.c_str());
    }
    c= static_cast(in.peek());
    if(c!='-' && !isdigit(c)){         // Comments start with a non-digit
        getline(in, describe_points);
        in >> ws;
    }
    if(inCount> p;
        if(in.fail()){
            in.clear();
            string remainder;
            getline(in, remainder);
            throw QhullError(10008, "Qhull error: failed to read coordinate %d  of point %d\n   '%s'", coordinatesCount % inDimension, coordinatesCount/inDimension, 0, remainder.c_str());
        }else{
            point_coordinates.push_back(p);
            coordinatesCount++;
        }
        in >> ws;
    }
    if(coordinatesCount != inCount*inDimension){
        if(coordinatesCount%inDimension==0){
            throw QhullError(10006, "Qhull error: expected %d %d-d PointCoordinates but read %i PointCoordinates", int(inCount), inDimension, 0.0, int(coordinatesCount/inDimension));
        }else{
            throw QhullError(10012, "Qhull error: expected %d %d-d PointCoordinates but read %i PointCoordinates plus %f extra coordinates", inCount, inDimension, float(coordinatesCount%inDimension), coordinatesCount/inDimension);
        }
    }
    makeValid();
}//appendPoints istream

PointCoordinates PointCoordinates::
operator+(const PointCoordinates &other) const
{
    PointCoordinates pc= *this;
    pc << other;
    return pc;
}//operator+

void PointCoordinates::
reserveCoordinates(countT newCoordinates)
{
    // vector::reserve is not const
    point_coordinates.reserve(static_cast(point_coordinates.size()+newCoordinates)); // WARN64
    makeValid();
}//reserveCoordinates

#//!\name Helpers

countT PointCoordinates::
indexOffset(countT i) const {
    countT n= i*dimension();
    countT coordinatesCount= point_coordinates.count();
    if(i<0 || n>coordinatesCount){
        throw QhullError(10061, "Qhull error: point_coordinates is too short (%d) for point %d", coordinatesCount, i);
    }
    return n;
}

}//namespace orgQhull

#//!\name Global functions

using std::endl;
using std::ostream;

using orgQhull::Coordinates;
using orgQhull::PointCoordinates;

ostream&
operator<<(ostream &os, const PointCoordinates &p)
{
    p.checkValid();
    countT count= p.count();
    int dimension= p.dimension();
    string comment= p.comment();
    if(comment.empty()){
        os << dimension << endl;
    }else{
        os << dimension << " " << comment << endl;
    }
    os << count << endl;
    Coordinates::ConstIterator c= p.beginCoordinates();
    for(countT i=0; i
#include 

#ifndef QHULL_NO_STL
#include 
#endif

namespace orgQhull {

#//!\name Defined here
    //! QhullPoints with Coordinates and description
    //! Inherited by RboxPoints
    class PointCoordinates;

    //! Java-style iterators are not implemented for PointCoordinates.  Expensive copy constructor and copy assignment for Coordinates (std::vector).
    //! A pointer to PointCoordinates is vulnerable to mysterious overwrites (e.g., deleting a returned value and reusing its memory)
    //! 'foreach' likewise makes a copy of point_coordinates and should be avoided

class PointCoordinates : public QhullPoints {

private:
#//!\name Fields
    Coordinates         point_coordinates;      //! std::vector of point coordinates
                                                //! may have extraCoordinates()
    std::string         describe_points;        //! Comment describing PointCoordinates

public:
#//!\name Construct
    //! QhullPoint, PointCoordinates, and QhullPoints have similar constructors
    //! If Qhull/QhullQh is not initialized, then dimension()==0                        PointCoordinates();
                        PointCoordinates();
    explicit            PointCoordinates(const std::string &aComment);
                        PointCoordinates(int pointDimension, const std::string &aComment);
                        //! Qhull/QhullQh used for dimension() and QhullPoint equality
    explicit            PointCoordinates(const Qhull &q);
                        PointCoordinates(const Qhull &q, const std::string &aComment);
                        PointCoordinates(const Qhull &q, int pointDimension, const std::string &aComment);
                        PointCoordinates(const Qhull &q, int pointDimension, const std::string &aComment, countT coordinatesCount, const coordT *c); // may be invalid
                        //! Use append() and appendPoints() for Coordinates and vector
    explicit            PointCoordinates(QhullQh *qqh);
                        PointCoordinates(QhullQh *qqh, const std::string &aComment);
                        PointCoordinates(QhullQh *qqh, int pointDimension, const std::string &aComment);
                        PointCoordinates(QhullQh *qqh, int pointDimension, const std::string &aComment, countT coordinatesCount, const coordT *c); // may be invalid
                        //! Use append() and appendPoints() for Coordinates and vector
                        PointCoordinates(const PointCoordinates &other);
    PointCoordinates &  operator=(const PointCoordinates &other);
                        ~PointCoordinates();

#//!\name Convert
    //! QhullPoints coordinates, constData, data, count, size
#ifndef QHULL_NO_STL
    void                append(const std::vector &otherCoordinates) { if(!otherCoordinates.empty()){ append(static_cast(otherCoordinates.size()), &otherCoordinates[0]); } }
    std::vector toStdVector() const { return point_coordinates.toStdVector(); }
#endif //QHULL_NO_STL
#ifdef QHULL_USES_QT
    void                append(const QList &pointCoordinates) { if(!pointCoordinates.isEmpty()){ append(pointCoordinates.count(), &pointCoordinates[0]); } }
    QList       toQList() const { return point_coordinates.toQList(); }
#endif //QHULL_USES_QT

#//!\name GetSet
    //! See QhullPoints for coordinates, coordinateCount, dimension, empty, isEmpty, ==, !=
    void                checkValid() const;
    std::string         comment() const { return describe_points; }
    void                makeValid() { defineAs(point_coordinates.count(), point_coordinates.data()); }
    const Coordinates & getCoordinates() const { return point_coordinates; }
    void                setComment(const std::string &s) { describe_points= s; }
    void                setDimension(int i);

private:
    //! disable QhullPoints.defineAs()
    void                defineAs(countT coordinatesCount, coordT *c) { QhullPoints::defineAs(coordinatesCount, c); }
public:

#//!\name ElementAccess
    //! See QhullPoints for at, back, first, front, last, mid, [], value

#//!\name Foreach
    //! See QhullPoints for begin, constBegin, end
    Coordinates::ConstIterator  beginCoordinates() const { return point_coordinates.begin(); }
    Coordinates::Iterator       beginCoordinates() { return point_coordinates.begin(); }
    Coordinates::ConstIterator  beginCoordinates(countT pointIndex) const;
    Coordinates::Iterator       beginCoordinates(countT pointIndex);
    Coordinates::ConstIterator  endCoordinates() const { return point_coordinates.end(); }
    Coordinates::Iterator       endCoordinates() { return point_coordinates.end(); }

#//!\name Search
    //! See QhullPoints for contains, count, indexOf, lastIndexOf

#//!\name GetSet
    PointCoordinates    operator+(const PointCoordinates &other) const;

#//!\name Modify
    // QH11001 FIX: Add clear() and other modify operators from Coordinates.h.  Include QhullPoint::operator=()
    void                append(countT coordinatesCount, const coordT *c);  //! Dimension previously defined
    void                append(const coordT &c) { append(1, &c); } //! Dimension previously defined
    void                append(const QhullPoint &p);
    //! See convert for std::vector and QList
    void                append(const Coordinates &c) { append(c.count(), c.data()); }
    void                append(const PointCoordinates &other);
    void                appendComment(const std::string &s);
    void                appendPoints(std::istream &in);
    PointCoordinates &  operator+=(const PointCoordinates &other) { append(other); return *this; }
    PointCoordinates &  operator+=(const coordT &c) { append(c); return *this; }
    PointCoordinates &  operator+=(const QhullPoint &p) { append(p); return *this; }
    PointCoordinates &  operator<<(const PointCoordinates &other) { return *this += other; }
    PointCoordinates &  operator<<(const coordT &c) { return *this += c; }
    PointCoordinates &  operator<<(const QhullPoint &p) { return *this += p; }
    // reserve() is non-const
    void                reserveCoordinates(countT newCoordinates);

#//!\name Helpers
private:
    int                 indexOffset(int i) const;

};//PointCoordinates

}//namespace orgQhull

#//!\name Global

std::ostream &          operator<<(std::ostream &os, const orgQhull::PointCoordinates &p);

#endif // QHPOINTCOORDINATES_H
qhull-2020.2/src/libqhullcpp/Qhull.cpp0000644060175106010010000003130613710644344016076 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/Qhull.cpp#12 $$Change: 3009 $
** $DateTime: 2020/07/30 19:25:22 $$Author: bbarber $
**
****************************************************************************/

#//! Qhull -- invoke qhull from C++
#//! Compile libqhull_r and Qhull together due to use of setjmp/longjmp()

#include "libqhullcpp/Qhull.h"

#include "libqhullcpp/QhullError.h"
#include "libqhullcpp/RboxPoints.h"
#include "libqhullcpp/QhullQh.h"
#include "libqhullcpp/QhullFacet.h"
#include "libqhullcpp/QhullFacetList.h"

#include 

using std::cerr;
using std::string;
using std::vector;
using std::ostream;

#ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
#pragma warning( disable : 4611)  // interaction between '_setjmp' and C++ object destruction is non-portable
#pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
#endif

namespace orgQhull{

#//!\name Global variables

const char s_unsupported_options[]=" Fd TI ";
const char s_not_output_options[]= " Fd TI A C d E H P Qa Qb QbB Qbb Qc Qf Qg Qi Qm QJ Qr QR Qs Qt Qv Qx Qz Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 Q10 Q11 Q15 R TA Tc TC TM TP TR Tv TV TW U v V W ";

#//!\name Constructor, destructor, etc.
Qhull::
Qhull()
: qh_qh(0)
, origin_point()
, run_called(false)
, feasible_point()
{
    allocateQhullQh();
}//Qhull

//! Invokes Qhull on rboxPoints
//! Same as runQhull()
//! For rbox commands, see http://www.qhull.org/html/rbox.htm or html/rbox.htm
//! For qhull commands, see http://www.qhull.org/html/qhull.htm or html/qhull.htm
Qhull::
Qhull(const RboxPoints &rboxPoints, const char *qhullCommand2)
: qh_qh(0)
, origin_point()
, run_called(false)
, feasible_point()
{
    allocateQhullQh();
    runQhull(rboxPoints, qhullCommand2);
}//Qhull rbox

//! Invokes Qhull on a set of input points
//! Same as runQhull()
//! For qhull commands, see http://www.qhull.org/html/qhull.htm or html/qhull.htm
Qhull::
Qhull(const char *inputComment2, int pointDimension, int pointCount, const realT *pointCoordinates, const char *qhullCommand2)
: qh_qh(0)
, origin_point()
, run_called(false)
, feasible_point()
{
    allocateQhullQh();
    runQhull(inputComment2, pointDimension, pointCount, pointCoordinates, qhullCommand2);
}//Qhull points

void Qhull::
allocateQhullQh()
{
  QHULL_LIB_CHECK /* Check for compatible library */

    qh_qh= new QhullQh;
    void *p= qh_qh;
    void *p2= static_cast(qh_qh);
    char *s= static_cast(p);
    char *s2= static_cast(p2);
    if(s!=s2){
        throw QhullError(10074, "Qhull error: QhullQh at a different address than base type QhT (%d bytes).  Please report compiler to qhull.org", int(s2-s));
    }
}//allocateQhullQh

Qhull::
~Qhull() throw()
{
    // Except for cerr, does not throw errors
    if(qh_qh->hasQhullMessage()){
        cerr<< "\nQhull messages at ~Qhull()\n"; // QH11005 FIX: where should error and log messages go on ~Qhull?
        cerr<< qh_qh->qhullMessage();
        qh_qh->clearQhullMessage();
    }
    delete qh_qh;
    qh_qh= 0;
}//~Qhull

#//!\name GetSet

void Qhull::
checkIfQhullInitialized()
{
    if(!initialized()){ // qh_initqhull_buffers() not called
        throw QhullError(10023, "Qhull error: checkIfQhullInitialized failed.  Call runQhull() first.");
    }
}//checkIfQhullInitialized

//! Return feasiblePoint for halfspace intersection
//! If called before runQhull(), then it returns the value from setFeasiblePoint.  qh.feasible_string overrides this value if it is defined.
Coordinates Qhull::
feasiblePoint() const
{
    Coordinates result;
    if(qh_qh->feasible_point){
        result.append(qh_qh->hull_dim, qh_qh->feasible_point);
    }else{
        result= feasible_point;
    }
    return result;
}//feasiblePoint

//! Return origin point for qh.input_dim
QhullPoint Qhull::
inputOrigin()
{
    QhullPoint result= origin();
    result.setDimension(qh_qh->input_dim);
    return result;
}//inputOrigin

#//!\name GetValue

double Qhull::
area(){
    checkIfQhullInitialized();
    if(!qh_qh->hasAreaVolume){
        QH_TRY_(qh_qh){ // no object creation -- destructors skipped on longjmp()
            qh_getarea(qh_qh, qh_qh->facet_list);
        }
        qh_qh->NOerrexit= true;
        qh_qh->maybeThrowQhullMessage(QH_TRY_status);
    }
    return qh_qh->totarea;
}//area

double Qhull::
volume(){
    checkIfQhullInitialized();
    if(!qh_qh->hasAreaVolume){
        QH_TRY_(qh_qh){ // no object creation -- destructors skipped on longjmp()
            qh_getarea(qh_qh, qh_qh->facet_list);
        }
        qh_qh->NOerrexit= true;
        qh_qh->maybeThrowQhullMessage(QH_TRY_status);
    }
    return qh_qh->totvol;
}//volume

#//!\name Foreach

//! Define QhullVertex::neighborFacets().
//! Automatically called if merging facets or computing the Voronoi diagram.
//! Noop if called multiple times.
void Qhull::
defineVertexNeighborFacets(){
    checkIfQhullInitialized();
    if(!qh_qh->hasAreaVolume){
        QH_TRY_(qh_qh){ // no object creation -- destructors skipped on longjmp()
            qh_vertexneighbors(qh_qh);
        }
        qh_qh->NOerrexit= true;
        qh_qh->maybeThrowQhullMessage(QH_TRY_status);
    }
}//defineVertexNeighborFacets

QhullFacetList Qhull::
facetList() const
{
    return QhullFacetList(beginFacet(), endFacet());
}//facetList

QhullPoints Qhull::
points() const
{
    return QhullPoints(qh_qh, qh_qh->hull_dim, qh_qh->num_points*qh_qh->hull_dim, qh_qh->first_point);
}//points

QhullPointSet Qhull::
otherPoints() const
{
    return QhullPointSet(qh_qh, qh_qh->other_points);
}//otherPoints

//! Return vertices of the convex hull in qh.vertex_list order
//! Vertices are not ordered by adjacency (see QhullFacet::nextFacet2d)
QhullVertexList Qhull::
vertexList() const
{
    return QhullVertexList(beginVertex(), endVertex());
}//vertexList

#//!\name Methods

void Qhull::
outputQhull()
{
    checkIfQhullInitialized();
    QH_TRY_(qh_qh){ // no object creation -- destructors skipped on longjmp()
        qh_produce_output2(qh_qh);
    }
    qh_qh->NOerrexit= true;
    qh_qh->maybeThrowQhullMessage(QH_TRY_status);
}//outputQhull

void Qhull::
outputQhull(const char *outputflags)
{
    checkIfQhullInitialized();
    string cmd(" "); // qh_checkflags skips first word
    cmd += outputflags;
    char *command= const_cast(cmd.c_str());
    QH_TRY_(qh_qh){ // no object creation -- destructors skipped on longjmp()
        qh_clear_outputflags(qh_qh);
        char *s= qh_qh->qhull_command + strlen(qh_qh->qhull_command) + 1; //space
        strncat(qh_qh->qhull_command, command, sizeof(qh_qh->qhull_command)-strlen(qh_qh->qhull_command)-1);
        qh_checkflags(qh_qh, command, const_cast(s_not_output_options));
        qh_initflags(qh_qh, s);
        qh_initqhull_outputflags(qh_qh);
        if(qh_qh->KEEPminArea < REALmax/2 || qh_qh->KEEParea || qh_qh->KEEPmerge || qh_qh->GOODvertex
                  || qh_qh->GOODpoint || qh_qh->GOODthreshold || qh_qh->SPLITthresholds){
            facetT *facet;
            qh_qh->ONLYgood= False;
            FORALLfacet_(qh_qh->facet_list){
                facet->good= True;
            }
            qh_prepare_output(qh_qh);
        }
        qh_produce_output2(qh_qh);
        if(qh_qh->VERIFYoutput && !qh_qh->FORCEoutput && !qh_qh->STOPadd && !qh_qh->STOPcone && !qh_qh->STOPpoint){
            qh_check_points(qh_qh);
        }
    }
    qh_qh->NOerrexit= true;
    qh_qh->maybeThrowQhullMessage(QH_TRY_status);
}//outputQhull

//! Prepare Qhull for Voronoi output
//! Calls qh_markvoronoi ('v o Fi Fo') and qh_order_vertexneighbors ('v Fi Fo')
void Qhull::
prepareVoronoi(bool *isLower, int *voronoiVertexCount)
{
  QH_TRY_(qh_qh){ // no object creation -- destructors skipped on longjmp()
    boolT isLowerHull;
    vertexT *vertex;

    setT *vertices= qh_markvoronoi(qh_qh, facetList().first().getFacetT(), NULL, !qh_ALL, &isLowerHull, voronoiVertexCount);
    *isLower= isLowerHull;

    qhT *qh= qh_qh;
    FORALLvertices{
      qh_order_vertexneighbors(qh, vertex);
    }
    qh_settempfree(qh, &vertices);
  }
  qh_qh->NOerrexit= true;
  qh_qh->maybeThrowQhullMessage(QH_TRY_status);
}//prepareVoronoi

//! For qhull commands, see http://www.qhull.org/html/qhull.htm or html/qhull.htm
void Qhull::
runQhull(const RboxPoints &rboxPoints, const char *qhullCommand2)
{
    runQhull(rboxPoints.comment().c_str(), rboxPoints.dimension(), rboxPoints.count(), &*rboxPoints.coordinates(), qhullCommand2);
}//runQhull, RboxPoints

//! pointCoordinates is a array of points, input sites ('d' or 'v'), or halfspaces with offset last ('H')
//! Derived from qh_new_qhull [user.c]
//! For rbox commands, see http://www.qhull.org/html/rbox.htm or html/rbox.htm
//! For qhull commands, see http://www.qhull.org/html/qhull.htm or html/qhull.htm
void Qhull::
runQhull(const char *inputComment2, int pointDimension, int pointCount, const realT *pointCoordinates, const char *qhullCommand2)
{
  /* gcc may issue a "might be clobbered" warning for pointDimension and pointCoordinates [-Wclobbered].
     These parameters are not referenced after a longjmp() and hence not clobbered.
     See http://stackoverflow.com/questions/7721854/what-sense-do-these-clobbered-variable-warnings-make */
    if(run_called){
        throw QhullError(10027, "Qhull error: runQhull called twice.  Only one call allowed.");
    }
    run_called= true;
    string s("qhull ");
    s += qhullCommand2;
    char *command= const_cast(s.c_str());
    /************* Expansion of QH_TRY_ for debugging
    int QH_TRY_status;
    if(qh_qh->NOerrexit){
        qh_qh->NOerrexit= False;
        QH_TRY_status= setjmp(qh_qh->errexit);
    }else{
        QH_TRY_status= QH_TRY_ERROR;
    }
    if(!QH_TRY_status){
    *************/
    QH_TRY_(qh_qh){ // no object creation -- destructors are skipped on longjmp()
        qh_checkflags(qh_qh, command, const_cast(s_unsupported_options));
        qh_initflags(qh_qh, command);
        *qh_qh->rbox_command= '\0';
        strncat( qh_qh->rbox_command, inputComment2, sizeof(qh_qh->rbox_command)-1);
        if(qh_qh->DELAUNAY){
            qh_qh->PROJECTdelaunay= True;   // qh_init_B() calls qh_projectinput()
        }
        pointT *newPoints= const_cast(pointCoordinates);
        int newDimension= pointDimension;
        int newIsMalloc= False;
        if(qh_qh->HALFspace){
            --newDimension;
            initializeFeasiblePoint(newDimension);
            newPoints= qh_sethalfspace_all(qh_qh, pointDimension, pointCount, newPoints, qh_qh->feasible_point);
            newIsMalloc= True;
        }
        qh_init_B(qh_qh, newPoints, pointCount, newDimension, newIsMalloc);
        qh_qhull(qh_qh);
        qh_check_output(qh_qh);
        qh_prepare_output(qh_qh);
        if(qh_qh->VERIFYoutput && !qh_qh->FORCEoutput && !qh_qh->STOPadd && !qh_qh->STOPcone && !qh_qh->STOPpoint){
            qh_check_points(qh_qh);
        }
    }
    qh_qh->NOerrexit= true;
    for(int k= qh_qh->hull_dim; k--; ){  // Do not move into QH_TRY block.  It may throw an error
        origin_point << 0.0;
    }
    qh_qh->maybeThrowQhullMessage(QH_TRY_status);
}//runQhull

#//!\name Helpers -- be careful of allocating C++ objects due to setjmp/longjmp() error handling by qh_... routines

//! initialize qh.feasible_point for half-space intersection
//! Sets from qh.feasible_string if available, otherwise from Qhull::feasible_point
//! called only once from runQhull(), otherwise it leaks memory (the same as qh_setFeasible)
void Qhull::
initializeFeasiblePoint(int hulldim)
{
    if(qh_qh->feasible_string){
        qh_setfeasible(qh_qh, hulldim);
    }else{
        if(feasible_point.isEmpty()){
            qh_fprintf(qh_qh, qh_qh->ferr, 6209, "qhull error: missing feasible point for halfspace intersection.  Use option 'Hn,n' or Qhull::setFeasiblePoint before runQhull()\n");
            qh_errexit(qh_qh, qh_ERRmem, NULL, NULL);
        }
        if(feasible_point.size()!=static_cast(hulldim)){
            qh_fprintf(qh_qh, qh_qh->ferr, 6210, "qhull error: dimension of feasiblePoint should be %d.  It is %u\n", hulldim, feasible_point.size());
            qh_errexit(qh_qh, qh_ERRmem, NULL, NULL);
        }
        qh_qh->feasible_point= static_cast(qh_malloc(static_cast(hulldim) * sizeof(coordT)));
        if(!qh_qh->feasible_point){
            qh_fprintf(qh_qh, qh_qh->ferr, 6042, "qhull error (Qhull.cpp): insufficient memory for feasible point\n");
            qh_errexit(qh_qh, qh_ERRmem, NULL, NULL);
        }
        coordT *t= qh_qh->feasible_point;
        // No qh_... routines after here -- longjmp() ignores destructor
        for(Coordinates::ConstIterator p=feasible_point.begin(); p.  It could be rewritten for another vector class such as QList
   #define QHULL_USES_QT
      Supply conversions to QT
      qhulltest requires QT.  It is defined in RoadTest.h

  #define QHULL_ASSERT
      Defined by QhullError.h
      It invokes assert()
*/

#//!\name Used here
    class QhullFacetList;
    class QhullPoints;
    class QhullQh;
    class RboxPoints;

#//!\name Defined here
    class Qhull;

//! Interface to Qhull from C++
class Qhull {

private:
#//!\name Members and friends
    QhullQh *           qh_qh;          //! qhT for this instance
    Coordinates         origin_point;   //! origin for qh_qh->hull_dim.  Set by runQhull()
    bool                run_called;     //! True at start of runQhull.  Errors if call again.
    Coordinates         feasible_point;  //! feasible point for half-space intersection (alternative to qh.feasible_string for qh.feasible_point)

public:
#//!\name Constructors
                        Qhull();      //!< call runQhull() next
                        Qhull(const RboxPoints &rboxPoints, const char *qhullCommand2);
                        Qhull(const char *inputComment2, int pointDimension, int pointCount, const realT *pointCoordinates, const char *qhullCommand2);
                        ~Qhull() throw();
private:                //! Disable copy constructor and assignment.  Qhull owns QhullQh.
                        Qhull(const Qhull &);
    Qhull &             operator=(const Qhull &);

private:
    void                allocateQhullQh();

public:

#//!\name GetSet
    void                checkIfQhullInitialized();
    int                 dimension() const { return qh_qh->input_dim; } //!< Dimension of input and result
    void                disableOutputStream() { qh_qh->disableOutputStream(); }
    void                enableOutputStream() { qh_qh->enableOutputStream(); }
    countT              facetCount() const { return qh_qh->num_facets; }
    Coordinates         feasiblePoint() const; 
    int                 hullDimension() const { return qh_qh->hull_dim; } //!< Dimension of the computed hull
    bool                hasOutputStream() const { return qh_qh->hasOutputStream(); }
    bool                initialized() const { return (qh_qh->hull_dim>0); }
    const char *        inputComment() const { return qh_qh->rbox_command; }
    QhullPoint          inputOrigin();
    bool                isDelaunay() const { return qh_qh->DELAUNAY; }
                        //! non-const due to QhullPoint
    QhullPoint          origin() { QHULL_ASSERT(initialized()); return QhullPoint(qh_qh, origin_point.data()); }
    QhullQh *           qh() const { return qh_qh; }
    const char *        qhullCommand() const { return qh_qh->qhull_command; }
    const char *        rboxCommand() const { return qh_qh->rbox_command; }
    int                 rotateRandom() const { return qh_qh->ROTATErandom; } //!< Return QRn for repeating QR0 runs
    void                setFeasiblePoint(const Coordinates &c) { feasible_point= c; } //!< Sets qh.feasible_point via initializeFeasiblePoint
    countT              vertexCount() const { return qh_qh->num_vertices; }

#//!\name Delegated to QhullQh
    double              angleEpsilon() const { return qh_qh->angleEpsilon(); } //!< Epsilon for hyperplane angle equality
    void                appendQhullMessage(const std::string &s) { qh_qh->appendQhullMessage(s); }
    void                clearQhullMessage() { qh_qh->clearQhullMessage(); }
    double              distanceEpsilon() const { return qh_qh->distanceEpsilon(); } //!< Epsilon for distance to hyperplane
    double              factorEpsilon() const { return qh_qh->factorEpsilon(); }  //!< Factor for angleEpsilon and distanceEpsilon
    std::string         qhullMessage() const { return qh_qh->qhullMessage(); }
    bool                hasQhullMessage() const { return qh_qh->hasQhullMessage(); }
    int                 qhullStatus() const { return qh_qh->qhullStatus(); }
    void                setErrorStream(std::ostream *os) { qh_qh->setErrorStream(os); }
    void                setFactorEpsilon(double a) { qh_qh->setFactorEpsilon(a); }
    void                setOutputStream(std::ostream *os) { qh_qh->setOutputStream(os); }

#//!\name ForEach
    QhullFacet          beginFacet() const { return QhullFacet(qh_qh, qh_qh->facet_list); }
    QhullVertex         beginVertex() const { return QhullVertex(qh_qh, qh_qh->vertex_list); }
    void                defineVertexNeighborFacets(); //!< Automatically called if merging facets or Voronoi diagram
    QhullFacet          endFacet() const { return QhullFacet(qh_qh, qh_qh->facet_tail); }
    QhullVertex         endVertex() const { return QhullVertex(qh_qh, qh_qh->vertex_tail); }
    QhullFacetList      facetList() const;
    QhullFacet          firstFacet() const { return beginFacet(); }
    QhullVertex         firstVertex() const { return beginVertex(); }
    QhullPoints         points() const;
    QhullPointSet       otherPoints() const;
                        //! Same as points().coordinates()
    coordT *            pointCoordinateBegin() const { return qh_qh->first_point; }
    coordT *            pointCoordinateEnd() const { return qh_qh->first_point + qh_qh->num_points*qh_qh->hull_dim; }
    QhullVertexList     vertexList() const;

#//!\name Methods
    double              area();
    void                outputQhull();
    void                outputQhull(const char * outputflags);
    void                prepareVoronoi(bool *isLower, int *voronoiVertexCount);
    void                runQhull(const RboxPoints &rboxPoints, const char *qhullCommand2);
    void                runQhull(const char *inputComment2, int pointDimension, int pointCount, const realT *pointCoordinates, const char *qhullCommand2);
    double              volume();

#//!\name Helpers
private:
    void                initializeFeasiblePoint(int hulldim);
};//Qhull

}//namespace orgQhull

#endif // QHULLCPP_H
qhull-2020.2/src/libqhullcpp/QhullError.h0000644060175106010010000000450513661631133016553 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullError.h#4 $$Change: 2953 $
** $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
**
****************************************************************************/

#ifndef QHULLERROR_H
#define QHULLERROR_H

#include "libqhullcpp/RoadError.h"
// No dependencies on libqhull

#ifndef QHULL_ASSERT
#define QHULL_ASSERT assert
#include 
#endif

namespace orgQhull {

#//!\name Defined here
    //! QhullError -- std::exception class for Qhull
    class QhullError;

class QhullError : public RoadError {

public:
#//!\name Constants
    enum {
        QHULLfirstError= 10000, //MSG_QHULL_ERROR in Qhull's user.h
        QHULLlastError= 10081,
        NOthrow= 1 //! For flag to indexOf()
    };

#//!\name Constructors
    // default constructors
    QhullError() : RoadError() {}
    QhullError(const QhullError &other) : RoadError(other) {}
    QhullError(int code, const std::string &message) : RoadError(code, message) {}
    QhullError(int code, const char *fmt) : RoadError(code, fmt) {}
    QhullError(int code, const char *fmt, int d) : RoadError(code, fmt, d) {}
    QhullError(int code, const char *fmt, int d, int d2) : RoadError(code, fmt, d, d2) {}
    QhullError(int code, const char *fmt, int d, int d2, float f) : RoadError(code, fmt, d, d2, f) {}
    QhullError(int code, const char *fmt, int d, int d2, float f, const char *s) : RoadError(code, fmt, d, d2, f, s) {}
    QhullError(int code, const char *fmt, int d, int d2, float f, const void *x) : RoadError(code, fmt, d, d2, f, x) {}
    QhullError(int code, const char *fmt, int d, int d2, float f, int i) : RoadError(code, fmt, d, d2, f, i) {}
    QhullError(int code, const char *fmt, int d, int d2, float f, long long i) : RoadError(code, fmt, d, d2, f, i) {}
    QhullError(int code, const char *fmt, int d, int d2, float f, double e) : RoadError(code, fmt, d, d2, f, e) {}
    QhullError &operator=(const QhullError &other) { this->RoadError::operator=(other); return *this; }
    ~QhullError() throw() {}

};//class QhullError


}//namespace orgQhull

#//!\name Global

inline std::ostream &operator<<(std::ostream &os, const orgQhull::QhullError &e) { return os << e.what(); }

#endif // QHULLERROR_H
qhull-2020.2/src/libqhullcpp/QhullFacet.cpp0000644060175106010010000003772013710645347017053 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullFacet.cpp#5 $$Change: 3009 $
** $DateTime: 2020/07/30 19:25:22 $$Author: bbarber $
**
****************************************************************************/

#//! QhullFacet -- Qhull's facet structure, facetT, as a C++ class

#include "libqhullcpp/QhullFacet.h"

#include "libqhullcpp/QhullError.h"
#include "libqhullcpp/Qhull.h"
#include "libqhullcpp/QhullSet.h"
#include "libqhullcpp/QhullPoint.h"
#include "libqhullcpp/QhullPointSet.h"
#include "libqhullcpp/QhullRidge.h"
#include "libqhullcpp/QhullFacetSet.h"
#include "libqhullcpp/QhullVertex.h"

#include 

using std::endl;
using std::ostream;

#ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
#pragma warning( disable : 4611)  // interaction between '_setjmp' and C++ object destruction is non-portable
#pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
#endif

namespace orgQhull {

#//!\name Class objects
facetT QhullFacet::
s_empty_facet= {
#if !qh_COMPUTEfurthest         // must match facetT -Wmissing-field-initializers
        0.0,
#endif
#if qh_MAXoutside
        0.0,
#endif
        0.0,NULL,{0.0},
        NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,0,0,
        false,false,false,false,false,
        false,false,false,false,false,
        false,false,false,false,false,
        false,false,false,false,false,
        false,false,false};

#//!\name Constructors

QhullFacet::
QhullFacet(const Qhull &q)
: qh_facet(&s_empty_facet)
, qh_qh(q.qh())
{
}

QhullFacet::
QhullFacet(const Qhull &q, facetT *f)
: qh_facet(f ? f : &s_empty_facet)
, qh_qh(q.qh())
{
}

#//!\name GetSet

//! Return voronoi center or facet centrum.  Derived from qh_printcenter [io_r.c]
//! if printFormat=qh_PRINTtriangles and qh.DELAUNAY, returns centrum of a Delaunay facet
//! Sets center if needed
//! Code duplicated for PrintCenter and getCenter
//! Returns QhullPoint() if none or qh_INFINITE
QhullPoint QhullFacet::
getCenter(qh_PRINT printFormat)
{
    if(!qh_qh){
        // returns QhullPoint()
    }else if(qh_qh->CENTERtype==qh_ASvoronoi){
        if(!qh_facet->normal || !qh_facet->upperdelaunay || !qh_qh->ATinfinity){
            if(!qh_facet->center){
                QH_TRY_(qh_qh){ // no object creation -- destructors skipped on longjmp()
                    qh_facet->center= qh_facetcenter(qh_qh, qh_facet->vertices);
                }
                qh_qh->NOerrexit= true;
                qh_qh->maybeThrowQhullMessage(QH_TRY_status);
            }
            return QhullPoint(qh_qh, qh_qh->hull_dim-1, qh_facet->center);
        }
    }else if(qh_qh->CENTERtype==qh_AScentrum){
        volatile int numCoords= qh_qh->hull_dim;
        if(printFormat==qh_PRINTtriangles && qh_qh->DELAUNAY){
            numCoords--;
        }
        if(!qh_facet->center){
            QH_TRY_(qh_qh){ // no object creation -- destructors skipped on longjmp()
                qh_facet->center= qh_getcentrum(qh_qh, getFacetT());
            }
            qh_qh->NOerrexit= true;
            qh_qh->maybeThrowQhullMessage(QH_TRY_status);
        }
        return QhullPoint(qh_qh, numCoords, qh_facet->center);
    }
    return QhullPoint();
 }//getCenter

//! Return innerplane clearly below the vertices
//! from io_r.c[qh_PRINTinner]
QhullHyperplane QhullFacet::
innerplane() const
{
    QhullHyperplane h;
    if(qh_qh){
        realT inner;
        // Does not error, TRY_QHULL_ not needed
        qh_outerinner(qh_qh, const_cast(getFacetT()), NULL, &inner);
        h= hyperplane();
        h.setOffset(h.offset()-inner); //inner is negative
    }
    return h;
}//innerplane

QhullFacet QhullFacet::
nextFacet2d(QhullVertex *nextVertex) const
{
    QhullFacet f;
    if(qh_qh && qh_facet){
        vertexT *vertex;
        // Does not error, TRY_QHULL_ not needed
        facetT *facet= qh_nextfacet2d(getFacetT(), &vertex);
        f.setFacetT(qh_qh, facet);
        nextVertex->setVertexT(qh_qh, vertex);
    }
    return f;
}//nextFacet2d

//! Return outerplane clearly above all points
//! from io_r.c[qh_PRINTouter]
QhullHyperplane QhullFacet::
outerplane() const
{
    QhullHyperplane h;
    if(qh_qh){
        realT outer;
        // Does not error, TRY_QHULL_ not needed
        qh_outerinner(qh_qh, const_cast(getFacetT()), &outer, NULL);
        h= hyperplane();
        h.setOffset(h.offset()-outer); //outer is positive
    }
    return h;
}//outerplane

//! Set by qh_triangulate for option 'Qt'.
//! Errors if tricoplanar and facetArea() or qh_getarea() called first.
QhullFacet QhullFacet::
tricoplanarOwner() const
{
    if(qh_facet->tricoplanar){
        if(qh_facet->isarea){
            throw QhullError(10018, "Qhull error: facetArea() or qh_getarea() previously called.  triCoplanarOwner() is not available.");
        }
        return QhullFacet(qh_qh, qh_facet->f.triowner);
    }
    return QhullFacet(qh_qh);
}//tricoplanarOwner

QhullPoint QhullFacet::
voronoiVertex()
{
    if(qh_qh && qh_qh->CENTERtype!=qh_ASvoronoi){
          throw QhullError(10052, "Error: QhullFacet.voronoiVertex() requires option 'v' (qh_ASvoronoi)");
    }
    return getCenter();
}//voronoiVertex

#//!\name Value

//! Disables tricoplanarOwner()
double QhullFacet::
facetArea()
{
    if(qh_qh && !qh_facet->isarea){
        QH_TRY_(qh_qh){ // no object creation -- destructors skipped on longjmp()
            qh_facet->f.area= qh_facetarea(qh_qh, qh_facet);
            qh_facet->isarea= True;
        }
        qh_qh->NOerrexit= true;
        qh_qh->maybeThrowQhullMessage(QH_TRY_status);
    }
    return qh_facet->f.area;
}//facetArea

#//!\name Foreach

QhullPointSet QhullFacet::
coplanarPoints() const
{
    return QhullPointSet(qh_qh, qh_facet->coplanarset);
}//coplanarPoints

QhullFacetSet QhullFacet::
neighborFacets() const
{
    return QhullFacetSet(qh_qh, qh_facet->neighbors);
}//neighborFacets

QhullPointSet QhullFacet::
outsidePoints() const
{
    return QhullPointSet(qh_qh, qh_facet->outsideset);
}//outsidePoints

QhullRidgeSet QhullFacet::
ridges() const
{
    return QhullRidgeSet(qh_qh, qh_facet->ridges);
}//ridges

QhullVertexSet QhullFacet::
vertices() const
{
    return QhullVertexSet(qh_qh, qh_facet->vertices);
}//vertices

}//namespace orgQhull

#//!\name operator<<

using std::ostream;

using orgQhull::QhullFacet;
using orgQhull::QhullFacetSet;
using orgQhull::QhullPoint;
using orgQhull::QhullPointSet;
using orgQhull::QhullRidge;
using orgQhull::QhullRidgeSet;
using orgQhull::QhullSetBase;
using orgQhull::QhullVertexSet;

ostream &
operator<<(ostream &os, const QhullFacet::PrintFacet &pr)
{
    os << pr.message;
    QhullFacet f= *pr.facet;
    if(f.getFacetT()==0){ // Special values from set iterator
        os << " NULLfacet" << endl;
        return os;
    }
    if(f.getFacetT()==qh_MERGEridge){
        os << " MERGEridge" << endl;
        return os;
    }
    if(f.getFacetT()==qh_DUPLICATEridge){
        os << " DUPLICATEridge" << endl;
        return os;
    }
    os << f.printHeader();
    if(!f.ridges().isEmpty()){
        os << f.printRidges();
    }
    return os;
}//operator<< PrintFacet

//! Print Voronoi center or facet centrum to stream.  Same as qh_printcenter [_r.]
//! Code duplicated for PrintCenter and getCenter
//! Sets center if needed
ostream &
operator<<(ostream &os, const QhullFacet::PrintCenter &pr)
{
    facetT *f= pr.facet->getFacetT();
    if(pr.facet->qh()->CENTERtype!=qh_ASvoronoi && pr.facet->qh()->CENTERtype!=qh_AScentrum){
        return os;
    }
    if(pr.message){
        os << pr.message;
    }
    int numCoords;
    if(pr.facet->qh()->CENTERtype==qh_ASvoronoi){
        numCoords= pr.facet->qh()->hull_dim-1;
        if(!f->normal || !f->upperdelaunay || !pr.facet->qh()->ATinfinity){
            if(!f->center){
                f->center= qh_facetcenter(pr.facet->qh(), f->vertices);
            }
            for(int k=0; kcenter[k] << " "; // QH11010 FIX: qh_REAL_1
            }
        }else{
            for(int k=0; kqh()->hull_dim;
        if(pr.print_format==qh_PRINTtriangles && pr.facet->qh()->DELAUNAY){
            numCoords--;
        }
        if(!f->center){
            f->center= qh_getcentrum(pr.facet->qh(), f);
        }
        for(int k=0; kcenter[k] << " "; // QH11010 FIX: qh_REAL_1
        }
    }
    if(pr.print_format==qh_PRINTgeom && numCoords==2){
        os << " 0";
    }
    os << endl;
    return os;
}//operator<< PrintCenter

//! Print flags for facet to stream.  Space prefix.  From qh_printfacetheader [io_r.c]
ostream &
operator<<(ostream &os, const QhullFacet::PrintFlags &p)
{
    const facetT *f= p.facet->getFacetT();
    if(p.message){
        os << p.message;
    }

    os << (p.facet->isTopOrient() ? " top" : " bottom");
    if(p.facet->isSimplicial()){
        os << " simplicial";
    }
    if(p.facet->isTriCoplanar()){
        os << " tricoplanar";
    }
    if(p.facet->isUpperDelaunay()){
        os << " upperDelaunay";
    }
    if(f->visible){
        os << " visible";
    }
    if(f->newfacet){
        os << " new";
    }
    if(f->tested){
        os << " tested";
    }
    if(!f->good){
        os << " notG";
    }
    if(f->seen && p.facet->qh()->IStracing){
        os << " seen";
    }
    if(f->seen2 && p.facet->qh()->IStracing){
      os << " seen";
    }
    if(f->isarea){
      os << " isarea";
    }
    if(f->coplanarhorizon){
        os << " coplanarhorizon";
    }
    if(f->mergehorizon){
        os << " mergehorizon";
    }
    if(f->cycledone){
      os << " cycledone";
    }
    if(f->keepcentrum){
        os << " keepcentrum";
    }
    if(f->dupridge){
        os << " dupridge";
    }
    if(f->mergeridge && !f->mergeridge2){
        os << " mergeridge1";
    }
    if(f->mergeridge2){
        os << " mergeridge2";
    }
    if(f->newmerge){
        os << " newmerge";
    }
    if(f->flipped){
        os << " flipped";
    }
    if(f->notfurthest){
        os << " notfurthest";
    }
    if(f->degenerate){
        os << " degenerate";
    }
    if(f->redundant){
        os << " redundant";
    }
    os << endl;
    return os;
}//operator<< PrintFlags

//! Print header for facet to stream. Space prefix.  From qh_printfacetheader [io_r.c]
ostream &
operator<<(ostream &os, const QhullFacet::PrintHeader &pr)
{
    QhullFacet facet= *pr.facet;
    facetT *f= facet.getFacetT();
    os << "- f" << facet.id() << endl;
    os << facet.printFlags("    - flags:");
    if(f->isarea){
        os << "    - area: " << f->f.area << endl; //QH11010 FIX: 2.2g
    }else if(pr.facet->qh()->NEWfacets && f->visible && f->f.replace){
        os << "    - replacement: f" << f->f.replace->id << endl;
    }else if(f->newfacet){
        if(f->f.samecycle && f->f.samecycle != f){
            os << "    - shares same visible/horizon as f" << f->f.samecycle->id << endl;
        }
    }else if(f->tricoplanar /* !isarea */){
        if(f->f.triowner){
            os << "    - owner of normal & centrum is facet f" << f->f.triowner->id << endl;
        }
    }else if(f->f.newcycle){
        os << "    - was horizon to f" << f->f.newcycle->id << endl;
    }
    if(f->nummerge){
        os << "    - merges: " << f->nummerge << endl;
    }
    os << facet.hyperplane().print("    - normal: ", "\n    - offset: "); // QH11010 FIX: %10.7g
    if(pr.facet->qh()->CENTERtype==qh_ASvoronoi || f->center){
        os << facet.printCenter(qh_PRINTfacets, "    - center: ");
    }
#if qh_MAXoutside
    if(f->maxoutside > pr.facet->qh()->DISTround){
        os << "    - maxoutside: " << f->maxoutside << endl; //QH11010 FIX: %10.7g
    }
#endif
    QhullPointSet ps= facet.outsidePoints();
    if(!ps.isEmpty()){
        QhullPoint furthest= ps.last();
        if(ps.size() < 6){
            os << "    - outside set(furthest p" << furthest.id() << "):" << endl;
            for(QhullPointSet::iterator i=ps.begin(); i!=ps.end(); ++i){
                QhullPoint p= *i;
                os << p.print("     ");
            }
        }else if(ps.size()<21){
            os << ps.print("    - outside set:");
        }else{
            os << "    - outside set:  " << ps.size() << " points.";
            os << furthest.print("  Furthest");
        }
#if !qh_COMPUTEfurthest
        os << "    - furthest distance= " << f->furthestdist << endl; //QH11010 FIX: %2.2g
#endif
    }
    QhullPointSet cs= facet.coplanarPoints();
    if(!cs.isEmpty()){
        QhullPoint furthest= cs.last();
        if(cs.size() < 6){
            os << "    - coplanar set(furthest p" << furthest.id() << "):" << endl;
            for(QhullPointSet::iterator i=cs.begin(); i!=cs.end(); ++i){
                QhullPoint p= *i;
                os << p.print("     ");
            }
        }else if(cs.size()<21){
            os << cs.print("    - coplanar set:");
        }else{
            os << "    - coplanar set:  " << cs.size() << " points.";
            os << furthest.print("  Furthest");
        }
        // QH11027 FIX: Can/should zinc_(Zdistio) be called from C++ interface
        double d= facet.distance(furthest);
        os << "      furthest distance= " << d << endl; //QH11010 FIX: %2.2g
    }
    QhullVertexSet vs= facet.vertices();
    if(!vs.isEmpty()){
        os << vs.print("    - vertices:");
    }
    QhullFacetSet fs= facet.neighborFacets();
    fs.selectAll();
    if(!fs.isEmpty()){
        os << fs.printIdentifiers("    - neighboring facets:");
    }
    return os;
}//operator<< PrintHeader


//! Print ridges of facet to stream.  Same as qh_printfacetridges [io_r.c]
ostream &
operator<<(ostream &os, const QhullFacet::PrintRidges &pr)
{
    const QhullFacet facet= *pr.facet;
    facetT *f= facet.getFacetT();
    QhullRidgeSet rs= facet.ridges();
    if(!rs.isEmpty()){
        if(f->visible && pr.facet->qh()->NEWfacets){
            os << "    - ridges(ids may be garbage):";
            for(QhullRidgeSet::iterator i=rs.begin(); i!=rs.end(); ++i){
                QhullRidge r= *i;
                os << " r" << r.id();
            }
            os << endl;
        }else{
            os << "    - ridges:" << endl;
        }

        // Keep track of printed ridges
        for(QhullRidgeSet::iterator i=rs.begin(); i!=rs.end(); ++i){
            QhullRidge r= *i;
            r.getRidgeT()->seen= false;
        }
        int ridgeCount= 0;
        if(facet.dimension()==3){
            for(QhullRidge r= rs.first(); !r.getRidgeT()->seen; r= r.nextRidge3d(facet)){
                r.getRidgeT()->seen= true;
                os << r.print("");
                ++ridgeCount;
                if(!r.hasNextRidge3d(facet)){
                    break;
                }
            }
        }else{
            QhullFacetSet ns(facet.neighborFacets());
            for(QhullFacetSet::iterator i=ns.begin(); i!=ns.end(); ++i){
                QhullFacet neighbor= *i;
                QhullRidgeSet nrs(neighbor.ridges());
                for(QhullRidgeSet::iterator j=nrs.begin(); j!=nrs.end(); ++j){
                    QhullRidge r= *j;
                    if(r.otherFacet(neighbor)==facet){
                        r.getRidgeT()->seen= true;
                        os << r.print("");
                        ridgeCount++;
                    }
                }
            }
        }
        if(ridgeCount!=rs.count()){
            os << "     - all ridges:";
            for(QhullRidgeSet::iterator i=rs.begin(); i!=rs.end(); ++i){
                QhullRidge r= *i;
                os << " r" << r.id();
            }
            os << endl;
        }
        for(QhullRidgeSet::iterator i=rs.begin(); i!=rs.end(); ++i){
            QhullRidge r= *i;
            if(!r.getRidgeT()->seen){
                os << r.print("");
            }
        }
    }
    return os;
}//operator<< PrintRidges

// "No conversion" error if defined inline
ostream &
operator<<(ostream &os, QhullFacet &f)
{
    os << f.print("");
    return os;
}//<< QhullFacet
qhull-2020.2/src/libqhullcpp/QhullFacet.h0000644060175106010010000001670713665501303016512 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullFacet.h#4 $$Change: 2963 $
** $DateTime: 2020/06/03 19:31:01 $$Author: bbarber $
**
****************************************************************************/

#ifndef QHULLFACET_H
#define QHULLFACET_H

#include "libqhull_r/qhull_ra.h"
#include "libqhullcpp/QhullHyperplane.h"
#include "libqhullcpp/QhullPoint.h"
#include "libqhullcpp/QhullSet.h"
#include "libqhullcpp/QhullPointSet.h"

#include 

namespace orgQhull {

#//!\name Used here
    class Coordinates;
    class Qhull;
    class QhullFacetSet;
    class QhullRidge;
    class QhullVertex;
    class QhullVertexSet;

#//!\name Defined here
    class QhullFacet;
    typedef QhullSet  QhullRidgeSet;

//! A QhullFacet is the C++ equivalent to Qhull's facetT*
class QhullFacet {

#//!\name Defined here
public:
    typedef facetT *   base_type;  // for QhullVertexSet

private:
#//!\name Fields -- no additions (QhullFacetSet of facetT*)
    facetT *            qh_facet;  //!< Corresponding facetT, may be 0 for corner cases (e.g., *facetSet.end()==0) and tricoplanarOwner()
    QhullQh *           qh_qh;     //!< QhullQh/qhT for facetT, may be 0

#//!\name Class objects
    static facetT       s_empty_facet; // needed for shallow copy

public:
#//!\name Constructors
                        QhullFacet() : qh_facet(&s_empty_facet), qh_qh(0) {}
    explicit            QhullFacet(const Qhull &q);
                        QhullFacet(const Qhull &q, facetT *f);
    explicit            QhullFacet(QhullQh *qqh) : qh_facet(&s_empty_facet), qh_qh(qqh) {}
                        QhullFacet(QhullQh *qqh, facetT *f) : qh_facet(f ? f : &s_empty_facet), qh_qh(qqh) {}
                        // Creates an alias.  Does not copy QhullFacet.  Needed for return by value and parameter passing
                        QhullFacet(const QhullFacet &other) : qh_facet(other.qh_facet ? other.qh_facet : &s_empty_facet), qh_qh(other.qh_qh) {}
                        // Creates an alias.  Does not copy QhullFacet.  Needed for vector
    QhullFacet &        operator=(const QhullFacet &other) { qh_facet= other.qh_facet ? other.qh_facet : &s_empty_facet; qh_qh= other.qh_qh; return *this; }
                        ~QhullFacet() {}


#//!\name GetSet
    int                 dimension() const { return (qh_qh ? qh_qh->hull_dim : 0); }
    QhullPoint          getCenter() { return getCenter(qh_PRINTpoints); }
    QhullPoint          getCenter(qh_PRINT printFormat);
    facetT *            getBaseT() const { return getFacetT(); } //!< For QhullSet
                        // Do not define facetT().  It conflicts with return type facetT*
    facetT *            getFacetT() const { return qh_facet; }
    bool                hasNext() const { return (qh_facet->next != NULL && qh_facet->next != qh_qh->facet_tail); }
    bool                hasPrevious() const { return (qh_facet->previous != NULL); }
    QhullHyperplane     hyperplane() const { return QhullHyperplane(qh_qh, dimension(), qh_facet->normal, qh_facet->offset); }
    countT              id() const { return (qh_facet ? qh_facet->id : static_cast(qh_IDunknown)); }
    QhullHyperplane     innerplane() const;
    bool                isValid() const { return qh_qh && qh_facet && qh_facet != &s_empty_facet; }
    bool                isGood() const { return qh_facet && qh_facet->good; }
    bool                isSimplicial() const { return qh_facet && qh_facet->simplicial; }
    bool                isTopOrient() const { return qh_facet && qh_facet->toporient; }
    bool                isTriCoplanar() const { return qh_facet && qh_facet->tricoplanar; }
    bool                isUpperDelaunay() const { return qh_facet && qh_facet->upperdelaunay; }
    QhullFacet          next() const { return QhullFacet(qh_qh, qh_facet->next); }
    QhullFacet          nextFacet2d(QhullVertex *nextVertex) const;
    bool                operator==(const QhullFacet &other) const { return qh_facet==other.qh_facet; }
    bool                operator!=(const QhullFacet &other) const { return !operator==(other); }
    QhullHyperplane     outerplane() const;
    QhullFacet          previous() const { return QhullFacet(qh_qh, qh_facet->previous); }
    QhullQh *           qh() const { return qh_qh; }
    void                setFacetT(QhullQh *qqh, facetT *facet) { qh_qh= qqh; qh_facet= facet; }
    QhullFacet          tricoplanarOwner() const;
    int                 visitId() const { return (qh_facet ? qh_facet->visitid : -1); }
    QhullPoint          voronoiVertex();

#//!\name value
    //! Undefined if c.size() != dimension()
    double              distance(const Coordinates &c) const { return distance(c.data()); }
    double              distance(const pointT *p) const { return distance(QhullPoint(qh_qh, const_cast(p))); }
    double              distance(const QhullPoint &p) const { return hyperplane().distance(p); }
    double              facetArea();

#//!\name foreach
    // Can not inline.  Otherwise circular reference
    QhullPointSet       coplanarPoints() const;
    QhullFacetSet       neighborFacets() const;
    QhullPointSet       outsidePoints() const;
    QhullRidgeSet       ridges() const;
    QhullVertexSet      vertices() const;

#//!\name IO
    struct PrintCenter{
        QhullFacet *    facet;  // non-const due to facet.center()
        const char *    message;
        qh_PRINT        print_format;
                        PrintCenter(QhullFacet &f, qh_PRINT printFormat, const char * s) : facet(&f), message(s), print_format(printFormat){}
    };//PrintCenter
    PrintCenter         printCenter(qh_PRINT printFormat, const char *message) { return PrintCenter(*this, printFormat, message); }

    struct PrintFacet{
        QhullFacet *    facet;  // non-const due to f->center()
        const char *    message;
        explicit        PrintFacet(QhullFacet &f, const char * s) : facet(&f), message(s) {}
    };//PrintFacet
    PrintFacet          print(const char *message) { return PrintFacet(*this, message); }

    struct PrintFlags{
        const QhullFacet *facet;
        const char *    message;
                        PrintFlags(const QhullFacet &f, const char *s) : facet(&f), message(s) {}
    };//PrintFlags
    PrintFlags          printFlags(const char *message) const { return PrintFlags(*this, message); }

    struct PrintHeader{
        QhullFacet *    facet;  // non-const due to f->center()
                        PrintHeader(QhullFacet &f) : facet(&f) {}
    };//PrintHeader
    PrintHeader         printHeader() { return PrintHeader(*this); }

    struct PrintRidges{
        const QhullFacet *facet;
                        PrintRidges(QhullFacet &f) : facet(&f) {}
    };//PrintRidges
    PrintRidges         printRidges() { return PrintRidges(*this); }

};//class QhullFacet

}//namespace orgQhull

#//!\name Global

std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacet::PrintFacet &pr);
std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacet::PrintCenter &pr);
std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacet::PrintFlags &pr);
std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacet::PrintHeader &pr);
std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacet::PrintRidges &pr);
std::ostream &operator<<(std::ostream &os, orgQhull::QhullFacet &f); // non-const due to qh_getcenter()

#endif // QHULLFACET_H
qhull-2020.2/src/libqhullcpp/QhullFacetList.cpp0000644060175106010010000001061213661631133017667 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullFacetList.cpp#2 $$Change: 2953 $
** $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
**
****************************************************************************/

#//! QhullFacetList -- Qhull's linked facets, as a C++ class

#include "libqhullcpp/QhullFacetList.h"

#include "libqhullcpp/QhullFacet.h"
#include "libqhullcpp/QhullPoint.h"
#include "libqhullcpp/QhullRidge.h"
#include "libqhullcpp/QhullVertex.h"

using std::string;
using std::vector;

#ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
#pragma warning( disable : 4611)  // interaction between '_setjmp' and C++ object destruction is non-portable
#pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
#endif

namespace orgQhull {

#//!\name Constructors

QhullFacetList::
QhullFacetList(const Qhull &q, facetT *b, facetT *e ) 
: QhullLinkedList(QhullFacet(q, b), QhullFacet(q, e))
, select_all(false)
{
}

#//!\name Conversions

// See qt_qhull.cpp for QList conversions

#ifndef QHULL_NO_STL
std::vector QhullFacetList::
toStdVector() const
{
    QhullLinkedListIterator i(*this);
    std::vector vs;
    while(i.hasNext()){
        QhullFacet f= i.next();
        if(isSelectAll() || f.isGood()){
            vs.push_back(f);
        }
    }
    return vs;
}//toStdVector
#endif //QHULL_NO_STL

#ifndef QHULL_NO_STL
//! Same as PrintVertices
std::vector QhullFacetList::
vertices_toStdVector() const
{
    std::vector vs;
    QhullVertexSet qvs(qh(), first().getFacetT(), 0, isSelectAll());

    for(QhullVertexSet::iterator i=qvs.begin(); i!=qvs.end(); ++i){
        vs.push_back(*i);
    }
    return vs;
}//vertices_toStdVector
#endif //QHULL_NO_STL

#//!\name GetSet

bool QhullFacetList::
contains(const QhullFacet &facet) const
{
    if(isSelectAll()){
        return QhullLinkedList::contains(facet);
    }
    for(QhullFacetList::const_iterator i=begin(); i != end(); ++i){
        QhullFacet f= *i;
        if(f==facet && f.isGood()){
            return true;
        }
    }
    return false;
}//contains

int QhullFacetList::
count() const
{
    if(isSelectAll()){
        return QhullLinkedList::count();
    }
    int counter= 0;
    for(QhullFacetList::const_iterator i=begin(); i != end(); ++i){
        if((*i).isGood()){
            counter++;
        }
    }
    return counter;
}//count

int QhullFacetList::
count(const QhullFacet &facet) const
{
    if(isSelectAll()){
        return QhullLinkedList::count(facet);
    }
    int counter= 0;
    for(QhullFacetList::const_iterator i=begin(); i != end(); ++i){
        QhullFacet f= *i;
        if(f==facet && f.isGood()){
            counter++;
        }
    }
    return counter;
}//count

}//namespace orgQhull

#//!\name Global functions

using std::endl;
using std::ostream;
using orgQhull::QhullFacet;
using orgQhull::QhullFacetList;
using orgQhull::QhullVertex;
using orgQhull::QhullVertexSet;

ostream &
operator<<(ostream &os, const QhullFacetList::PrintFacetList &pr)
{
    os << pr.print_message;
    QhullFacetList fs= *pr.facet_list;
    os << "Vertices for " << fs.count() << " facets" << endl;
    os << fs.printVertices();
    os << fs.printFacets();
    return os;
}//operator<<

//! Print facet list to stream.  From qh_printafacet [io_r.c]
ostream &
operator<<(ostream &os, const QhullFacetList::PrintFacets &pr)
{
    for(QhullFacetList::const_iterator i= pr.facet_list->begin(); i != pr.facet_list->end(); ++i){
        QhullFacet f= *i;
        if(pr.facet_list->isSelectAll() || f.isGood()){
            os << f.print("");
        }
    }
    return os;
}//printFacets

//! Print vertices of good faces in facet list to stream.  From qh_printvertexlist [io_r.c]
//! Same as vertices_toStdVector
ostream &
operator<<(ostream &os, const QhullFacetList::PrintVertices &pr)
{
    QhullVertexSet vs(pr.facet_list->qh(), pr.facet_list->first().getFacetT(), NULL, pr.facet_list->isSelectAll());
    for(QhullVertexSet::iterator i=vs.begin(); i!=vs.end(); ++i){
        QhullVertex v= *i;
        os << v.print("");
    }
    return os;
}//printVertices

std::ostream &
operator<<(ostream &os, const QhullFacetList &fs)
{
    os << fs.printFacets();
    return os;
}//QhullFacetList

qhull-2020.2/src/libqhullcpp/QhullFacetList.h0000644060175106010010000001043113706435715017343 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullFacetList.h#3 $$Change: 3001 $
** $DateTime: 2020/07/24 20:43:28 $$Author: bbarber $
**
****************************************************************************/

#ifndef QHULLFACETLIST_H
#define QHULLFACETLIST_H

#include "libqhullcpp/QhullLinkedList.h"
#include "libqhullcpp/QhullFacet.h"

#include 

#ifndef QHULL_NO_STL
#include 
#endif

namespace orgQhull {

#//!\name Used here
    class Qhull;
    class QhullFacet;
    class QhullQh;

#//!\name Defined here
    //! QhullFacetList -- List of QhullFacet/facetT, as a C++ class.  
    //!\see QhullFacetSet.h
    class QhullFacetList;
    //! QhullFacetListIterator is a Java-style iterator for QhullFacetList. -- if(f.isGood()){ ... }
    typedef QhullLinkedListIterator QhullFacetListIterator;

class QhullFacetList : public QhullLinkedList {

#//!\name  Fields
private:
    bool                select_all;   //! True if include bad facets.  Default is false.

#//!\name Constructors
public:
                        QhullFacetList(const Qhull &q, facetT *b, facetT *e);
                        QhullFacetList(QhullQh *qqh, facetT *b, facetT *e);
                        QhullFacetList(QhullFacet b, QhullFacet e) : QhullLinkedList(b, e), select_all(false) {}
                        //Copy constructor copies pointer but not contents.  Needed for return by value and parameter passing.
                        QhullFacetList(const QhullFacetList &other) : QhullLinkedList(*other.begin(), *other.end()), select_all(other.select_all) {}
    QhullFacetList &    operator=(const QhullFacetList &other) { QhullLinkedList::operator =(other); select_all= other.select_all; return *this; }
                        ~QhullFacetList() {}

private:                //!Disable default constructor.  See QhullLinkedList
                        QhullFacetList();
public:

#//!\name Conversion
#ifndef QHULL_NO_STL
    std::vector toStdVector() const;
    std::vector vertices_toStdVector() const;
#endif //QHULL_NO_STL
#ifdef QHULL_USES_QT
    QList   toQList() const;
    QList  vertices_toQList() const;
#endif //QHULL_USES_QT

#//!\name GetSet
                        //! Filtered by facet.isGood().  May be 0 when !isEmpty().
    countT              count() const;
    bool                contains(const QhullFacet &f) const;
    countT              count(const QhullFacet &f) const;
    bool                isSelectAll() const { return select_all; }
    QhullQh *           qh() const { return first().qh(); }
    void                selectAll() { select_all= true; }
    void                selectGood() { select_all= false; }
                        //!< operator==() does not depend on isGood()

#//!\name IO
    struct PrintFacetList{
        const QhullFacetList *facet_list;
        const char *    print_message;   //!< non-null message
                        PrintFacetList(const QhullFacetList &fl, const char *message) : facet_list(&fl), print_message(message) {}
    };//PrintFacetList
    PrintFacetList      print(const char *message) const  { return PrintFacetList(*this, message); }

    struct PrintFacets{
        const QhullFacetList *facet_list;
                        PrintFacets(const QhullFacetList &fl) : facet_list(&fl) {}
    };//PrintFacets
    PrintFacets         printFacets() const { return PrintFacets(*this); }

    struct PrintVertices{
        const QhullFacetList *facet_list;
                        PrintVertices(const QhullFacetList &fl) : facet_list(&fl) {}
    };//PrintVertices
    PrintVertices       printVertices() const { return PrintVertices(*this); }
};//class QhullFacetList

}//namespace orgQhull

#//!\name == Global namespace =========================================

std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacetList::PrintFacetList &p);
std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacetList::PrintFacets &p);
std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacetList::PrintVertices &p);
std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacetList &fs);

#endif // QHULLFACETLIST_H
qhull-2020.2/src/libqhullcpp/QhullFacetSet.cpp0000644060175106010010000000714413661631133017515 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullFacetSet.cpp#2 $$Change: 2953 $
** $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
**
****************************************************************************/

#//! QhullFacetSet -- Qhull's linked facets, as a C++ class

#include "libqhullcpp/QhullFacetSet.h"

#include "libqhullcpp/QhullFacet.h"
#include "libqhullcpp/QhullPoint.h"
#include "libqhullcpp/QhullRidge.h"
#include "libqhullcpp/QhullVertex.h"

#ifndef QHULL_NO_STL
using std::vector;
#endif

#ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
#pragma warning( disable : 4611)  // interaction between '_setjmp' and C++ object destruction is non-portable
#pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
#endif

namespace orgQhull {

#//!\name Conversions

// See qt-qhull.cpp for QList conversions

#ifndef QHULL_NO_STL
std::vector QhullFacetSet::
toStdVector() const
{
    QhullSetIterator i(*this);
    std::vector vs;
    while(i.hasNext()){
        QhullFacet f= i.next();
        if(isSelectAll() || f.isGood()){
            vs.push_back(f);
        }
    }
    return vs;
}//toStdVector
#endif //QHULL_NO_STL

#//!\name GetSet

bool QhullFacetSet::
contains(const QhullFacet &facet) const
{
    if(isSelectAll()){
        return QhullSet::contains(facet);
    }
    for(QhullFacetSet::const_iterator i=begin(); i != end(); ++i){
        QhullFacet f= *i;
        if(f==facet && f.isGood()){
            return true;
        }
    }
    return false;
}//contains

int QhullFacetSet::
count() const
{
    if(isSelectAll()){
        return QhullSet::count();
    }
    int counter= 0;
    for(QhullFacetSet::const_iterator i=begin(); i != end(); ++i){
        QhullFacet f= *i;
        if(f.isGood()){
            counter++;
        }
    }
    return counter;
}//count

int QhullFacetSet::
count(const QhullFacet &facet) const
{
    if(isSelectAll()){
        return QhullSet::count(facet);
    }
    int counter= 0;
    for(QhullFacetSet::const_iterator i=begin(); i != end(); ++i){
        QhullFacet f= *i;
        if(f==facet && f.isGood()){
            counter++;
        }
    }
    return counter;
}//count

}//namespace orgQhull

#//!\name Global functions

using std::endl;
using std::ostream;
using orgQhull::QhullFacet;
using orgQhull::QhullFacetSet;

ostream &
operator<<(ostream &os, const QhullFacetSet &fs)
{
    os << fs.print("");
    return os;
}//<begin(); i!=p.facet_set->end(); ++i){
        const QhullFacet f= *i;
        if(f.getFacetT()==qh_MERGEridge){
            os << " MERGE";
        }else if(f.getFacetT()==qh_DUPLICATEridge){
            os << " DUP";
        }else if(p.facet_set->isSelectAll() || f.isGood()){
            os << " f" << f.id();
        }
    }
    os << endl;
    return os;
}//<

namespace orgQhull {

#//!\name Used here
    class Qhull;

#//!\name Defined here
    //! QhullFacetSet -- a set of Qhull facets, as a C++ class.  See QhullFacetList.h
    class QhullFacetSet;

    //! QhullFacetSetIterator is a Java-style iterator.  It may be used on temporary results.
    //! QhullFacetSetIterator copies the qh_set and qh_qh pointers in QhullSetBase
    //! QhullFacetSetIterator, iterator, and const_iterator return all facets.  Select good facets with facet.isGood()
    typedef QhullSetIterator QhullFacetSetIterator;

class QhullFacetSet : public QhullSet {

#//!\name Defined here
public:
    typedef facetT *   base_type;  // for QhullVertexSet

private:
#//!\name Fields
    bool                select_all;   //! True if include bad facets.  Default is false.

public:
#//!\name Constructor
                        //Conversion from setT* is not type-safe.  Implicit conversion for void* to T
                        QhullFacetSet(const Qhull &q, setT *s) : QhullSet(q, s), select_all(false) {}
                        QhullFacetSet(QhullQh *qqh, setT *s) : QhullSet(qqh, s), select_all(false) {}
                        //!Copy constructor copies pointers but not contents.  Needed for return by value and parameter passing.
                        QhullFacetSet(const QhullFacetSet &other) : QhullSet(other), select_all(other.select_all) {}
                        //!Assignment copies pointers but not contents.
    QhullFacetSet &     operator=(const QhullFacetSet &other) { QhullSet::operator=(other); select_all= other.select_all; return *this; }

private:
                        //!Disable default constructor.  See QhullSetBase
                        QhullFacetSet();
public:

#//!\name Conversion
#ifndef QHULL_NO_STL
    std::vector toStdVector() const;
#endif //QHULL_NO_STL
#ifdef QHULL_USES_QT
    QList   toQList() const;
#endif //QHULL_USES_QT

#//!\name GetSet
                        //! Filtered by facet.isGood().  May be 0 when !isEmpty().
    countT              count() const;
    bool                contains(const QhullFacet &f) const;
    countT              count(const QhullFacet &f) const;
    bool                isSelectAll() const { return select_all; }
                        //! operator==() does not depend on isGood()
    void                selectAll() { select_all= true; }
    void                selectGood() { select_all= false; }

#//!\name IO
    // Not same as QhullFacetList#IO.  A QhullFacetSet is a component of a QhullFacetList.

    struct PrintFacetSet{
        const QhullFacetSet *facet_set;
        const char *    print_message;  //!< non-null message
                        PrintFacetSet(const char *message, const QhullFacetSet *s) : facet_set(s), print_message(message) {}
    };//PrintFacetSet
    const PrintFacetSet print(const char *message) const { return PrintFacetSet(message, this); }

    struct PrintIdentifiers{
        const QhullFacetSet *facet_set;
        const char *    print_message;  //!< non-null message
                        PrintIdentifiers(const char *message, const QhullFacetSet *s) : facet_set(s), print_message(message) {}
    };//PrintIdentifiers
    PrintIdentifiers    printIdentifiers(const char *message) const { return PrintIdentifiers(message, this); }

};//class QhullFacetSet

}//namespace orgQhull

#//!\name == Global namespace =========================================

std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacetSet &fs);
std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacetSet::PrintFacetSet &pr);
std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacetSet::PrintIdentifiers &p);

#endif // QHULLFACETSET_H
qhull-2020.2/src/libqhullcpp/QhullHyperplane.cpp0000644060175106010010000001161313710645347020131 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2009-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullHyperplane.cpp#5 $$Change: 3009 $
** $DateTime: 2020/07/30 19:25:22 $$Author: bbarber $
**
****************************************************************************/

#include "libqhullcpp/QhullHyperplane.h"

#include "libqhullcpp/Qhull.h"
#include "libqhullcpp/QhullPoint.h"

#include 


#ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
#endif

namespace orgQhull {

#//!\name Constructors

QhullHyperplane::
QhullHyperplane(const Qhull &q)
: hyperplane_coordinates(0)
, qh_qh(q.qh())
, hyperplane_offset(0.0)
, hyperplane_dimension(0)
{
}

QhullHyperplane::
QhullHyperplane(const Qhull &q, int hyperplaneDimension, coordT *c, coordT hyperplaneOffset)
: hyperplane_coordinates(c)
, qh_qh(q.qh())
, hyperplane_offset(hyperplaneOffset)
, hyperplane_dimension(hyperplaneDimension)
{
}

#//!\name Conversions

// See qt-qhull.cpp for QList conversions

#ifndef QHULL_NO_STL
std::vector QhullHyperplane::
toStdVector() const
{
    QhullHyperplaneIterator i(*this);
    std::vector fs;
    while(i.hasNext()){
        fs.push_back(i.next());
    }
    fs.push_back(hyperplane_offset);
    return fs;
}//toStdVector
#endif //QHULL_NO_STL

#//!\name GetSet

//! Return true if equal
//! If qh_qh defined, tests qh.distanceEpsilon and qh.angleEpsilon
//! otherwise, tests equal coordinates and offset
bool QhullHyperplane::
operator==(const QhullHyperplane &other) const
{
    if(hyperplane_dimension!=other.hyperplane_dimension || !hyperplane_coordinates || !other.hyperplane_coordinates){
        return false;
    }
    double d= fabs(hyperplane_offset-other.hyperplane_offset);
    if(d > (qh_qh ? qh_qh->distanceEpsilon() : 0.0)){
        return false;
    }
    double angle= hyperplaneAngle(other);

    double a= fabs(angle-1.0);
    if(a > (qh_qh ? qh_qh->angleEpsilon() : 0.0)){
        return false;
    }
    return true;
}//operator==

#//!\name Methods

//! Return distance from point to hyperplane.
//!   If greater than zero, the point is above the facet (i.e., outside).
// qh_distplane [geom_r.c], QhullFacet::distance, and QhullHyperplane::distance are copies
//    Does not support RANDOMdist or logging
double QhullHyperplane::
distance(const QhullPoint &p) const
{
    const coordT *point= p.coordinates();
    int dim= p.dimension();
    QHULL_ASSERT(dim==dimension());
    const coordT *normal= coordinates();
    double dist;

    switch (dim){
  case 2:
      dist= offset() + point[0] * normal[0] + point[1] * normal[1];
      break;
  case 3:
      dist= offset() + point[0] * normal[0] + point[1] * normal[1] + point[2] * normal[2];
      break;
  case 4:
      dist= offset()+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3];
      break;
  case 5:
      dist= offset()+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4];
      break;
  case 6:
      dist= offset()+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5];
      break;
  case 7:
      dist= offset()+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6];
      break;
  case 8:
      dist= offset()+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6]+point[7]*normal[7];
      break;
  default:
      dist= offset();
      for(int k=dim; k--; ){
          dist += *point++ * *normal++;
      }
      break;
    }
    return dist;
}//distance

double QhullHyperplane::
hyperplaneAngle(const QhullHyperplane &other) const
{
    volatile realT result= 0.0;
    QH_TRY_(qh_qh){ // no object creation -- destructors skipped on longjmp()
        result= qh_getangle(qh_qh, hyperplane_coordinates, other.hyperplane_coordinates);
    }
    qh_qh->NOerrexit= true;
    qh_qh->maybeThrowQhullMessage(QH_TRY_status);
    return result;
}//hyperplaneAngle

double QhullHyperplane::
norm() const {
    double d= 0.0;
    const coordT *c= coordinates();
    for(int k=dimension(); k--; ){
        d += *c * *c;
        ++c;
    }
    return sqrt(d);
}//norm

}//namespace orgQhull

#//!\name Global functions

using std::ostream;
using orgQhull::QhullHyperplane;

#//!\name GetSet<<

ostream &
operator<<(ostream &os, const QhullHyperplane &p)
{
    os << p.print("");
    return os;
}

ostream &
operator<<(ostream &os, const QhullHyperplane::PrintHyperplane &pr)
{
    os << pr.print_message;
    QhullHyperplane p= *pr.hyperplane;
    const realT *c= p.coordinates();
    for(int k=p.dimension(); k--; ){
        realT r= *c++;
        os << " " << r; // QH11010 FIX: %8.4g qh_REAL_1
    }
    os << pr.hyperplane_offset_message << " " << p.offset();
    os << std::endl;
    return os;
}//PrintHyperplane

qhull-2020.2/src/libqhullcpp/QhullHyperplane.h0000644060175106010010000001550713710603351017571 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2009-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullHyperplane.h#4 $$Change: 3008 $
** $DateTime: 2020/07/30 13:54:27 $$Author: bbarber $
**
****************************************************************************/

#ifndef QHHYPERPLANE_H
#define QHHYPERPLANE_H

#include "libqhull_r/qhull_ra.h"
#include "libqhullcpp/QhullError.h"
#include "libqhullcpp/QhullIterator.h"
#include "libqhullcpp/QhullQh.h"

#include 

namespace orgQhull {

#//!\name Used here
    class Qhull;
    class QhullPoint;

#//!\name Defined here
    class QhullHyperplane;          //!< QhullHyperplane is a pointer to the normal vector, an offset from the origin, and dimension
    class QhullHyperplaneIterator;  //!< Java-style iterator for QhullHyperplane coordinates    

class QhullHyperplane { // Similar to QhullPoint
public:
#//!\name Subtypes
    typedef const coordT *                  iterator;
    typedef const coordT *                  const_iterator;
    typedef QhullHyperplane::iterator       Iterator;
    typedef QhullHyperplane::const_iterator ConstIterator;

private:
#//!\name Fields
    coordT *            hyperplane_coordinates;  //!< Normal to hyperplane.   facetT.normal is normalized to 1.0
    QhullQh *           qh_qh;                  //!< qhT for distanceEpsilon() in operator==
    coordT              hyperplane_offset;      //!< Distance from hyperplane to origin
    int                 hyperplane_dimension;   //!< Dimension of hyperplane

#//!\name Construct
public:
                        QhullHyperplane() : hyperplane_coordinates(0), qh_qh(0), hyperplane_offset(0.0), hyperplane_dimension(0) {}
    explicit            QhullHyperplane(const Qhull &q);
                        QhullHyperplane(const Qhull &q, int hyperplaneDimension, coordT *c, coordT hyperplaneOffset);
    explicit            QhullHyperplane(QhullQh *qqh) : hyperplane_coordinates(0), qh_qh(qqh), hyperplane_offset(0.0), hyperplane_dimension(0) {}
                        QhullHyperplane(QhullQh *qqh, int hyperplaneDimension, coordT *c, coordT hyperplaneOffset) : hyperplane_coordinates(c), qh_qh(qqh), hyperplane_offset(hyperplaneOffset), hyperplane_dimension(hyperplaneDimension) {}
                        // Creates an alias.  Does not copy the hyperplane's coordinates.  Needed for return by value and parameter passing.
                        QhullHyperplane(const QhullHyperplane &other)  : hyperplane_coordinates(other.hyperplane_coordinates), qh_qh(other.qh_qh), hyperplane_offset(other.hyperplane_offset), hyperplane_dimension(other.hyperplane_dimension) {}
                        // Creates an alias.  Does not copy the hyperplane's coordinates.  Needed for vector
    QhullHyperplane &   operator=(const QhullHyperplane &other) { hyperplane_coordinates= other.hyperplane_coordinates; qh_qh= other.qh_qh; hyperplane_offset= other.hyperplane_offset; hyperplane_dimension= other.hyperplane_dimension; return *this; }
                        ~QhullHyperplane() {}

#//!\name Conversions --
//! Includes offset at end
#ifndef QHULL_NO_STL
    std::vector toStdVector() const;
#endif //QHULL_NO_STL
#ifdef QHULL_USES_QT
    QList       toQList() const;
#endif //QHULL_USES_QT

#//!\name GetSet
public:
    const coordT *      coordinates() const { return hyperplane_coordinates; }
    coordT *            coordinates() { return hyperplane_coordinates; }
    void                defineAs(int hyperplaneDimension, coordT *c, coordT hyperplaneOffset) { QHULL_ASSERT(hyperplaneDimension>=0); hyperplane_coordinates= c; hyperplane_dimension= hyperplaneDimension; hyperplane_offset= hyperplaneOffset; }
    //! Creates an alias to other using the same qh_qh
    void                defineAs(QhullHyperplane &other) { hyperplane_coordinates= other.coordinates(); hyperplane_dimension= other.dimension();  hyperplane_offset= other.offset(); }
    int                 dimension() const { return hyperplane_dimension; }
    bool                isValid() const { return hyperplane_coordinates!=0 && hyperplane_dimension>0; }
    coordT              offset() const { return hyperplane_offset; }
    bool                operator==(const QhullHyperplane &other) const;
    bool                operator!=(const QhullHyperplane &other) const { return !operator==(other); }
    const coordT &      operator[](int idx) const { QHULL_ASSERT(idx>=0 && idx=0 && idx(hyperplane_dimension); }

#//!\name Methods
    double              distance(const QhullPoint &p) const;
    double              hyperplaneAngle(const QhullHyperplane &other) const;
    double              norm() const;

#//!\name IO
    struct PrintHyperplane{
        const QhullHyperplane  *hyperplane;
        const char *    print_message;      //!< non-null message
        const char *    hyperplane_offset_message;  //!< non-null message
                        PrintHyperplane(const char *message, const char *offsetMessage, const QhullHyperplane &p) : hyperplane(&p), print_message(message), hyperplane_offset_message(offsetMessage) {}
    };//PrintHyperplane
    PrintHyperplane          print(const char *message) const { return PrintHyperplane(message, "", *this); }
    PrintHyperplane          print(const char *message, const char *offsetMessage) const { return PrintHyperplane(message, offsetMessage, *this); }

};//QhullHyperplane

//! QhullHyperplaneIterator is a Java-style iterator for QhullHyperplane coordinates
QHULL_DECLARE_SEQUENTIAL_ITERATOR(QhullHyperplane, coordT)

}//namespace orgQhull

#//!\name Global

std::ostream &operator<<(std::ostream &os, const orgQhull::QhullHyperplane::PrintHyperplane &pr);
std::ostream &operator<<(std::ostream &os, const orgQhull::QhullHyperplane &p);

#endif // QHHYPERPLANE_H

qhull-2020.2/src/libqhullcpp/QhullIterator.h0000644060175106010010000001761613706413717017270 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullIterator.h#4 $$Change: 3001 $
** $DateTime: 2020/07/24 20:43:28 $$Author: bbarber $
**
****************************************************************************/

#ifndef QHULLITERATOR_H
#define QHULLITERATOR_H

#include "libqhull_r/qhull_ra.h"

#include 
#include 
#include 
#include 

namespace orgQhull {

#//!\name Defined here
    //! Only QHULL_DECLARE_SEQUENTIAL_ITERATOR is used in libqhullcpp.  The others need further development
    //! QHULL_DECLARE_SEQUENTIAL_ITERATOR(C) -- Declare a Java-style iterator
    //! QHULL_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR(C) -- Declare a mutable Java-style iterator
    //! QHULL_DECLARE_SET_ITERATOR(C) -- Declare a set iterator
    //! QHULL_DECLARE_MUTABLE_SET_ITERATOR(C) -- Declare a mutable set iterator
    //! Derived from Qt/core/tools/qiterator.h and qset_r.h/FOREACHsetelement_()

//! Stores C as done in Qt's Q_DECLARE_SEQUENTIAL_ITERATOR.  Allows use with temporaries.
//! Do not use for containers with deep-copy semantics (e.g., STL::vector)
// C::const_iterator is an STL-style iterator that returns T&
#define QHULL_DECLARE_SEQUENTIAL_ITERATOR(C, T) \
    \
    class C##Iterator \
    { \
        typedef C::const_iterator const_iterator; \
        C c; \
        const_iterator i; \
        public: \
        inline C##Iterator(const C &container) \
        : c(container), i(c.constBegin()) {} \
        inline C##Iterator &operator=(const C &container) \
        { c= container; i= c.constBegin(); return *this; } \
        inline void toFront() { i= c.constBegin(); } \
        inline void toBack() { i= c.constEnd(); } \
        inline bool hasNext() const { return i != c.constEnd(); } \
        inline const T &next() { return *i++; } \
        inline const T &peekNext() const { return *i; } \
        inline bool hasPrevious() const { return i != c.constBegin(); } \
        inline const T &previous() { return *--i; } \
        inline const T &peekPrevious() const { const_iterator p= i; return *--p; } \
        inline bool findNext(const T &t) \
        { while (i != c.constEnd()) if (*i++ == t) return true; return false; } \
        inline bool findPrevious(const T &t) \
        { while (i != c.constBegin()) if (*(--i) == t) return true; \
        return false;  } \
    };//C##Iterator

// Remove setShareable() from Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR
// Uses QHULL_ASSERT (assert.h)
// Duplicated in MutablePointIterator without insert or remove
// Not used in libqhullcpp.  See Coordinates.h
#define QHULL_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR(C, T) \
    class Mutable##C##Iterator \
    { \
        typedef C::iterator iterator; \
        typedef C::const_iterator const_iterator; \
        C *c; \
        iterator i, n; \
        inline bool item_exists() const { return const_iterator(n) != c->constEnd(); } \
        public: \
        inline Mutable##C##Iterator(C &container) \
        : c(&container) \
        { i= c->begin(); n= c->end(); } \
        inline ~Mutable##C##Iterator() \
        {} \
        inline Mutable##C##Iterator &operator=(C &container) \
        { c= &container; \
        i= c->begin(); n= c->end(); return *this; } \
        inline void toFront() { i= c->begin(); n= c->end(); } \
        inline void toBack() { i= c->end(); n= i; } \
        inline bool hasNext() const { return c->constEnd() != const_iterator(i); } \
        inline T &next() { n= i++; return *n; } \
        inline T &peekNext() const { return *i; } \
        inline bool hasPrevious() const { return c->constBegin() != const_iterator(i); } \
        inline T &previous() { n= --i; return *n; } \
        inline T &peekPrevious() const { iterator p= i; return *--p; } \
        inline void remove() \
        { if (c->constEnd() != const_iterator(n)) { i= c->erase(n); n= c->end(); } } \
        inline void setValue(const T &t) const { if (c->constEnd() != const_iterator(n)) *n= t; } \
        inline T &value() { QHULL_ASSERT(item_exists()); return *n; } \
        inline const T &value() const { QHULL_ASSERT(item_exists()); return *n; } \
        inline void insert(const T &t) { n= i= c->insert(i, t); ++i; } \
        inline bool findNext(const T &t) \
        { while (c->constEnd() != const_iterator(n= i)) if (*i++ == t) return true; return false; } \
        inline bool findPrevious(const T &t) \
        { while (c->constBegin() != const_iterator(i)) if (*(n= --i) == t) return true; \
        n= c->end(); return false;  } \
    };//Mutable##C##Iterator

// Not used in libqhullcpp.
#define QHULL_DECLARE_SET_ITERATOR(C) \
\
    template  \
    class Qhull##C##Iterator \
    { \
        typedef typename Qhull##C::const_iterator const_iterator; \
        Qhull##C c; \
        const_iterator i; \
    public: \
        inline Qhull##C##Iterator(const Qhull##C &container) \
        : c(container), i(c.constBegin()) {} \
        inline Qhull##C##Iterator &operator=(const Qhull##C &container) \
        { c= container; i= c.constBegin(); return *this; } \
        inline void toFront() { i= c.constBegin(); } \
        inline void toBack() { i= c.constEnd(); } \
        inline bool hasNext() const { return i != c.constEnd(); } \
        inline const T &next() { return *i++; } \
        inline const T &peekNext() const { return *i; } \
        inline bool hasPrevious() const { return i != c.constBegin(); } \
        inline const T &previous() { return *--i; } \
        inline const T &peekPrevious() const { const_iterator p= i; return *--p; } \
        inline bool findNext(const T &t) \
        { while (i != c.constEnd()) if (*i++ == t) return true; return false; } \
        inline bool findPrevious(const T &t) \
        { while (i != c.constBegin()) if (*(--i) == t) return true; \
        return false;  } \
    };//Qhull##C##Iterator

// Not used in libqhullcpp.
#define QHULL_DECLARE_MUTABLE_SET_ITERATOR(C) \
\
template  \
class QhullMutable##C##Iterator \
{ \
    typedef typename Qhull##C::iterator iterator; \
    typedef typename Qhull##C::const_iterator const_iterator; \
    Qhull##C *c; \
    iterator i, n; \
    inline bool item_exists() const { return const_iterator(n) != c->constEnd(); } \
public: \
    inline Mutable##C##Iterator(Qhull##C &container) \
        : c(&container) \
    { c->setSharable(false); i= c->begin(); n= c->end(); } \
    inline ~Mutable##C##Iterator() \
    { c->setSharable(true); } \
    inline Mutable##C##Iterator &operator=(Qhull##C &container) \
    { c->setSharable(true); c= &container; c->setSharable(false); \
      i= c->begin(); n= c->end(); return *this; } \
    inline void toFront() { i= c->begin(); n= c->end(); } \
    inline void toBack() { i= c->end(); n= i; } \
    inline bool hasNext() const { return c->constEnd() != const_iterator(i); } \
    inline T &next() { n= i++; return *n; } \
    inline T &peekNext() const { return *i; } \
    inline bool hasPrevious() const { return c->constBegin() != const_iterator(i); } \
    inline T &previous() { n= --i; return *n; } \
    inline T &peekPrevious() const { iterator p= i; return *--p; } \
    inline void remove() \
    { if (c->constEnd() != const_iterator(n)) { i= c->erase(n); n= c->end(); } } \
    inline void setValue(const T &t) const { if (c->constEnd() != const_iterator(n)) *n= t; } \
    inline T &value() { Q_ASSERT(item_exists()); return *n; } \
    inline const T &value() const { Q_ASSERT(item_exists()); return *n; } \
    inline void insert(const T &t) { n= i= c->insert(i, t); ++i; } \
    inline bool findNext(const T &t) \
    { while (c->constEnd() != const_iterator(n= i)) if (*i++ == t) return true; return false; } \
    inline bool findPrevious(const T &t) \
    { while (c->constBegin() != const_iterator(i)) if (*(n= --i) == t) return true; \
      n= c->end(); return false;  } \
};//QhullMutable##C##Iterator

}//namespace orgQhull

#endif // QHULLITERATOR_H

qhull-2020.2/src/libqhullcpp/QhullLinkedList.h0000644060175106010010000003051613710644344017530 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullLinkedList.h#6 $$Change: 3009 $
** $DateTime: 2020/07/30 19:25:22 $$Author: bbarber $
**
****************************************************************************/

#ifndef QHULLLINKEDLIST_H
#define QHULLLINKEDLIST_H

#include "libqhull_r/qhull_ra.h"
#include "libqhullcpp/QhullError.h"

#include   // ptrdiff_t, size_t

#ifdef QHULL_USES_QT
#include 
#endif

#ifndef QHULL_NO_STL
#include 
#include 
#include 
#endif

namespace orgQhull {

#//!\name Defined here
    //! QhullLinkedList -- A linked list modeled on QLinkedList.
    //!   T is an opaque type with T(B *b), b=t.getBaseT(), t=t.next(), and t=t.prev().  The end node is a sentinel.
    //!   QhullQh/qhT owns the contents.
    //!   QhullLinkedList does not define erase(), clear(), removeFirst(), removeLast(), pop_back(), pop_front(), fromStdList()
    //!   Derived from Qt/core/tools/qlinkedlist.h and libqhull_r.h/FORALLfacets_()
    //! QhullLinkedList::const_iterator -- STL-style iterator
    //! QhullLinkedList::iterator -- STL-style iterator
    //! QhullLinkedListIterator -- Java-style iterator
    //!   Derived from Qt/core/tools/qiterator.h
    //!   Works with Qt's foreach keyword [Qt/src/corelib/global/qglobal.h]

template 
class QhullLinkedList
{
#//!\name Defined here
public:
    class const_iterator;
    class iterator;
    typedef const_iterator  ConstIterator;
    typedef iterator    Iterator;
    typedef ptrdiff_t   difference_type;
    typedef countT      size_type;
    typedef T           value_type;
    typedef const value_type *const_pointer;
    typedef const value_type &const_reference;
    typedef value_type *pointer;
    typedef value_type &reference;

#//!\name Fields
private:
    T                   begin_node;
    T                   end_node;     //! Sentinel node at end of list

#//!\name Constructors
public:
                        QhullLinkedList(T b, T e) : begin_node(b), end_node(e) {}
                        //! Copy constructor copies begin_node and end_node, but not the list elements.  Needed for return by value and parameter passing.
                        QhullLinkedList(const QhullLinkedList &other) : begin_node(other.begin_node), end_node(other.end_node) {}
                        //! Copy assignment copies begin_node and end_node, but not the list elements.
                        QhullLinkedList & operator=(const QhullLinkedList &other) { begin_node= other.begin_node; end_node= other.end_node; return *this; }
                        ~QhullLinkedList() {}

private:
                        //!disabled since a sentinel must be allocated as the private type
                        QhullLinkedList() {}

public:

#//!\name Conversions
#ifndef QHULL_NO_STL
    std::vector      toStdVector() const;
#endif
#ifdef QHULL_USES_QT
    QList            toQList() const;
#endif

#//!\name GetSet
    countT              count() const;
                        //count(t) under #//!\name Search
    bool                isEmpty() const { return (begin_node==end_node); }
    bool                operator==(const QhullLinkedList &o) const;
    bool                operator!=(const QhullLinkedList &o) const { return !operator==(o); }
    size_t              size() const { return count(); }

#//!\name Element access
    //! For back() and last(), return T instead of T& (T is computed)
    const T             back() const { return last(); }
    T                   back() { return last(); }
    const T &           first() const { QHULL_ASSERT(!isEmpty()); return begin_node; }
    T &                 first() { QHULL_ASSERT(!isEmpty()); return begin_node; }
    const T &           front() const { return first(); }
    T &                 front() { return first(); }
    const T             last() const { QHULL_ASSERT(!isEmpty()); return *--end(); }
    T                   last() { QHULL_ASSERT(!isEmpty()); return *--end(); }

#//!\name Modify -- Allocation of opaque types not implemented.

#//!\name Search
    bool                contains(const T &t) const;
    countT              count(const T &t) const;

#//!\name Iterator
    iterator            begin() { return begin_node; }
    const_iterator      begin() const { return begin_node; }
    const_iterator      constBegin() const { return begin_node; }
    const_iterator      constEnd() const { return end_node; }
    iterator            end() { return end_node; }
    const_iterator      end() const { return end_node; }

    class iterator {

    private:
        T               i;
        friend class const_iterator;

    public:
        typedef std::bidirectional_iterator_tag  iterator_category;
        typedef T           value_type;
        typedef value_type *pointer;
        typedef value_type &reference;
        typedef ptrdiff_t   difference_type;

                        iterator() : i() {}
                        iterator(const T &t) : i(t) {}  //!< Automatic conversion to iterator
                        iterator(const iterator &o) : i(o.i) {}
        iterator &      operator=(const iterator &o) { i= o.i; return *this; }

        const T &       operator*() const { return i; }
        T &             operator*() { return i; }
        // Do not define operator[]
        const T *       operator->() const { return &i; }
        T *             operator->() { return &i; }
        bool            operator==(const iterator &o) const { return i == o.i; }
        bool            operator!=(const iterator &o) const { return !operator==(o); }
        bool            operator==(const const_iterator &o) const { return i==reinterpret_cast(o).i; }
        bool            operator!=(const const_iterator &o) const { return !operator==(o); }
        iterator &      operator++() { i= i.next(); return *this; }
        iterator        operator++(int) { iterator o= i; i= i.next(); return o; }
        iterator &      operator--() { i= i.previous(); return *this; }
        iterator        operator--(int) { iterator o= i; i= i.previous(); return o; }
        iterator        operator+(int j) const;
        iterator        operator-(int j) const { return operator+(-j); }
        iterator &      operator+=(int j) { return (*this= *this + j); }
        iterator &      operator-=(int j) { return (*this= *this - j); }
    };//QhullLinkedList::iterator

    class const_iterator {

    private:
        T               i;

    public:
        typedef std::bidirectional_iterator_tag  iterator_category;
        typedef T                 value_type;
        typedef const value_type *pointer;
        typedef const value_type &reference;
        typedef ptrdiff_t         difference_type;

                        const_iterator() : i() {}
                        const_iterator(const T &t) : i(t) {}  //!< Automatic conversion to const_iterator
                        const_iterator(const iterator &o) : i(o.i) {}
                        const_iterator(const const_iterator &o) : i(o.i) {}
        const_iterator &operator=(const const_iterator &o) { i= o.i; return *this; }

        const T &       operator*() const { return i; }
        const T *       operator->() const { return &i; }
        bool            operator==(const const_iterator &o) const { return i == o.i; }
        bool            operator!=(const const_iterator &o) const { return !operator==(o); }
                        // No comparisons or iterator diff
        const_iterator &operator++() { i= i.next(); return *this; }
        const_iterator  operator++(int) { const_iterator o= i; i= i.next(); return o; }
        const_iterator &operator--() { i= i.previous(); return *this; }
        const_iterator  operator--(int) { const_iterator o= i; i= i.previous(); return o; }
        const_iterator  operator+(int j) const;
        const_iterator  operator-(int j) const { return operator+(-j); }
        const_iterator &operator+=(int j) { return (*this= *this + j); }
        const_iterator &operator-=(int j) { return (*this= *this - j); }
    };//QhullLinkedList::const_iterator

};//QhullLinkedList

template 
class QhullLinkedListIterator // QH11016 FIX: define QhullMutableLinkedListIterator
{
    typedef typename QhullLinkedList::const_iterator const_iterator;
    QhullLinkedList  c;
    const_iterator      i;

public:
                        QhullLinkedListIterator(const QhullLinkedList &container) : c(container), i(c.constBegin()) {}
    QhullLinkedListIterator & operator=(const QhullLinkedList &container) { c= container; i= c.constBegin(); return *this; }
    bool                findNext(const T &t);
    bool                findPrevious(const T &t);
    bool                hasNext() const { return i != c.constEnd(); }
    bool                hasPrevious() const { return i != c.constBegin(); }
    T                   next() { return *i++; }
    T                   peekNext() const { return *i; }
    T                   peekPrevious() const { const_iterator p= i; return *--p; }
    T                   previous() { return *--i; }
    void                toFront() { i= c.constBegin(); }
    void                toBack() { i= c.constEnd(); }
};//QhullLinkedListIterator

#//!\name == Definitions =========================================

#//!\name Conversion

#ifndef QHULL_NO_STL
template 
std::vector QhullLinkedList::
toStdVector() const
{
    std::vector tmp;
    std::copy(constBegin(), constEnd(), std::back_inserter(tmp));
    return tmp;
}//toStdVector
#endif

#ifdef QHULL_USES_QT
template 
QList  QhullLinkedList::
toQList() const
{
    QhullLinkedListIterator i(*this);
    QList ls;
    while(i.hasNext()){
        ls.append(i.next());
    }
    return ls;
}//toQList
#endif

#//!\name GetSet

template 
countT QhullLinkedList::
count() const
{
    const_iterator i= begin_node;
    countT c= 0;
    while(i != end_node){
        c++;
        i++;
    }
    return c;
}//count

#//!\name Search

template 
bool QhullLinkedList::
contains(const T &t) const
{
    const_iterator i= begin_node;
    while(i != end_node){
        if(i==t){
            return true;
        }
        i++;
    }
    return false;
}//contains

template 
countT QhullLinkedList::
count(const T &t) const
{
    const_iterator i= begin_node;
    countT c= 0;
    while(i != end_node){
        if(i==t){
            c++;
        }
        i++;
    }
    return c;
}//count

template 
bool QhullLinkedList::
operator==(const QhullLinkedList &l) const
{
    if(begin_node==l.begin_node){
        return (end_node==l.end_node);
    }
    T i= begin_node;
    T il= l.begin_node;
    while(i != end_node){
        if(i != il){
            return false;
        }
        i= static_cast(i.next());
        il= static_cast(il.next());
    }
    if(il != l.end_node){
        return false;
    }
    return true;
}//operator==

#//!\name Iterator

template 
typename QhullLinkedList::iterator  QhullLinkedList::iterator::
operator+(int j) const
{
    T n= i;
    if(j>0){
        while(j--){
            n= n.next();
        }
    }else{
        while(j++){
            n= n.previous();
        }
    }
    return iterator(n);
}//operator+

template 
typename QhullLinkedList::const_iterator  QhullLinkedList::const_iterator::
operator+(int j) const
{
    T n= i;
    if(j>0){
        while(j--){
            n= n.next();
        }
    }else{
        while(j++){
            n= n.previous();
        }
    }
    return const_iterator(n);
}//operator+

#//!\name QhullLinkedListIterator

template 
bool QhullLinkedListIterator::
findNext(const T &t)
{
    while(i != c->constEnd()){
        if(*i++ == t){
            return true;
        }
    }
    return false;
}//findNext

template 
bool QhullLinkedListIterator::
findPrevious(const T &t)
{
    while(i!=c->constBegin()){
        if(*(--i)==t){
            return true;
        }
    }
    return false;
}//findNext

}//namespace orgQhull

#//!\name Global

template 
std::ostream &
operator<<(std::ostream &os, const orgQhull::QhullLinkedList &qs)
{
    typename orgQhull::QhullLinkedList::const_iterator i;
    for(i= qs.begin(); i != qs.end(); ++i){
        os << *i;
    }
    return os;
}//operator<<

#endif // QHULLLINKEDLIST_H

qhull-2020.2/src/libqhullcpp/QhullPoint.cpp0000644060175106010010000001256713661631133017115 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2009-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullPoint.cpp#4 $$Change: 2953 $
** $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
**
****************************************************************************/

#include "libqhullcpp/QhullPoint.h"

#include "libqhullcpp/QhullError.h"
#include "libqhullcpp/Qhull.h"

#include 
#include 

#ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
#endif

namespace orgQhull {

#//!\name Constructors


QhullPoint::
QhullPoint(const Qhull &q)
: point_coordinates(0)
, qh_qh(q.qh())
, point_dimension(q.hullDimension())
{
}//QhullPoint

QhullPoint::
QhullPoint(const Qhull &q, coordT *c)
: point_coordinates(c)
, qh_qh(q.qh())
, point_dimension(q.hullDimension())
{
    QHULL_ASSERT(q.hullDimension()>0);
}//QhullPoint dim, coordT

QhullPoint::
QhullPoint(const Qhull &q, int pointDimension, coordT *c)
: point_coordinates(c)
, qh_qh(q.qh())
, point_dimension(pointDimension)
{
}//QhullPoint dim, coordT

//! QhullPoint of Coordinates with point_dimension==c.count()
QhullPoint::
QhullPoint(const Qhull &q, Coordinates &c)
: point_coordinates(c.data())
, qh_qh(q.qh())
, point_dimension(c.count())
{
}//QhullPoint Coordinates

#//!\name Conversions

// See qt-qhull.cpp for QList conversion

#ifndef QHULL_NO_STL
std::vector QhullPoint::
toStdVector() const
{
    QhullPointIterator i(*this);
    std::vector vs;
    while(i.hasNext()){
        vs.push_back(i.next());
    }
    return vs;
}//toStdVector
#endif //QHULL_NO_STL

#//!\name GetSet

//! QhullPoint is equal if it has the same address and dimension
//! If !qh_qh, returns true if dimension and coordinates are equal
//! If qh_qh, returns true if the distance between points is less than qh_qh->distanceEpsilon()
//!\todo Compares distance with distance-to-hyperplane (distanceEpsilon).   Is that correct?
bool QhullPoint::
operator==(const QhullPoint &other) const
{
    if(point_dimension!=other.point_dimension){
        return false;
    }
    const coordT *c= point_coordinates;
    const coordT *c2= other.point_coordinates;
    if(c==c2){
        return true;
    }
    if(!c || !c2){
        return false;
    }
    if(!qh_qh || qh_qh->hull_dim==0){
        for(int k= point_dimension; k--; ){
            if(*c++ != *c2++){
                return false;
            }
        }
        return true;
    }
    double dist2= 0.0;
    for(int k= point_dimension; k--; ){
        double diff= *c++ - *c2++;
        dist2 += diff*diff;
    }
    dist2= sqrt(dist2);
    return (dist2 < qh_qh->distanceEpsilon());
}//operator==

#//!\name Methods

//! Return distance between two points.
double QhullPoint::
distance(const QhullPoint &p) const
{
    const coordT *c= point_coordinates;
    const coordT *c2= p.point_coordinates;
    int dim= point_dimension;
    if(dim!=p.point_dimension){
        throw QhullError(10075, "QhullPoint error: Expecting dimension %d for distance().  Got %d", dim, p.point_dimension);
    }
    if(!c || !c2){
        throw QhullError(10076, "QhullPoint error: Cannot compute distance() for undefined point");
    }
    double dist;

    switch(dim){
  case 2:
      dist= (c[0]-c2[0])*(c[0]-c2[0]) + (c[1]-c2[1])*(c[1]-c2[1]);
      break;
  case 3:
      dist= (c[0]-c2[0])*(c[0]-c2[0]) + (c[1]-c2[1])*(c[1]-c2[1]) + (c[2]-c2[2])*(c[2]-c2[2]);
      break;
  case 4:
      dist= (c[0]-c2[0])*(c[0]-c2[0]) + (c[1]-c2[1])*(c[1]-c2[1]) + (c[2]-c2[2])*(c[2]-c2[2]) + (c[3]-c2[3])*(c[3]-c2[3]);
      break;
  case 5:
      dist= (c[0]-c2[0])*(c[0]-c2[0]) + (c[1]-c2[1])*(c[1]-c2[1]) + (c[2]-c2[2])*(c[2]-c2[2]) + (c[3]-c2[3])*(c[3]-c2[3]) + (c[4]-c2[4])*(c[4]-c2[4]);
      break;
  case 6:
      dist= (c[0]-c2[0])*(c[0]-c2[0]) + (c[1]-c2[1])*(c[1]-c2[1]) + (c[2]-c2[2])*(c[2]-c2[2]) + (c[3]-c2[3])*(c[3]-c2[3]) + (c[4]-c2[4])*(c[4]-c2[4]) + (c[5]-c2[5])*(c[5]-c2[5]);
      break;
  case 7:
      dist= (c[0]-c2[0])*(c[0]-c2[0]) + (c[1]-c2[1])*(c[1]-c2[1]) + (c[2]-c2[2])*(c[2]-c2[2]) + (c[3]-c2[3])*(c[3]-c2[3]) + (c[4]-c2[4])*(c[4]-c2[4]) + (c[5]-c2[5])*(c[5]-c2[5]) + (c[6]-c2[6])*(c[6]-c2[6]);
      break;
  case 8:
      dist= (c[0]-c2[0])*(c[0]-c2[0]) + (c[1]-c2[1])*(c[1]-c2[1]) + (c[2]-c2[2])*(c[2]-c2[2]) + (c[3]-c2[3])*(c[3]-c2[3]) + (c[4]-c2[4])*(c[4]-c2[4]) + (c[5]-c2[5])*(c[5]-c2[5]) + (c[6]-c2[6])*(c[6]-c2[6]) + (c[7]-c2[7])*(c[7]-c2[7]);
      break;
  default:
      dist= 0.0;
      for(int k=dim; k--; ){
          dist += (*c - *c2) * (*c - *c2);
          ++c;
          ++c2;
      }
      break;
    }
    return sqrt(dist);
}//distance

}//namespace orgQhull

#//!\name Global functions

using std::ostream;
using orgQhull::QhullPoint;

//! Same as qh_printpointid [io.c]
ostream &
operator<<(ostream &os, const QhullPoint::PrintPoint &pr)
{
    QhullPoint p= *pr.point;
    countT i= p.id();
    if(pr.point_message){
        if(*pr.point_message){
            os << pr.point_message << " ";
        }
        if(pr.with_identifier && (i!=qh_IDunknown) && (i!=qh_IDnone)){
            os << "p" << i << ": ";
        }
    }
    const realT *c= p.coordinates();
    for(int k=p.dimension(); k--; ){
        realT r= *c++;
        os << " " << r; // QH11010 FIX: %8.4g  qh_REAL_1
    }
    os << std::endl;
    return os;
}//printPoint

ostream &
operator<<(ostream &os, const QhullPoint &p)
{
    os << p.print("");
    return os;
}//operator<<
qhull-2020.2/src/libqhullcpp/QhullPoint.h0000644060175106010010000001734213710603311016546 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2009-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullPoint.h#5 $$Change: 3008 $
** $DateTime: 2020/07/30 13:54:27 $$Author: bbarber $
**
****************************************************************************/

#ifndef QHPOINT_H
#define QHPOINT_H

#include "libqhull_r/qhull_ra.h"
#include "libqhullcpp/QhullError.h"
#include "libqhullcpp/QhullIterator.h"
#include "libqhullcpp/QhullQh.h"
#include "libqhullcpp/Coordinates.h"

#include 

namespace orgQhull {

#//!\name Defined here
    class QhullPoint;           //!< QhullPoint is a pointer to coordinates and dimension
    class QhullPointIterator;   //!< Java-style iterator for QhullPoint coordinates

#//!\name Used here
    class Qhull;

//! A QhullPoint is a dimension and an array of coordinates.
//! With Qhull/QhullQh, a QhullPoint has an identifier.  Point equality is relative to qh.distanceEpsilon
class QhullPoint {

#//!\name Iterators
public:
    typedef coordT *                    base_type;  // for QhullPointSet
    typedef const coordT *              iterator;
    typedef const coordT *              const_iterator;
    typedef QhullPoint::iterator        Iterator;
    typedef QhullPoint::const_iterator  ConstIterator;

#//!\name Fields
protected: // For QhullPoints::iterator, QhullPoints::const_iterator
    coordT *            point_coordinates;  //!< Pointer to first coordinate,   0 if undefined
    QhullQh *           qh_qh;              //!< qhT for this instance of Qhull.  0 if undefined.
                                            //!< operator==() returns true if points within sqrt(qh_qh->distanceEpsilon())
                                            //!< If !qh_qh, id() is -3, and operator==() requires equal coordinates
    int                 point_dimension;    //!< Default dimension is qh_qh->hull_dim
public:

#//!\name Constructors
    //! QhullPoint, PointCoordinates, and QhullPoints have similar constructors
    //! If Qhull/QhullQh is not initialized, then QhullPoint.dimension() is zero unless explicitly set
    //! Cannot define QhullPoints(int pointDimension) since it is ambiguous with QhullPoints(QhullQh *qqh)
                        QhullPoint() : point_coordinates(0), qh_qh(0), point_dimension(0) {}
                        QhullPoint(int pointDimension, coordT *c) : point_coordinates(c), qh_qh(0), point_dimension(pointDimension) { QHULL_ASSERT(pointDimension>0); }
    explicit            QhullPoint(const Qhull &q);
                        QhullPoint(const Qhull &q, coordT *c);
                        QhullPoint(const Qhull &q, Coordinates &c);
                        QhullPoint(const Qhull &q, int pointDimension, coordT *c);
    explicit            QhullPoint(QhullQh *qqh) : point_coordinates(0), qh_qh(qqh), point_dimension(qqh->hull_dim) {}
                        QhullPoint(QhullQh *qqh, coordT *c) : point_coordinates(c), qh_qh(qqh), point_dimension(qqh->hull_dim) { QHULL_ASSERT(qqh->hull_dim>0); }
                        QhullPoint(QhullQh *qqh, Coordinates &c) : point_coordinates(c.data()), qh_qh(qqh), point_dimension(c.count()) {}
                        QhullPoint(QhullQh *qqh, int pointDimension, coordT *c) : point_coordinates(c), qh_qh(qqh), point_dimension(pointDimension) {}
                        //! Creates an alias.  Does not make a deep copy of the point.  Needed for return by value and parameter passing.
                        QhullPoint(const QhullPoint &other) : point_coordinates(other.point_coordinates), qh_qh(other.qh_qh), point_dimension(other.point_dimension) {}
                        //! Creates an alias.  Does not make a deep copy of the point.  Needed for vector
    QhullPoint &        operator=(const QhullPoint &other) { point_coordinates= other.point_coordinates; qh_qh= other.qh_qh; point_dimension= other.point_dimension; return *this; }
                        ~QhullPoint() {}


#//!\name Conversions

#ifndef QHULL_NO_STL
    std::vector toStdVector() const;
#endif //QHULL_NO_STL
#ifdef QHULL_USES_QT
    QList       toQList() const;
#endif //QHULL_USES_QT

#//!\name GetSet
public:
    const coordT *      coordinates() const { return point_coordinates; }  //!< 0 if undefined
    coordT *            coordinates() { return point_coordinates; }        //!< 0 if undefined
    void                defineAs(coordT *c) { QHULL_ASSERT(point_dimension>0); point_coordinates= c; }
    void                defineAs(int pointDimension, coordT *c) { QHULL_ASSERT(pointDimension>=0); point_coordinates= c; point_dimension= pointDimension; }
    void                defineAs(QhullPoint &other) { point_coordinates= other.point_coordinates; qh_qh= other.qh_qh; point_dimension= other.point_dimension; }
    int                 dimension() const { return point_dimension; }
    coordT *            getBaseT() const { return point_coordinates; } // for QhullPointSet
    countT              id() const { return qh_pointid(qh_qh, point_coordinates); } // NOerrors
    bool                isValid() const { return (point_coordinates!=0 && point_dimension>0); }
    bool                operator==(const QhullPoint &other) const;
    bool                operator!=(const QhullPoint &other) const { return ! operator==(other); }
    const coordT &      operator[](int idx) const { QHULL_ASSERT(point_coordinates!=0 && idx>=0 && idx=0 && idx(point_coordinates ? point_dimension : 0); }

#//!\name Methods
    void                advancePoint(countT idx) { if(point_coordinates) { point_coordinates += idx*point_dimension; } }
    double              distance(const QhullPoint &p) const;

#//!\name IO

    struct PrintPoint{
        const QhullPoint *point;
        const char *    point_message;
        bool            with_identifier;
                        PrintPoint(const char *message, bool withIdentifier, const QhullPoint &p) : point(&p), point_message(message), with_identifier(withIdentifier) {}
    };//PrintPoint
    PrintPoint          print(const char *message) const { return PrintPoint(message, false, *this); }
    PrintPoint          printWithIdentifier(const char *message) const { return PrintPoint(message, true, *this); }

};//QhullPoint

//! QhullPointIterator is a Java-style iterator for QhullPoint coordinates
//! QhullPointIterator may be used on temporary results.  It copies the coordinates pointer in QhullPoint
QHULL_DECLARE_SEQUENTIAL_ITERATOR(QhullPoint, coordT)

}//namespace orgQhull

#//!\name Global

std::ostream &operator<<(std::ostream &os, const orgQhull::QhullPoint::PrintPoint &pr);
std::ostream &operator<<(std::ostream &os, const orgQhull::QhullPoint &p);

#endif // QHPOINT_H

qhull-2020.2/src/libqhullcpp/QhullPoints.cpp0000644060175106010010000001607713706415263017304 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2009-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullPoints.cpp#5 $$Change: 3001 $
** $DateTime: 2020/07/24 20:43:28 $$Author: bbarber $
**
****************************************************************************/

#include "libqhullcpp/QhullPoints.h"

#include "libqhullcpp/Qhull.h"

#include 

#ifndef QHULL_NO_STL
#include 
#endif

#ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
#endif

namespace orgQhull {

#//!\name Constructors

QhullPoints::
QhullPoints(const Qhull &q)
: point_first(0)
, point_end(0)
, qh_qh(q.qh())
, point_dimension(q.hullDimension())
{
}//QhullPoints Qhull

QhullPoints::
QhullPoints(const Qhull &q, countT coordinateCount2, coordT *c)
: point_first(c)
, point_end(c+coordinateCount2)
, qh_qh(q.qh())
, point_dimension(q.hullDimension())
{
    QHULL_ASSERT(q.hullDimension());
    QHULL_ASSERT(coordinateCount2>=0);
}//QhullPoints Qhull dim

QhullPoints::
QhullPoints(const Qhull &q, int pointDimension, countT coordinateCount2, coordT *c)
: point_first(c)
, point_end(c+coordinateCount2)
, qh_qh(q.qh())
, point_dimension(pointDimension)
{
    QHULL_ASSERT(pointDimension>=0);
    QHULL_ASSERT(coordinateCount2>=0);
}//QhullPoints Qhull dim coordT

QhullPoints::
QhullPoints(QhullQh *qqh, int pointDimension, countT coordinateCount2, coordT *c)
: point_first(c)
, point_end(c+coordinateCount2)
, qh_qh(qqh)
, point_dimension(pointDimension)
{
    QHULL_ASSERT(pointDimension>=0);
    QHULL_ASSERT(coordinateCount2>=0);
}//QhullPoints QhullQh dim coordT

#//!\name Conversions
// See qt-qhull.cpp for QList conversion

#ifndef QHULL_NO_STL
std::vector QhullPoints::
toStdVector() const
{
    QhullPointsIterator i(*this);
    std::vector vs;
    while(i.hasNext()){
        vs.push_back(i.next());
    }
    return vs;
}//toStdVector
#endif //QHULL_NO_STL

#//!\name GetSet

countT QhullPoints::
extraCoordinatesCount() const
{
    if(point_dimension>0){
        return (point_end-point_first) % point_dimension; /* must be less than point_dimension */
    }
    return 0;
}//extraCoordinatesCount

//! QhullPoints is equal if the same address, or if the coordinates are identical
//! Use QhullPoint.operator==() for DISTround equality
bool QhullPoints::
operator==(const QhullPoints &other) const
{
    if((point_end-point_first) != (other.point_end-other.point_first)){
        return false;
    }
    if(point_dimension!=other.point_dimension){
        return false;
    }
    if(point_first==other.point_first){
        return true;
    }
    if(!qh_qh || qh_qh->hull_dim==0){
        const coordT *c= point_first;
        const coordT *c2= other.point_first;
        while(chull_dim : 0);
    point_first= 0;
    point_end= 0;
}//resetQhullQh

QhullPoint QhullPoints::
value(countT idx) const
{
    QhullPoint p(qh_qh);
    if(idx>=0 && idx=0 && idx(offset/point_dimension);
    countT extra= offset % point_dimension;   /* must be less than point_dimension */
    if(extra!=0){
        throw QhullError(10066, "Qhull error: coordinates %x are not at point boundary (extra %d at index %d)", extra, idx, 0.0, pointCoordinates);
    }
    return idx;
}//indexOf coordT

countT QhullPoints::
indexOf(const coordT *pointCoordinates, int noThrow) const
{
    size_t extra= 0;
    if(noThrow){
        if(!includesCoordinates(pointCoordinates) || point_dimension==0){
            return -1;
        }
        extra= (pointCoordinates-point_first) % point_dimension;
    }
    return indexOf(pointCoordinates-extra);
}//indexOf coordT noThrow

countT QhullPoints::
indexOf(const QhullPoint &t) const
{
    countT j=0;
    const_iterator i= begin();
    while(i!=end()){
        if(*i==t){
            return j;
        }
        ++i;
        ++j;
    }
    return -1;
}//indexOf

countT QhullPoints::
lastIndexOf(const QhullPoint &t) const
{
    countT j= count();
    const_iterator i= end();
    while(i != begin()){
        --i;
        --j;
        if(*i==t){
            return j;
        }
    }
    return -1;
}//lastIndexOf

QhullPoints QhullPoints::
mid(countT idx, countT length) const
{
    countT n= count();
    if(idx<0 || idx>=n){
        n= 0;
    }else if(length<0 || idx+length>=n){
        n -= idx;
    }else{
        n -= idx+length;
    }
    return QhullPoints(qh_qh, point_dimension, n*point_dimension, point_first+idx*point_dimension);
}//mid

#//!\name QhullPointsIterator

bool QhullPointsIterator::
findNext(const QhullPoint &p)
{
    while(i!=ps.constEnd()){
        if(*i++ == p){
            return true;
        }
    }
    return false;
}//findNext

bool QhullPointsIterator::
findPrevious(const QhullPoint &p)
{
    while(i!=ps.constBegin()){
        if(*--i == p){
            return true;
        }
    }
    return false;
}//findPrevious

}//namespace orgQhull

#//!\name Global functions

using std::ostream;
using orgQhull::QhullPoint;
using orgQhull::QhullPoints;
using orgQhull::QhullPointsIterator;

ostream &
operator<<(ostream &os, const QhullPoints &p)
{
    QhullPointsIterator i(p);
    while(i.hasNext()){
        os << i.next();
    }
    return os;
}//operator<  // ptrdiff_t, size_t
#include 

namespace orgQhull {

#//!\name Defined here
    class QhullPoints;          //!< One or more points Coordinate pointers with dimension and iterators
    class QhullPointsIterator;  //!< Java-style iterator

//! QhullPoints are an array of QhullPoint as pointers into an array of coordinates.
//! For Qhull/QhullQh, QhullPoints must use hull_dim.  Can change QhullPoint to input_dim if needed for Delaunay input site
class QhullPoints {

private:
#//!\name Fields
    coordT *            point_first; //!< First coordinate of an array of points of point_dimension
    coordT *            point_end;   //!< End of point coordinates (end>=first).  Trailing coordinates ignored
    QhullQh *           qh_qh;       //!< Maybe initialized NULL to allow ownership by RboxPoints
                                     //!< qh_qh used for QhullPoint() and qh_qh->hull_dim in constructor
    int                 point_dimension;  //!< Dimension, >=0

public:
#//!\name Subtypes
    class const_iterator;
    class iterator;
    typedef QhullPoints::const_iterator ConstIterator;
    typedef QhullPoints::iterator       Iterator;

#//!\name Construct
    //! QhullPoint, PointCoordinates, and QhullPoints have similar constructors
    //! If Qhull/QhullQh is not initialized, then QhullPoints.dimension() is zero unless explicitly set
    //! Cannot define QhullPoints(int pointDimension) since it is ambiguous with QhullPoints(QhullQh *qqh)
                        QhullPoints() : point_first(0), point_end(0), qh_qh(0), point_dimension(0) { }
                        QhullPoints(int pointDimension, countT coordinateCount2, coordT *c) : point_first(c), point_end(c+coordinateCount2), qh_qh(0), point_dimension(pointDimension) { QHULL_ASSERT(pointDimension>=0); }
    explicit            QhullPoints(const Qhull &q);
                        QhullPoints(const Qhull &q, countT coordinateCount2, coordT *c);
                        QhullPoints(const Qhull &q, int pointDimension, countT coordinateCount2, coordT *c);
    explicit            QhullPoints(QhullQh *qqh) : point_first(0), point_end(0), qh_qh(qqh), point_dimension(qqh ? qqh->hull_dim : 0) { }
                        QhullPoints(QhullQh *qqh, countT coordinateCount2, coordT *c) : point_first(c), point_end(c+coordinateCount2), qh_qh(qqh), point_dimension(qqh ? qqh->hull_dim : 0) { QHULL_ASSERT(qqh && qqh->hull_dim>0); }
                        QhullPoints(QhullQh *qqh, int pointDimension, countT coordinateCount2, coordT *c);
                        //! Copy constructor copies pointers but not contents.  Needed for return by value and parameter passing.
                        QhullPoints(const QhullPoints &other)  : point_first(other.point_first), point_end(other.point_end), qh_qh(other.qh_qh), point_dimension(other.point_dimension) {}
    QhullPoints &       operator=(const QhullPoints &other) { point_first= other.point_first; point_end= other.point_end; qh_qh= other.qh_qh; point_dimension= other.point_dimension; return *this; }
                        ~QhullPoints() {}

public:

#//!\name Conversion

#ifndef QHULL_NO_STL
    std::vector toStdVector() const;
#endif //QHULL_NO_STL
#ifdef QHULL_USES_QT
    QList   toQList() const;
#endif //QHULL_USES_QT

#//!\name GetSet
    // Constructs QhullPoint.  Cannot return reference.
    const QhullPoint    at(countT idx) const { /* point_first==0 caught by point_end assert */ coordT *p= point_first+idx*point_dimension; QHULL_ASSERT(p(point_end-point_first); } // WARN64
    countT              count() const { return static_cast(size()); } // WARN64
    const coordT *      data() const { return point_first; }
    coordT *            data() { return point_first; }
    void                defineAs(int pointDimension, countT coordinatesCount, coordT *c) { QHULL_ASSERT(pointDimension>=0 && coordinatesCount>=0 && c!=0); point_first= c; point_end= c+coordinatesCount; point_dimension= pointDimension; }
    void                defineAs(countT coordinatesCount, coordT *c) { QHULL_ASSERT((point_dimension>0 && coordinatesCount>=0 && c!=0) || (c==0 && coordinatesCount==0)); point_first= c; point_end= c+coordinatesCount; }
    void                defineAs(const QhullPoints &other) { point_first= other.point_first; point_end= other.point_end; qh_qh= other.qh_qh; point_dimension= other.point_dimension; }
    int                 dimension() const { return point_dimension; }
    ConstIterator       end() const { return ConstIterator(qh_qh, point_dimension, point_end); }
    Iterator            end() { return Iterator(qh_qh, point_dimension, point_end); }
    coordT *            extraCoordinates() const { return (extraCoordinatesCount() ? (point_end-extraCoordinatesCount()) : 0); }
    countT              extraCoordinatesCount() const;  // WARN64
    // Constructs QhullPoint.  Cannot return reference.
    const QhullPoint    first() const { return QhullPoint(qh_qh, point_dimension, point_first); }
    QhullPoint          first() { return QhullPoint(qh_qh, point_dimension, point_first); }
    // Constructs QhullPoint.  Cannot return reference.
    const QhullPoint    front() const { return first(); }
    QhullPoint          front() { return first(); }
    bool                includesCoordinates(const coordT *c) const { return (c>=point_first && c(other)); return *this; }

        // Need 'const QhullPoint' to maintain const
        const QhullPoint & operator*() const { return *this; }
        QhullPoint &    operator*() { return *this; }
        const QhullPoint * operator->() const { return this; }
        QhullPoint *    operator->() { return this; }
        // value instead of reference since advancePoint() modifies self
        QhullPoint      operator[](countT idx) const { QhullPoint result= *this; result.advancePoint(idx); return result; }
        bool            operator==(const iterator &o) const { QHULL_ASSERT(qh_qh==o.qh_qh); return (point_coordinates==o.point_coordinates && point_dimension==o.point_dimension); }
        bool            operator!=(const iterator &o) const { return (! operator==(o)); }
        bool            operator<(const iterator &o) const  { QHULL_ASSERT(qh_qh==o.qh_qh); return point_coordinates < o.point_coordinates; }
        bool            operator<=(const iterator &o) const { QHULL_ASSERT(qh_qh==o.qh_qh); return point_coordinates <= o.point_coordinates; }
        bool            operator>(const iterator &o) const  { QHULL_ASSERT(qh_qh==o.qh_qh); return point_coordinates > o.point_coordinates; }
        bool            operator>=(const iterator &o) const { QHULL_ASSERT(qh_qh==o.qh_qh); return point_coordinates >= o.point_coordinates; }
        // reinterpret_cast to break circular dependency
        bool            operator==(const QhullPoints::const_iterator &o) const { QHULL_ASSERT(qh_qh==reinterpret_cast(o).qh_qh); return (point_coordinates==reinterpret_cast(o).point_coordinates && point_dimension==reinterpret_cast(o).point_dimension); }
        bool            operator!=(const QhullPoints::const_iterator &o) const { return (! operator==(reinterpret_cast(o))); }
        bool            operator<(const QhullPoints::const_iterator &o) const  { QHULL_ASSERT(qh_qh==reinterpret_cast(o).qh_qh); return point_coordinates < reinterpret_cast(o).point_coordinates; }
        bool            operator<=(const QhullPoints::const_iterator &o) const { QHULL_ASSERT(qh_qh==reinterpret_cast(o).qh_qh); return point_coordinates <= reinterpret_cast(o).point_coordinates; }
        bool            operator>(const QhullPoints::const_iterator &o) const  { QHULL_ASSERT(qh_qh==reinterpret_cast(o).qh_qh); return point_coordinates > reinterpret_cast(o).point_coordinates; }
        bool            operator>=(const QhullPoints::const_iterator &o) const { QHULL_ASSERT(qh_qh==reinterpret_cast(o).qh_qh); return point_coordinates >= reinterpret_cast(o).point_coordinates; }
        iterator &      operator++() { advancePoint(1); return *this; }
        iterator        operator++(int) { iterator n= *this; operator++(); return iterator(n); }
        iterator &      operator--() { advancePoint(-1); return *this; }
        iterator        operator--(int) { iterator n= *this; operator--(); return iterator(n); }
        iterator &      operator+=(countT idx) { advancePoint(idx); return *this; }
        iterator &      operator-=(countT idx) { advancePoint(-idx); return *this; }
        iterator        operator+(countT idx) const { iterator n= *this; n.advancePoint(idx); return n; }
        iterator        operator-(countT idx) const { iterator n= *this; n.advancePoint(-idx); return n; }
        difference_type operator-(iterator o) const { QHULL_ASSERT(qh_qh==o.qh_qh && point_dimension==o.point_dimension); return (point_dimension ? (point_coordinates-o.point_coordinates)/point_dimension : 0); }
    };//QhullPoints::iterator

#//!\name QhullPoints::const_iterator
    //!\todo QH11018 FIX: const_iterator same as iterator.  SHould have a common definition
    class const_iterator : public QhullPoint {

    public:
        typedef std::random_access_iterator_tag  iterator_category;
        typedef QhullPoint          value_type;
        typedef const value_type *  pointer;
        typedef const value_type &  reference;
        typedef ptrdiff_t           difference_type;

                        const_iterator(const QhullPoints::iterator &o) : QhullPoint(*o) {}
        explicit        const_iterator(const QhullPoints &ps) : QhullPoint(ps.qh(), ps.dimension(), ps.coordinates()) {}
                        const_iterator(const int pointDimension, coordT *c): QhullPoint(pointDimension, c) {}
                        const_iterator(const Qhull &q, coordT *c): QhullPoint(q, c) {}
                        const_iterator(const Qhull &q, int pointDimension, coordT *c): QhullPoint(q, pointDimension, c) {}
                        const_iterator(QhullQh *qqh, coordT *c): QhullPoint(qqh, c) {}
                        const_iterator(QhullQh *qqh, int pointDimension, coordT *c): QhullPoint(qqh, pointDimension, c) {}
                        const_iterator(const const_iterator &o) : QhullPoint(*o) {}
        const_iterator &operator=(const const_iterator &o) { defineAs(const_cast(o)); return *this; }

        // value/non-const since advancePoint(1), etc. modifies self
        const QhullPoint & operator*() const { return *this; }
        const QhullPoint * operator->() const { return this; }
        // value instead of reference since advancePoint() modifies self
        const QhullPoint operator[](countT idx) const { QhullPoint n= *this; n.advancePoint(idx); return n; }
        bool            operator==(const const_iterator &o) const { QHULL_ASSERT(qh_qh==o.qh_qh); return (point_coordinates == o.point_coordinates && point_dimension==o.point_dimension); }
        bool            operator!=(const const_iterator &o) const { return (! operator==(o)); }
        bool            operator<(const const_iterator &o) const  { QHULL_ASSERT(qh_qh==o.qh_qh); return (point_coordinates < o.point_coordinates); }
        bool            operator<=(const const_iterator &o) const { QHULL_ASSERT(qh_qh==o.qh_qh); return (point_coordinates <= o.point_coordinates); }
        bool            operator>(const const_iterator &o) const  { QHULL_ASSERT(qh_qh==o.qh_qh); return (point_coordinates > o.point_coordinates); }
        bool            operator>=(const const_iterator &o) const { QHULL_ASSERT(qh_qh==o.qh_qh); return (point_coordinates >= o.point_coordinates); }
        const_iterator &operator++() { advancePoint(1); return *this; }
        const_iterator  operator++(int) { const_iterator n= *this; operator++(); return const_iterator(n); }
        const_iterator &operator--() { advancePoint(-1); return *this; }
        const_iterator  operator--(int) { const_iterator n= *this; operator--(); return const_iterator(n); }
        const_iterator &operator+=(countT idx) { advancePoint(idx); return *this; }
        const_iterator &operator-=(countT idx) { advancePoint(-idx); return *this; }
        const_iterator  operator+(countT idx) const { const_iterator n= *this; n.advancePoint(idx); return n; }
        const_iterator  operator-(countT idx) const { const_iterator n= *this; n.advancePoint(-idx); return n; }
        difference_type operator-(const_iterator o) const { QHULL_ASSERT(qh_qh==o.qh_qh && point_dimension==o.point_dimension); return (point_dimension ? (point_coordinates-o.point_coordinates)/point_dimension : 0); }
    };//QhullPoints::const_iterator

#//!\name IO
    struct PrintPoints{
        const QhullPoints  *points;
        const char *    point_message;
        bool            with_identifier;
        PrintPoints(const char *message, bool withIdentifier, const QhullPoints &ps) : points(&ps), point_message(message), with_identifier(withIdentifier) {}
    };//PrintPoints
    PrintPoints          print(const char *message) const { return PrintPoints(message, false, *this); }
    PrintPoints          printWithIdentifier(const char *message) const { return PrintPoints(message, true, *this); }
};//QhullPoints


//! QhullPointsIterator is a Java-style iterator.  It may be used on temporary results.  It copies the pointers in QhullPoints
//! Did not use QHULL_DECLARE_SEQUENTIAL_ITERATOR because next(),etc cannot return a reference to a temporary
class QhullPointsIterator
{
    typedef QhullPoints::const_iterator const_iterator;

#//!\name Fields
private:
    QhullPoints         ps;
    const_iterator      i;

public:
                        QhullPointsIterator(const QhullPoints &other) : ps(other), i(ps.constBegin()) {}
    QhullPointsIterator &operator=(const QhullPoints &other) { ps= other; i= ps.constBegin(); return *this; }

    bool                findNext(const QhullPoint &t);
    bool                findPrevious(const QhullPoint &t);
    bool                hasNext() const { return i != ps.constEnd(); }
    bool                hasPrevious() const { return i != ps.constBegin(); }
    QhullPoint          next() { return *i++; }
    QhullPoint          peekNext() const { return *i; }
    QhullPoint          peekPrevious() const { const_iterator p= i; return *--p; }
    QhullPoint          previous() { return *--i; }
    void                toBack() { i= ps.constEnd(); }
    void                toFront() { i= ps.constBegin(); }
};//QhullPointsIterator

}//namespace orgQhull

#//!\name Global

std::ostream &          operator<<(std::ostream &os, const orgQhull::QhullPoints &p);
std::ostream &          operator<<(std::ostream &os, const orgQhull::QhullPoints::PrintPoints &pr);

#endif // QHULLPOINTS_H
qhull-2020.2/src/libqhullcpp/QhullPointSet.cpp0000644060175106010010000000271513661631133017563 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2009-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullPointSet.cpp#2 $$Change: 2953 $
** $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
**
****************************************************************************/

#include "libqhullcpp/QhullPointSet.h"

#include 
#include 

#ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
#endif

namespace orgQhull {

// Implemented via QhullSet.h

}//namespace orgQhull

#//!\name Global functions

using std::endl;
using std::ostream;
using orgQhull::QhullPoint;
using orgQhull::QhullPointSet;
using orgQhull::QhullPointSetIterator;

ostream &
operator<<(ostream &os, const QhullPointSet::PrintIdentifiers &pr)
{
    os << pr.print_message;
    const QhullPointSet s= *pr.point_set;
    QhullPointSetIterator i(s);
    while(i.hasNext()){
        if(i.hasPrevious()){
            os << " ";
        }
        const QhullPoint point= i.next();
        countT id= point.id();
        os << "p" << id;

    }
    os << endl;
    return os;
}//PrintIdentifiers

ostream &
operator<<(ostream &os, const QhullPointSet::PrintPointSet &pr)
{
    os << pr.print_message;
    const QhullPointSet s= *pr.point_set;
    for(QhullPointSet::const_iterator i=s.begin(); i != s.end(); ++i){
        const QhullPoint point= *i;
        os << point;
    }
    return os;
}//printPointSet


qhull-2020.2/src/libqhullcpp/QhullPointSet.h0000644060175106010010000000576713706446211017243 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2009-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullPointSet.h#3 $$Change: 3001 $
** $DateTime: 2020/07/24 20:43:28 $$Author: bbarber $
**
****************************************************************************/

#ifndef QHULLPOINTSET_H
#define QHULLPOINTSET_H

#include "libqhull_r/qhull_ra.h"
#include "libqhullcpp/QhullSet.h"
#include "libqhullcpp/QhullPoint.h"

#include 

namespace orgQhull {

#//!\name Used here
    class Qhull;
    class QhullPoint;

#//!\name Defined here
    //! QhullPointSet -- a set of coordinate pointers with input dimension
    //! Includes const_iterator and iterator
    class QhullPointSet;

    //! QhullPointSetIterator is a Java-style iterator for QhullPoint in a QhullPointSet
    //! QhullPointSetIterator may be used on temporary results.  It copies the pointers in QhullPointSet
    typedef QhullSetIterator  QhullPointSetIterator;

class QhullPointSet : public QhullSet {

private:
#//!\name Fields
    // no fields
public:

#//!\name Construct
                        QhullPointSet(const Qhull &q, setT *s) : QhullSet(q, s) {}
                        //Conversion from setT* is not type-safe.  Implicit conversion for void* to T
                        QhullPointSet(QhullQh *qqh, setT *s) : QhullSet(qqh, s) {}
                        //Copy constructor copies pointer but not contents.  Needed for return by value and parameter passing.
                        QhullPointSet(const QhullPointSet &other) : QhullSet(other) {}
                        //!Assignment copies pointers but not contents.
    QhullPointSet &     operator=(const QhullPointSet &other) { QhullSet::operator=(other); return *this; }
                        ~QhullPointSet() {}

                        //!Default constructor disabled.
private:
                        QhullPointSet();
public:

#//!\name IO
    struct PrintIdentifiers{
        const QhullPointSet *point_set;
        const char *    print_message; //!< non-null message
        PrintIdentifiers(const char *message, const QhullPointSet *s) : point_set(s), print_message(message) {}
    };//PrintIdentifiers
    PrintIdentifiers printIdentifiers(const char *message) const { return PrintIdentifiers(message, this); }

    struct PrintPointSet{
        const QhullPointSet *point_set;
        const char *    print_message;  //!< non-null message
        PrintPointSet(const char *message, const QhullPointSet &s) : point_set(&s), print_message(message) {}
    };//PrintPointSet
    PrintPointSet       print(const char *message) const { return PrintPointSet(message, *this); }

};//QhullPointSet

}//namespace orgQhull

#//!\name Global

std::ostream &operator<<(std::ostream &os, const orgQhull::QhullPointSet::PrintIdentifiers &pr);
std::ostream &operator<<(std::ostream &os, const orgQhull::QhullPointSet::PrintPointSet &pr);

#endif // QHULLPOINTSET_H
qhull-2020.2/src/libqhullcpp/QhullQh.cpp0000644060175106010010000001132013710644251016356 0ustar  bbarber
/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullQh.cpp#7 $$Change: 3009 $
** $DateTime: 2020/07/30 19:25:22 $$Author: bbarber $
**
****************************************************************************/

#//! QhullQh -- Qhull's global data structure, qhT, as a C++ class


#include "libqhullcpp/QhullQh.h"

#include "libqhullcpp/QhullError.h"
#include "libqhullcpp/QhullStat.h"

#include 
#include 

#include 

using std::cerr;
using std::string;
using std::vector;
using std::ostream;

#ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
#pragma warning( disable : 4611)  // interaction between '_setjmp' and C++ object destruction is non-portable
#pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
#endif

namespace orgQhull {

#//!\name Global variables
const double QhullQh::
default_factor_epsilon= 1.0;

#//!\name Constructor, destructor, etc.

//! Derived from qh_new_qhull[user.c]
QhullQh::
QhullQh()
: qhull_status(qh_ERRnone)
, qhull_message()
, error_stream(0)
, output_stream(0)
, factor_epsilon(QhullQh::default_factor_epsilon)
, use_output_stream(false)
{
    // NOerrors: TRY_QHULL_ not needed since these routines do not call qh_errexit()
    qh_meminit(this, NULL);
    qh_initstatistics(this);
    qh_initqhull_start2(this, NULL, NULL, qh_FILEstderr);  // Initialize qhT
    this->ISqhullQh= True;
}//QhullQh

QhullQh::
~QhullQh()
{
    checkAndFreeQhullMemory();
}//~QhullQh

#//!\name Methods

//! Check memory for internal consistency
//! Free global memory used by qh_initbuild and qh_buildhull
//! Zero the qhT data structure, except for memory (qhmemT) and statistics (qhstatT)
//! Check and free short memory (e.g., facetT)
//! Zero the qhmemT data structure
void QhullQh::
checkAndFreeQhullMemory()
{
#ifdef qh_NOmem
    qh_freeqhull(this, qh_ALL);
#else
    qh_memcheck(this);
    qh_freeqhull(this, !qh_ALL);
    countT curlong;
    countT totlong;
    qh_memfreeshort(this, &curlong, &totlong);
    if(curlong || totlong)
        throw QhullError(10026, "Qhull error: qhull did not free %d bytes of long memory (%d pieces).", totlong, curlong);
#endif
}//checkAndFreeQhullMemory

#//!\name Messaging

void QhullQh::
appendQhullMessage(const string &s)
{
    if(output_stream && use_output_stream && this->USEstdout){
        *output_stream << s;
    }else if(error_stream){
        *error_stream << s;
    }else{
        qhull_message += s;
    }
}//appendQhullMessage

//! clearQhullMessage does not throw errors (~Qhull)
void QhullQh::
clearQhullMessage()
{
    qhull_status= qh_ERRnone;
    qhull_message.clear();
    RoadError::clearGlobalLog();
}//clearQhullMessage

//! hasQhullMessage does not throw errors (~Qhull)
bool QhullQh::
hasQhullMessage() const
{
    return (!qhull_message.empty() || qhull_status!=qh_ERRnone);
    // QH11006 FIX: inconsistent usage with Rbox.  hasRboxMessage just tests rbox_status.  No appendRboxMessage()
}

void QhullQh::
maybeThrowQhullMessage(int exitCode)
{
    if(!NOerrexit){
        if(qhull_message.size()>0){
            qhull_message.append("\n");
        }
        if(exitCode || qhull_status==qh_ERRnone){
            qhull_status= 10073;
        }else{
            qhull_message.append("QH10073: ");
        }
        qhull_message.append("Cannot call maybeThrowQhullMessage() from QH_TRY_().  Or missing 'qh->NOerrexit=true;' after QH_TRY_(){...}.");
    }
    if(qhull_status==qh_ERRnone){
        qhull_status= exitCode;
    }
    if(qhull_status!=qh_ERRnone){
        QhullError e(qhull_status, qhull_message);
        clearQhullMessage();
        throw e; // QH11007 FIX: copy constructor is expensive if logging
    }
}//maybeThrowQhullMessage

void QhullQh::
maybeThrowQhullMessage(int exitCode, int noThrow)  throw()
{
    QHULL_UNUSED(noThrow);

    if(qhull_status==qh_ERRnone){
        qhull_status= exitCode;
    }
    if(qhull_status!=qh_ERRnone){
        QhullError e(qhull_status, qhull_message);
        e.logErrorLastResort();
    }
}//maybeThrowQhullMessage

//! qhullMessage does not throw errors (~Qhull)
std::string QhullQh::
qhullMessage() const
{
    if(qhull_message.empty() && qhull_status!=qh_ERRnone){
        return "qhull: no message for error.  Check cerr or error stream\n";
    }else{
        return qhull_message;
    }
}//qhullMessage

int QhullQh::
qhullStatus() const
{
    return qhull_status;
}//qhullStatus

void QhullQh::
setErrorStream(ostream *os)
{
    error_stream= os;
}//setErrorStream

//! Updates use_output_stream
void QhullQh::
setOutputStream(ostream *os)
{
    output_stream= os;
    use_output_stream= (os!=0);
}//setOutputStream

}//namespace orgQhull

qhull-2020.2/src/libqhullcpp/QhullQh.h0000644060175106010010000001031713666017534016040 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullQh.h#3 $$Change: 2963 $
** $DateTime: 2020/06/03 19:31:01 $$Author: bbarber $
**
****************************************************************************/

#ifndef QHULLQH_H
#define QHULLQH_H

#include "libqhull_r/qhull_ra.h"

#include 

#ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
#pragma warning( disable : 4611)  /* interaction between '_setjmp' and C++ object destruction is non-portable */
/* setjmp should not be implemented with 'catch' */
#endif

//! Use QH_TRY_ or QH_TRY_NOTHROW_ to call a libqhull_r routine that may invoke qh_errexit()
//! QH_TRY_(qh){...} qh->NOerrexit=true;
//! No object creation -- longjmp() skips object destructors
//! To test for error when done -- qh->maybeThrowQhullMessage(QH_TRY_status);
//! Use the same compiler for QH_TRY_, libqhullcpp, and libqhull_r.  setjmp() is not portable between compilers.

#define QH_TRY_ERROR 10071

#define QH_TRY_(qh) \
    int QH_TRY_status; \
    if(qh->NOerrexit){ \
        qh->NOerrexit= False; \
        QH_TRY_status= setjmp(qh->errexit); \
    }else{ \
        throw QhullError(QH_TRY_ERROR, "Cannot invoke QH_TRY_() from inside a QH_TRY_.  Or missing 'qh->NOerrexit=true' after previously called QH_TRY_(qh){...}"); \
    } \
    if(!QH_TRY_status)

#define QH_TRY_NO_THROW_(qh) \
    int QH_TRY_status; \
    if(qh->NOerrexit){ \
        qh->NOerrexit= False; \
        QH_TRY_status= setjmp(qh->errexit); \
    }else{ \
        QH_TRY_status= QH_TRY_ERROR; \
    } \
    if(!QH_TRY_status)

namespace orgQhull {

#//!\name Defined here
    //! QhullQh -- Qhull's global data structure, qhT, as a C++ class
    class QhullQh;

//! POD type equivalent to qhT.  No virtual members
class QhullQh : public qhT {

#//!\name Constants

#//!\name Fields
private:
    int                 qhull_status;   //!< qh_ERRnone if valid
    std::string         qhull_message;  //!< Returned messages from libqhull_r
    std::ostream *      error_stream;   //!< overrides errorMessage, use appendQhullMessage()
    std::ostream *      output_stream;  //!< send output to stream
    double              factor_epsilon; //!< Factor to increase ANGLEround and DISTround for hyperplane equality
    bool                use_output_stream; //!< True if using output_stream

    //! modified by qh_fprintf in QhullUser.cpp
    friend void         ::qh_fprintf(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... );

    static const double default_factor_epsilon;  //!< Default factor_epsilon is 1.0, never updated

#//!\name Constructors
public:
                        QhullQh();
                        ~QhullQh();
private:
                        //!disable copy constructor and assignment
                        QhullQh(const QhullQh &);
    QhullQh &           operator=(const QhullQh &);
public:

#//!\name GetSet
    double              factorEpsilon() const { return factor_epsilon; }
    void                setFactorEpsilon(double a) { factor_epsilon= a; }
    void                disableOutputStream() { use_output_stream= false; }
    void                enableOutputStream() { use_output_stream= true; }

#//!\name Messaging
    void                appendQhullMessage(const std::string &s);
    void                clearQhullMessage();
    std::string         qhullMessage() const;
    bool                hasOutputStream() const { return use_output_stream; }
    bool                hasQhullMessage() const;
    void                maybeThrowQhullMessage(int exitCode);
    void                maybeThrowQhullMessage(int exitCode, int noThrow) throw();
    int                 qhullStatus() const;
    void                setErrorStream(std::ostream *os);
    void                setOutputStream(std::ostream *os);

#//!\name Methods
    double              angleEpsilon() const { return this->ANGLEround*factor_epsilon; } //!< Epsilon for hyperplane angle equality
    void                checkAndFreeQhullMemory();
    double              distanceEpsilon() const { return this->DISTround*factor_epsilon; } //!< Epsilon for distance to hyperplane

};//class QhullQh

}//namespace orgQhull

#endif // QHULLQH_H
qhull-2020.2/src/libqhullcpp/QhullRidge.cpp0000644060175106010010000000733413661631133017052 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullRidge.cpp#2 $$Change: 2953 $
** $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
**
****************************************************************************/

#//! QhullRidge -- Qhull's ridge structure, ridgeT, as a C++ class

#include "libqhullcpp/QhullRidge.h"

#include "libqhullcpp/QhullSets.h"
#include "libqhullcpp/QhullVertex.h"
#include "libqhullcpp/Qhull.h"

#ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
#pragma warning( disable : 4611)  // interaction between '_setjmp' and C++ object destruction is non-portable
#pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
#endif

namespace orgQhull {

#//!\name Class objects
ridgeT QhullRidge::
s_empty_ridge= {NULL,NULL,NULL,0,    // must match ridgeT -Wmissing-field-initializers
                false,false,false,false,false,false,false};

#//!\name Constructors

QhullRidge::QhullRidge(const Qhull &q)
: qh_ridge(&s_empty_ridge)
, qh_qh(q.qh())
{
}//Default

QhullRidge::QhullRidge(const Qhull &q, ridgeT *r)
: qh_ridge(r ? r : &s_empty_ridge)
, qh_qh(q.qh())
{
}//ridgeT

#//!\name foreach

//! Return True if nextRidge3d
//! Simplicial facets may have incomplete ridgeSets
//! Does not use qh_errexit()
bool QhullRidge::
hasNextRidge3d(const QhullFacet &f) const
{
    if(!qh_qh){
        return false;
    }
    vertexT *v= 0;
    // Does not call qh_errexit(), TRY_QHULL_ not needed
    ridgeT *ridge= qh_nextridge3d(getRidgeT(), f.getFacetT(), &v);
    return (ridge!=0);
}//hasNextRidge3d

//! Return next ridge and optional vertex for a 3d facet and ridge
//! Does not use qh_errexit()
QhullRidge QhullRidge::
nextRidge3d(const QhullFacet &f, QhullVertex *nextVertex) const
{
    vertexT *v= 0;
    ridgeT *ridge= 0;
    if(qh_qh){
        // Does not call qh_errexit(), TRY_QHULL_ not needed
        ridge= qh_nextridge3d(getRidgeT(), f.getFacetT(), &v);
        if(!ridge){
            throw QhullError(10030, "Qhull error nextRidge3d:  missing next ridge for facet %d ridge %d.  Does facet contain ridge?", f.id(), id());
        }
    }
    if(nextVertex!=0){
        *nextVertex= QhullVertex(qh_qh, v);
    }
    return QhullRidge(qh_qh, ridge);
}//nextRidge3d

}//namespace orgQhull

#//!\name Global functions

using std::endl;
using std::ostream;
using orgQhull::QhullRidge;
using orgQhull::QhullVertex;

ostream &
operator<<(ostream &os, const QhullRidge &r)
{
    os << r.print("");
    return os;
}//<< QhullRidge

//! Duplicate of qh_printridge [io_r.c]
ostream &
operator<<(ostream &os, const QhullRidge::PrintRidge &pr)
{
    if(*pr.print_message){
        os << pr.print_message << " ";
    }else{
        os << "     - ";
    }
    QhullRidge r= *pr.ridge;
    os << "r" << r.id();
    if(r.getRidgeT()->tested){
        os << " tested";
    }
    if(r.getRidgeT()->nonconvex){
        os << " nonconvex";
    }
    if(r.getRidgeT()->mergevertex){
      os << " mergevertex";
    }
    if(r.getRidgeT()->mergevertex2){
      os << " mergevertex2";
    }
    if(r.getRidgeT()->simplicialtop){
      os << " simplicialtop";
    }
    if(r.getRidgeT()->simplicialbot){
      os << " simplicialbot";
    }
    os << endl;
    os << r.vertices().print("           vertices:");
    if(r.getRidgeT()->top && r.getRidgeT()->bottom){
        os << "           between f" << r.topFacet().id() << " and f" << r.bottomFacet().id() << endl;
    }else if(r.getRidgeT()->top){
        os << "           top f" << r.topFacet().id() << endl;
    }else if(r.getRidgeT()->bottom){
        os << "           bottom f" << r.bottomFacet().id() << endl;
    }

    return os;
}//<< PrintRidge
qhull-2020.2/src/libqhullcpp/QhullRidge.h0000644060175106010010000001203513706446530016516 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullRidge.h#4 $$Change: 3001 $
** $DateTime: 2020/07/24 20:43:28 $$Author: bbarber $
**
****************************************************************************/

#ifndef QHULLRIDGE_H
#define QHULLRIDGE_H

#include "libqhull_r/qhull_ra.h"
#include "libqhullcpp/QhullSet.h"
#include "libqhullcpp/QhullVertex.h"
#include "libqhullcpp/QhullVertexSet.h"
#include "libqhullcpp/QhullFacet.h"

#include 

namespace orgQhull {

#//!\name Used here
    class Qhull;
    class QhullVertex;
    class QhullVertexSet;
    class QhullFacet;

#//!\name Defined here
    //! QhullRidge -- Qhull's ridge structure, ridgeT [libqhull.h], as a C++ class
    class QhullRidge;

    typedef QhullSet  QhullRidgeSet;

    //! QhullRidgeSetIterator is a Java-style iterator for QhullRidge in a QhullRidgeSet
    //! QhullRidgeSetIterator may be used on temporary results.  It copies the pointers in QhullRidgeSet
    //! Use QhullSets.h to avoid circular references to QhullRidgeSet and QhullRidgeSetIterator
    typedef QhullSetIterator  QhullRidgeSetIterator;

/************************
a ridge is hull_dim-1 simplex between two neighboring facets.  If the
facets are non-simplicial, there may be more than one ridge between
two facets.  E.G. a 4-d hypercube has two triangles between each pair
of neighboring facets.

topological information:
    vertices            a set of vertices
    top,bottom          neighboring facets with orientation

geometric information:
    tested              True if ridge is clearly convex
    nonconvex           True if ridge is non-convex
*/

class QhullRidge {

#//!\name Defined here
public:
    typedef ridgeT *   base_type;  // for QhullRidgeSet

#//!\name Fields
private:
    ridgeT *            qh_ridge;  //!< Corresponding ridgeT, never 0
    QhullQh *           qh_qh;     //!< QhullQh/qhT for ridgeT, may be 0

#//!\name Class objects
    static ridgeT       s_empty_ridge;

public:
#//!\name Constants

#//!\name Constructors
                        QhullRidge() : qh_ridge(&s_empty_ridge), qh_qh(0) {}
    explicit            QhullRidge(const Qhull &q);
                        QhullRidge(const Qhull &q, ridgeT *r);
    explicit            QhullRidge(QhullQh *qqh) : qh_ridge(&s_empty_ridge), qh_qh(qqh) {}
                        QhullRidge(QhullQh *qqh, ridgeT *r) : qh_ridge(r ? r : &s_empty_ridge), qh_qh(qqh) {}
                        // Creates an alias.  Does not copy QhullRidge.  Needed for return by value and parameter passing
                        QhullRidge(const QhullRidge &other) : qh_ridge(other.qh_ridge), qh_qh(other.qh_qh) {}
                        // Creates an alias.  Does not copy QhullRidge.  Needed for vector
    QhullRidge &        operator=(const QhullRidge &other) { qh_ridge= other.qh_ridge; qh_qh= other.qh_qh; return *this; }
                        ~QhullRidge() {}

#//!\name GetSet
    QhullFacet          bottomFacet() const { return QhullFacet(qh_qh, qh_ridge->bottom); }
    int                 dimension() const { return ((qh_qh && qh_qh->hull_dim) ? qh_qh->hull_dim-1 : 0); }
    ridgeT *            getBaseT() const { return getRidgeT(); } //!< For QhullSet
    ridgeT *            getRidgeT() const { return qh_ridge; }
    countT              id() const { return qh_ridge->id; }
    bool                isValid() const { return (qh_qh && qh_ridge != &s_empty_ridge); }
    bool                operator==(const QhullRidge &other) const { return qh_ridge==other.qh_ridge; }
    bool                operator!=(const QhullRidge &other) const { return !operator==(other); }
    QhullFacet          otherFacet(const QhullFacet &f) const { return QhullFacet(qh_qh, (qh_ridge->top==f.getFacetT() ? qh_ridge->bottom : qh_ridge->top)); }
    QhullQh *           qh() const { return qh_qh; }
    void                setRidgeT(QhullQh *qqh, ridgeT *ridge) { qh_qh= qqh; qh_ridge= ridge; }
    QhullFacet          topFacet() const { return QhullFacet(qh_qh, qh_ridge->top); }

#//!\name foreach
    bool                hasNextRidge3d(const QhullFacet &f) const;
    QhullRidge          nextRidge3d(const QhullFacet &f) const { return nextRidge3d(f, 0); }
    QhullRidge          nextRidge3d(const QhullFacet &f, QhullVertex *nextVertex) const;
    QhullVertexSet      vertices() const { return QhullVertexSet(qh_qh, qh_ridge->vertices); }

#//!\name IO

    struct PrintRidge{
        const QhullRidge *ridge;
        const char *    print_message;    //!< non-null message
                        PrintRidge(const char *message, const QhullRidge &r) : ridge(&r), print_message(message) {}
    };//PrintRidge
    PrintRidge          print(const char* message) const { return PrintRidge(message, *this); }
};//class QhullRidge

}//namespace orgQhull

std::ostream &operator<<(std::ostream &os, const orgQhull::QhullRidge &r);
std::ostream &operator<<(std::ostream &os, const orgQhull::QhullRidge::PrintRidge &pr);

#endif // QHULLRIDGE_H
qhull-2020.2/src/libqhullcpp/QhullSet.cpp0000644060175106010010000000273313710645347016560 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullSet.cpp#4 $$Change: 3009 $
** $DateTime: 2020/07/30 19:25:22 $$Author: bbarber $
**
****************************************************************************/

#//! QhullSet -- Qhull's set structure, setT, as a C++ class

#include "libqhullcpp/QhullSet.h"

#include "libqhullcpp/Qhull.h"
#include "libqhullcpp/QhullError.h"

#ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
#endif

namespace orgQhull {

#//!\name Class objects

setT QhullSetBase::
s_empty_set;

#//!\name Constructors

QhullSetBase::
QhullSetBase(const Qhull &q, setT *s)
: qh_set(s ? s : &s_empty_set)
, qh_qh(q.qh())
{
}

#//!\name Class methods

// Same code for qh_setsize [qset_r.c] and QhullSetBase::count [static]
countT QhullSetBase::
count(const setT *set)
{
    countT size;
    const setelemT *sizep;

    if(!set){
        return(0);
    }
    sizep= SETsizeaddr_(set);
    if((size= sizep->i)){
        size--;
        if(size > set->maxsize){
            // QH11022 FIX: How to add additional output to a error? -- qh_setprint(qhmem.ferr, "set: ", set);
            throw QhullError(10032, "QhullSet internal error: current set size %d is greater than maximum size %d\n",
                size, set->maxsize);
        }
    }else{
        size= set->maxsize;
    }
    return size;
}//count

}//namespace orgQhull

qhull-2020.2/src/libqhullcpp/QhullSet.h0000644060175106010010000004565713715350473016237 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullSet.h#5 $$Change: 3018 $
** $DateTime: 2020/08/15 19:58:23 $$Author: bbarber $
**
****************************************************************************/

#ifndef QhullSet_H
#define QhullSet_H

#include "libqhull_r/qhull_ra.h"
#include "libqhullcpp/QhullError.h"
#include "libqhullcpp/QhullQh.h"

#include   // ptrdiff_t, size_t

#ifndef QHULL_NO_STL
#include 
#endif

#ifdef QHULL_USES_QT
 #include 
#endif

namespace orgQhull {

#//!\name Used here
    class Qhull;

#//!\name Defined here
    class QhullSetBase;  //! Base class for QhullSet
    //! QhullSet defined below
    //! QhullSetIterator defined below
    //! \see QhullPointSet, QhullLinkedList

//! QhullSetBase is a wrapper for Qhull's setT of void* pointers
//! \see libqhull_r/qset.h
class QhullSetBase {

private:
#//!\name Fields --
    setT *              qh_set;
    QhullQh *           qh_qh;             //! Provides access to setT memory allocator

#//!\name Class objects
    static setT         s_empty_set;  //! Used if setT* is NULL

public:
#//!\name Constructors
                        QhullSetBase(const Qhull &q, setT *s);
                        QhullSetBase(QhullQh *qqh, setT *s) : qh_set(s ? s : &s_empty_set), qh_qh(qqh) {}
                        //! Copy constructor copies the pointer but not the set.  Needed for return by value and parameter passing.
                        QhullSetBase(const QhullSetBase &other) : qh_set(other.qh_set), qh_qh(other.qh_qh) {}
    QhullSetBase &      operator=(const QhullSetBase &other) { qh_set= other.qh_set; qh_qh= other.qh_qh; return *this; }
                        ~QhullSetBase() {}

private:
                        //!disabled since memory allocation for QhullSet not defined
                        QhullSetBase()  : qh_set(NULL), qh_qh(NULL) {}
public:

#//!\name GetSet
    countT              count() const { return QhullSetBase::count(qh_set); }
    void                defineAs(setT *s) { qh_set= s ? s : &s_empty_set; } //!< Not type-safe since setT may contain any type
    void                forceEmpty() { qh_set= &s_empty_set; }
    setT *              getSetT() const { return qh_set; }
    bool                isEmpty() const { return SETempty_(qh_set); }
    QhullQh *           qh() const { return qh_qh; }
    setT **             referenceSetT() { return &qh_set; }
    size_t              size() const { return QhullSetBase::count(qh_set); }

#//!\name Element
protected:
    void **             beginPointer() const { return &qh_set->e[0].p; }
    void **             elementPointer(countT idx) const { QHULL_ASSERT(idx>=0 && idxmaxsize); return &SETelem_(qh_set, idx); }
                        //! Always points to 0
    void **             endPointer() const { return qh_setendpointer(qh_set); }

#//!\name Class methods
public:
    static countT       count(const setT *set);
    //s may be null
    static bool         isEmpty(const setT *s) { return SETempty_(s); }
};//QhullSetBase


//! QhullSet -- A read-only wrapper to Qhull's collection class, setT.
//!  QhullSet is similar to STL's  and Qt's QVector
//!  QhullSet is unrelated to STL and Qt's set and map types (e.g., QSet and QMap)
//!  T is a Qhull type that defines 'base_type' and getBaseT() (e.g., QhullFacet with base_type 'facetT *'
//!  A QhullSet does not own its contents -- erase(), clear(), removeFirst(), removeLast(), pop_back(), pop_front(), fromStdList() not defined
//!  QhullSetIterator is faster than STL-style iterator/const_iterator
//!  Qhull's FOREACHelement_() [qset_r.h] maybe more efficient than QhullSet.  It uses a NULL terminator instead of an end pointer.  STL requires an end pointer.
//!  Derived from QhullLinkedList.h and Qt/core/tools/qlist.h w/o QT_STRICT_ITERATORS
template 
class QhullSet : public QhullSetBase {

private:
#//!\name Fields -- see QhullSetBase

#//!\name Class objects
    static setT         s_empty_set;  //! Workaround for no setT allocator.  Used if setT* is NULL

public:
#//!\name Defined here
    class iterator;
    class const_iterator;
    typedef typename QhullSet::iterator Iterator;
    typedef typename QhullSet::const_iterator ConstIterator;

#//!\name Constructors
                        QhullSet(const Qhull &q, setT *s) : QhullSetBase(q, s) { }
                        QhullSet(QhullQh *qqh, setT *s) : QhullSetBase(qqh, s) { }
                        //Conversion from setT* is not type-safe.  Implicit conversion for void* to T
                        //Copy constructor copies pointer but not contents.  Needed for return by value.
                        QhullSet(const QhullSet &other) : QhullSetBase(other) {}
    QhullSet &       operator=(const QhullSet &other) { QhullSetBase::operator=(other); return *this; }
                        ~QhullSet() {}

private:
                        //!Disable default constructor.  See QhullSetBase
                        QhullSet();
public:

#//!\name Conversion

#ifndef QHULL_NO_STL
    std::vector toStdVector() const;
#endif
#ifdef QHULL_USES_QT
    QList            toQList() const;
#endif

#//!\name GetSet -- see QhullSetBase for count(), empty(), isEmpty(), size()
    using QhullSetBase::count;
    using QhullSetBase::isEmpty;
    // operator== defined for QhullSets of the same type
    bool                operator==(const QhullSet &other) const { return qh_setequal(getSetT(), other.getSetT()); }
    bool                operator!=(const QhullSet &other) const { return !operator==(other); }

#//!\name Element access
    // Constructs T.  Cannot return reference.
    const T             at(countT idx) const { return operator[](idx); }
    // Constructs T.  Cannot return reference.
    const T             back() const { return last(); }
    T                   back() { return last(); }
    //! end element is NULL
    const typename T::base_type * constData() const { return reinterpret_cast(beginPointer()); }
    typename T::base_type *     data() { return reinterpret_cast(beginPointer()); }
    const typename T::base_type *data() const { return reinterpret_cast(beginPointer()); }
    typename T::base_type *     endData() { return reinterpret_cast(endPointer()); }
    const typename T::base_type * endData() const { return reinterpret_cast(endPointer()); }
    // Constructs T.  Cannot return reference.
    const T             first() const { QHULL_ASSERT(!isEmpty()); return T(qh(), *data()); }
    T                   first() { QHULL_ASSERT(!isEmpty()); return T(qh(), *data()); }
    // Constructs T.  Cannot return reference.
    const T             front() const { return first(); }
    T                   front() { return first(); }
    // Constructs T.  Cannot return reference.
    const T             last() const { QHULL_ASSERT(!isEmpty()); return T(qh(), *(endData()-1)); }
    T                   last() { QHULL_ASSERT(!isEmpty()); return T(qh(), *(endData()-1)); }
    // mid() not available.  No setT constructor
    // Constructs T.  Cannot return reference.
    const T             operator[](countT idx) const { const typename T::base_type *p= reinterpret_cast(elementPointer(idx)); QHULL_ASSERT(idx>=0 && p < endData()); return T(qh(), *p); }
    T                   operator[](countT idx) { typename T::base_type *p= reinterpret_cast(elementPointer(idx)); QHULL_ASSERT(idx>=0 && p < endData()); return T(qh(), *p); }
    const T             second() const { return operator[](1); }
    T                   second() { return operator[](1); }
    T                   value(countT idx) const;
    T                   value(countT idx, const T &defaultValue) const;

#//!\name Read-write -- Not available, no setT constructor

#//!\name iterator
    iterator            begin() { return iterator(qh(), reinterpret_cast(beginPointer())); }
    const_iterator      begin() const { return const_iterator(qh(), data()); }
    const_iterator      constBegin() const { return const_iterator(qh(), data()); }
    const_iterator      constEnd() const { return const_iterator(qh(), endData()); }
    iterator            end() { return iterator(qh(), endData()); }
    const_iterator      end() const { return const_iterator(qh(), endData()); }

#//!\name Search
    bool                contains(const T &t) const;
    countT              count(const T &t) const;
    countT              indexOf(const T &t) const { /* no qh_qh */ return qh_setindex(getSetT(), t.getBaseT()); }
    countT              lastIndexOf(const T &t) const;

    // before const_iterator for conversion with comparison operators
    class iterator {
        friend class const_iterator;
    private:
        typename T::base_type *  i;  // e.g., facetT**, first for debugger
        QhullQh *       qh_qh;

    public:
        typedef ptrdiff_t       difference_type;
        typedef std::bidirectional_iterator_tag  iterator_category;
        typedef T               value_type;

                        iterator(QhullQh *qqh, typename T::base_type *p) : i(p), qh_qh(qqh) {}
                        iterator(const iterator &o) : i(o.i), qh_qh(o.qh_qh) {}
        iterator &      operator=(const iterator &o) { i= o.i; qh_qh= o.qh_qh; return *this; }

        // Constructs T.  Cannot return reference.  
        T               operator*() const { return T(qh_qh, *i); }
        //operator->() n/a, value-type
        // Constructs T.  Cannot return reference.  
        T               operator[](countT idx) const { return T(qh_qh, *(i+idx)); } //!< No error checking
        bool            operator==(const iterator &o) const { return i == o.i; }
        bool            operator!=(const iterator &o) const { return !operator==(o); }
        bool            operator==(const const_iterator &o) const { return (i==reinterpret_cast(o).i); }
        bool            operator!=(const const_iterator &o) const { return !operator==(o); }

        //! Assumes same point set
        countT          operator-(const iterator &o) const { return static_cast(i-o.i); } //WARN64
        bool            operator>(const iterator &o) const { return i>o.i; }
        bool            operator<=(const iterator &o) const { return !operator>(o); }
        bool            operator<(const iterator &o) const { return i=(const iterator &o) const { return !operator<(o); }
        bool            operator>(const const_iterator &o) const { return (i > reinterpret_cast(o).i); }
        bool            operator<=(const const_iterator &o) const { return !operator>(o); }
        bool            operator<(const const_iterator &o) const { return (i < reinterpret_cast(o).i); }
        bool            operator>=(const const_iterator &o) const { return !operator<(o); }

        //! No error checking
        iterator &      operator++() { ++i; return *this; }
        iterator        operator++(int) { iterator o= *this; ++i; return o; }
        iterator &      operator--() { --i; return *this; }
        iterator        operator--(int) { iterator o= *this; --i; return o; }
        iterator        operator+(countT j) const { return iterator(qh_qh, i+j); }
        iterator        operator-(countT j) const { return operator+(-j); }
        iterator &      operator+=(countT j) { i += j; return *this; }
        iterator &      operator-=(countT j) { i -= j; return *this; }
    };//QhullPointSet::iterator

    class const_iterator {
    private:
        const typename T::base_type *  i;  // e.g., const facetT**, first for debugger
        QhullQh *       qh_qh;

    public:
        typedef ptrdiff_t       difference_type;
        typedef std::random_access_iterator_tag  iterator_category;
        typedef T               value_type;

                        const_iterator(QhullQh *qqh, const typename T::base_type * p) : i(p), qh_qh(qqh) {}
                        const_iterator(const const_iterator &o) : i(o.i), qh_qh(o.qh_qh) {}
                        const_iterator(const iterator &o) : i(o.i), qh_qh(o.qh_qh) {}
        const_iterator &operator=(const const_iterator &o) { i= o.i; qh_qh= o.qh_qh; return *this; }

        // Constructs T.  Cannot return reference.  Retaining 'const T' return type for consistency with QList/QVector
        const T         operator*() const { return T(qh_qh, *i); }
        const T         operator[](countT idx) const { return T(qh_qh, *(i+idx)); }  //!< No error checking
        //operator->() n/a, value-type
        bool            operator==(const const_iterator &o) const { return i == o.i; }
        bool            operator!=(const const_iterator &o) const { return !operator==(o); }

        //! Assumes same point set
        countT          operator-(const const_iterator &o) { return static_cast(i-o.i); } //WARN64
        bool            operator>(const const_iterator &o) const { return i>o.i; }
        bool            operator<=(const const_iterator &o) const { return !operator>(o); }
        bool            operator<(const const_iterator &o) const { return i=(const const_iterator &o) const { return !operator<(o); }

        //!< No error checking
        const_iterator &operator++() { ++i; return *this; }
        const_iterator  operator++(int) { const_iterator o= *this; ++i; return o; }
        const_iterator &operator--() { --i; return *this; }
        const_iterator  operator--(int) { const_iterator o= *this; --i; return o; }
        const_iterator  operator+(int j) const { return const_iterator(qh_qh, i+j); }
        const_iterator  operator-(int j) const { return operator+(-j); }
        const_iterator &operator+=(int j) { i += j; return *this; }
        const_iterator &operator-=(int j) { i -= j; return *this; }
    };//QhullPointSet::const_iterator

};//class QhullSet


//! QhullSetIterator is a Java-style iterator.  It may be used on temporary results.
//! QhullSetIterator copies the qh_set and qh_qh pointers in QhullSetBase
//! Faster then interator/const_iterator due to T::base_type
template 
class QhullSetIterator {

#//!\name Subtypes
    typedef typename QhullSet::const_iterator const_iterator;

private:
#//!\name Fields
    const typename T::base_type *  i;        // e.g., facetT**, first for debugger
    const typename T::base_type *  begin_i;  // must be initialized after i
    const typename T::base_type *  end_i;
    QhullQh *                qh_qh;

public:
#//!\name Constructors
                        QhullSetIterator(const QhullSet &s) : i(s.data()), begin_i(i), end_i(s.endData()), qh_qh(s.qh()) {}
                        QhullSetIterator(const QhullSetIterator &o) : i(o.i), begin_i(o.begin_i), end_i(o.end_i), qh_qh(o.qh_qh) {}
    QhullSetIterator &operator=(const QhullSetIterator &o) { i= o.i; begin_i= o.begin_i; end_i= o.end_i; qh_qh= o.qh_qh; return *this; }

#//!\name ReadOnly
    countT              countRemaining() { return static_cast(end_i-i); } // WARN64

#//!\name Search
    bool                findNext(const T &t);
    bool                findPrevious(const T &t);

#//!\name Foreach
    bool                hasNext() const { return i != end_i; }
    bool                hasPrevious() const { return i != begin_i; }
    T                   next() { return T(qh_qh, *i++); }
    T                   peekNext() const { return T(qh_qh, *i); }
    T                   peekPrevious() const { const typename T::base_type *p= i; return T(qh_qh, *--p); }
    T                   previous() { return T(qh_qh, *--i); }
    void                toBack() { i= end_i; }
    void                toFront() { i= begin_i; }
};//class QhullSetIterator

#//!\name == Definitions =========================================

#//!\name Conversions

// See qt-qhull.cpp for QList conversion

#ifndef QHULL_NO_STL
template 
std::vector QhullSet::
toStdVector() const
{
    typename QhullSet::const_iterator i= begin();
    typename QhullSet::const_iterator e= end();
    std::vector vs;
    while(i!=e){
        vs.push_back(*i++);
    }
    return vs;
}//toStdVector
#endif //QHULL_NO_STL

#ifdef QHULL_USES_QT
template 
QList QhullSet::
toQList() const
{
    typename QhullSet::const_iterator i= begin();
    typename QhullSet::const_iterator e= end();
    QList vs;
    while(i!=e){
        vs.append(*i++);
    }
    return vs;
}//toQList
#endif

#//!\name Element

template 
T QhullSet::
value(countT idx) const
{
    // Avoid call to qh_setsize() and assert in elementPointer()
    const typename T::base_type *p= reinterpret_cast(&SETelem_(getSetT(), idx));
    return (idx>=0 && p
T QhullSet::
value(countT idx, const T &defaultValue) const
{
    // Avoid call to qh_setsize() and assert in elementPointer()
    const typename T::base_type *p= reinterpret_cast(&SETelem_(getSetT(), idx));
    return (idx>=0 && p
bool QhullSet::
contains(const T &t) const
{
    setT *s= getSetT();
    void *p= t.getBaseT();  // contains() is not inline for better error reporting
    int result= qh_setin(s, p);
    return result!=0;
}//contains

template 
countT QhullSet::
count(const T &t) const
{
    countT n= 0;
    const typename T::base_type *i= data();
    const typename T::base_type *e= endData();
    typename T::base_type p= t.getBaseT();
    while(i
countT QhullSet::
lastIndexOf(const T &t) const
{
    const typename T::base_type *b= data();
    const typename T::base_type *i= endData();
    typename T::base_type p= t.getBaseT();
    while(--i>=b){
        if(*i==p){
            break;
        }
    }
    return static_cast(i-b); // WARN64
}//lastIndexOf

#//!\name QhullSetIterator

template 
bool QhullSetIterator::
findNext(const T &t)
{
    typename T::base_type p= t.getBaseT();
    while(i!=end_i){
        if(*(++i)==p){
            return true;
        }
    }
    return false;
}//findNext

template 
bool QhullSetIterator::
findPrevious(const T &t)
{
    typename T::base_type p= t.getBaseT();
    while(i!=begin_i){
        if(*(--i)==p){
            return true;
        }
    }
    return false;
}//findPrevious

}//namespace orgQhull


#//!\name == Global namespace =========================================

template 
std::ostream &
operator<<(std::ostream &os, const orgQhull::QhullSet &qs)
{
    const typename T::base_type *i= qs.data();
    const typename T::base_type *e= qs.endData();
    while(i!=e){
        os << T(qs.qh(), *i++);
    }
    return os;
}//operator<<

#endif // QhullSet_H
qhull-2020.2/src/libqhullcpp/QhullSets.h0000644060175106010010000000143313661631133016375 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullSets.h#2 $$Change: 2953 $
** $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
**
****************************************************************************/

#ifndef QHULLSETS_H
#define QHULLSETS_H

#include "libqhullcpp/QhullSet.h"

namespace orgQhull {

    //See: QhullFacetSet.h
    //See: QhullPointSet.h
    //See: QhullVertexSet.h

    // Avoid circular references between QhullFacet, QhullRidge, and QhullVertex
    class QhullRidge;
    typedef QhullSet  QhullRidgeSet;
    typedef QhullSetIterator  QhullRidgeSetIterator;

}//namespace orgQhull

#endif // QHULLSETS_H
qhull-2020.2/src/libqhullcpp/QhullStat.cpp0000644060175106010010000000162013661631133016723 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullStat.cpp#2 $$Change: 2953 $
** $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
**
****************************************************************************/

#//! QhullStat -- Qhull's global data structure, statT, as a C++ class

#include "libqhullcpp/QhullStat.h"

#include "libqhullcpp/QhullError.h"

#include 
#include 

using std::cerr;
using std::string;
using std::vector;
using std::ostream;

#ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
#endif

namespace orgQhull {

#//!\name Constructor, destructor, etc.

//! If qh_QHpointer==0, invoke with placement new on qh_stat;
QhullStat::
QhullStat()
{
}//QhullStat

QhullStat::
~QhullStat()
{
}//~QhullStat

}//namespace orgQhull

qhull-2020.2/src/libqhullcpp/QhullStat.h0000644060175106010010000000241413661631133016372 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullStat.h#2 $$Change: 2953 $
** $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
**
****************************************************************************/

#ifndef QHULLSTAT_H
#define QHULLSTAT_H

#include "libqhull_r/qhull_ra.h"

#include 
#include 

namespace orgQhull {

#//!\name defined here
    //! QhullStat -- Qhull's statistics, qhstatT, as a C++ class
    //! Statistics defined with zzdef_() control Qhull's behavior, summarize its result, and report precision problems.
    class QhullStat;

class QhullStat : public qhstatT {

private:
#//!\name Fields (empty) -- POD type equivalent to qhstatT.  No data or virtual members

public:
#//!\name Constants

#//!\name class methods

#//!\name constructor, assignment, destructor, invariant
                        QhullStat();
                        ~QhullStat();

private:
    //!disable copy constructor and assignment
                        QhullStat(const QhullStat &);
    QhullStat &         operator=(const QhullStat &);
public:

#//!\name Access
};//class QhullStat

}//namespace orgQhull

#endif // QHULLSTAT_H
qhull-2020.2/src/libqhullcpp/QhullUser.cpp0000644060175106010010000001716713710402462016737 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullUser.cpp#10 $$Change: 3008 $
** $DateTime: 2020/07/30 13:54:27 $$Author: bbarber $
**
****************************************************************************/

#include "libqhullcpp/QhullUser.h"

#include "libqhullcpp/QhullError.h"

#include 
#include 

using std::cerr;
using std::endl;
using std::istream;
using std::ostream;
using std::ostringstream;
using std::string;
using std::vector;
using std::ws;

#ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
#pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
#endif

namespace orgQhull{

#//! QhullUser -- user-defined interface to qhull via qh_fprintf


#//!\name Constructors
QhullUser::
QhullUser(QhullQh *qqh)
    : qh_qh(qqh)
    , previous_user(NULL)
    , doubles_vector()
    , ints_vector()
    , fprintf_ints()
    , fprintf_doubles()
    , fprintf_codes()
    , fprintf_strings()
    , num_facets(0)
    , num_neighbors(0)
    , num_numbers(0)
    , num_points(0)
    , num_results(0)
    , num_ridges(0)
    , num_vectors(0)
    , num_vertices(0)
    , qhull_dim(0)
    , delaunay_dim(0)
{
    previous_user= qh()->cpp_user;
    qh()->cpp_user= NULL;
    captureOn();
}//constructor

QhullUser::
~QhullUser()
{
    captureOff();
    qh()->cpp_user= previous_user;
}//destructor

#//!\name Get/Set

//! Clear working fields of QhullUser
//! Retains qh_qh and previous_user as initialized
//! Updates qhull_dim from qh_qh (does not change)
//! Updates delaunay_dim if qh_qh.ISdelaunay
void QhullUser::
clear()
{
    doubles_vector.clear();
    ints_vector.clear();
    fprintf_ints.clear();
    fprintf_doubles.clear();
    fprintf_codes.clear();
    fprintf_strings.clear();
    num_facets= 0;
    num_neighbors= 0;
    num_numbers= 0;
    num_points= 0;
    num_results= 0;
    num_ridges= 0;
    num_vectors= 0;
    num_vertices= 0;
}//clear

#//!\name Methods

void QhullUser::
captureOff()
{
    if(qh()->cpp_user==NULL){
        throw QhullError(10080, "Qhull error: QhullUser::captureOn not call before QhullUser::captureOff for QhullUser 0x%llx", 0, 0, 0.0, this);
    }
    if(qh()->cpp_user!=this){
        throw QhullError(10081, "Qhull error: conflicting QhullUser (0x%llx) for QhullUser::captureOff().  Does not match 'this' (0x...%X)", int(0xffff&(intptr_t)this), 0, 0.0, qh()->cpp_user);
    }
    qh()->cpp_user= NULL;
}//captureOff

void QhullUser::
captureOn()
{
    if(qh()->cpp_user){
        throw QhullError(10079, "Qhull error: conflicting user of cpp_user for QhullUser::captureOn() or corrupted qh_qh 0x%llx", 0, 0, 0.0, qh());
    }
    qh()->cpp_user= this;
}//captureOn

}//namespace orgQhull

#//!\name Global functions

/*---------------------------------

  qh_fprintf(qh, fp, msgcode, format, list of args )
    replacement for qh_fprintf in userprintf_r.c, which replaces fprintf for Qhull
    qh.ISqhullQh must be true, indicating that qh a subclass of QhullQh
    qh.cpp_user is an optional QhullUser for trapped MSG_OUTPUT calls
    fp may be NULL
    otherwise behaves the same as qh_fprintf in userprintf_r.c

returns:
    sets qhullQh->qhull_status if msgcode is error 6000..6999
....sets qh.last_errcode if error reported
....if qh.cpp_user defined, records results of 'qhull v Fi Fo'
        See "qvoronoi-fifo" in user_eg3_r.cpp for an example


notes:
    Only called from libqhull_r
    A similar technique is used by RboxPoints and qh_fprintf_rbox
    Do not throw errors from here.  Use qh_errexit;
    fgets() is not trapped like fprintf(), QH11008 FIX: how do users handle input?  A callback?
*/
extern "C"

//! Custom qh_fprintf for transferring Qhull output from io_r.c to QhullUser and QhullQh
//! Identify msgcodes with Qhull option 'Ta'
//! A similar technique is used by RboxPoints with a custom qh_fprintf_rbox
void qh_fprintf(qhT *qh, FILE* fp, int msgcode, const char *fmt, ... ){
    va_list args;
    int last_errcode;

    using namespace orgQhull;
    
    if(qh==NULL || !qh->ISqhullQh){
        qh_fprintf_stderr(10025, "Qhull error: qh_fprintf in QhullUser.cpp called from a Qhull instance without QhullQh defined\n");
        last_errcode= 10025;
        qh_exit(last_errcode);
    }
    va_start(args, fmt);
    if(msgcode>=MSG_OUTPUT && qh->cpp_user){
        QhullUser *out= reinterpret_cast(qh->cpp_user);
        bool isOut= false;
        switch (msgcode){
        case 9231:        /* printvdiagram, totcount (ignored) */
            out->setNumResults(va_arg(args, int));
            isOut= true;
            break;
        case 9271:        /* qh_printvnorm, count, pointId, pointId, hyperplane */
            out->appendInt(va_arg(args, int));
            out->appendInt(va_arg(args, int));
            out->appendInt(va_arg(args, int));
            out->appendAndClearInts();
            isOut= true;
            break;
        case 9272:
        case 9273:
            out->appendDouble(va_arg(args, double));
            isOut= true;
            break;
        case 9274:
            out->appendAndClearDoubles();
            isOut= true;
            break;
        default:
            // do nothing
            break;
        }
        if(isOut){
            out->appendCode(msgcode);
            va_end(args);
            return;
        }
    }/*MSG_OUTPUT, cpp_user*/

    QhullQh *qhullQh= static_cast(qh);
    char newMessage[MSG_MAXLEN];
    int msgLen= 0;
    if((qh && qh->ANNOTATEoutput) || msgcode < MSG_TRACE4){
        msgLen= snprintf(newMessage, sizeof(newMessage), "[QH%.4d]", msgcode);
    }else if(msgcode>=MSG_ERROR && msgcode < MSG_STDERR){
        msgLen= snprintf(newMessage, sizeof(newMessage), "QH%.4d ", msgcode);
    }
    if(msgLen>=0 && msgLen < (int)sizeof(newMessage)){
        vsnprintf(newMessage + msgLen, sizeof(newMessage) - msgLen, fmt, args);
    }
    if(msgcode < MSG_OUTPUT || fp == qh_FILEstderr){
        if(msgcode>=MSG_ERROR && msgcode < MSG_WARNING){
            qh->last_errcode= msgcode;
            if(qhullQh->qhull_status < MSG_ERROR || qhullQh->qhull_status>=MSG_WARNING){
                qhullQh->qhull_status= msgcode;
            }
        }
        qhullQh->appendQhullMessage(newMessage);
    }else if(qhullQh->output_stream && qhullQh->use_output_stream){
        *qhullQh->output_stream << newMessage;
        if(qh->FLUSHprint){
            qhullQh->output_stream->flush();
        }
    }else{
        qhullQh->appendQhullMessage(newMessage);
    }
    va_end(args);

    /* Place debugging traps here. Use with trace option 'Tn'
         Set qh.tracefacet_id, qh.traceridge_id, and/or qh.tracevertex_id in global_r.c
    */
    if(False){ /* in production skip test for debugging traps */
        facetT *neighbor, **neighborp;
        if(qh->tracefacet && qh->tracefacet->tested){
            if(qh_setsize(qh, qh->tracefacet->neighbors) < qh->hull_dim)
                qh_errexit(qh, qh_ERRdebug, qh->tracefacet, qh->traceridge);
            FOREACHneighbor_(qh->tracefacet){
                if(neighbor != qh_DUPLICATEridge && neighbor != qh_MERGEridge && neighbor->visible)
                    qh_errexit2(qh, qh_ERRdebug, qh->tracefacet, neighbor);
            }
        }
        if(qh->traceridge && qh->traceridge->top->id == 234342223){
            qh_errexit(qh, qh_ERRdebug, qh->tracefacet, qh->traceridge);
        }
        if(qh->tracevertex && qh_setsize(qh, qh->tracevertex->neighbors) > 3434334){
            qh_errexit(qh, qh_ERRdebug, qh->tracefacet, qh->traceridge);
        }
    }
} /* qh_fprintf */

qhull-2020.2/src/libqhullcpp/QhullUser.h0000644060175106010010000001221213710657410016373 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullUser.h#7 $$Change: 3010 $
** $DateTime: 2020/07/30 22:14:11 $$Author: bbarber $
**
****************************************************************************/

#ifndef QhullUser_H
#define QhullUser_H

#include "libqhull_r/qhull_ra.h"
#include "libqhullcpp/QhullPoint.h"
#include "libqhullcpp/PointCoordinates.h"

#include 
#include 
#include 
#include 
#include 
#include 

namespace orgQhull{

#//!\name Defined here
    //! QhullUser -- custom C++ interfaces into Qhull (via qh_fprintf)
    class QhullUser;
    // qh_fprintf is defined below.  It replaces libqhull_r/userprintf_r.c

#//!\name Used here
    class QhullQh;

    class QhullUser{

    private:
#//!\name Fields
        QhullQh *       qh_qh;          //!< QhullQh/qhT for access to libqhull_r
        void *          previous_user;  //!< previous qh.cpp_user, restored on deconstruction
        std::vector > doubles_vector;  //! vectors for capturing ints and doubles
        std::vector >  ints_vector;
        std::vector                fprintf_ints;
        std::vector             fprintf_doubles;
        std::vector                fprintf_codes;
        std::vector        fprintf_strings;
        int             num_facets;
        int             num_neighbors;
        int             num_numbers;
        int             num_points;
        int             num_results;
        int             num_ridges;
        int             num_vectors;
        int             num_vertices;
        int             qhull_dim;
        int             delaunay_dim;   //! ints for capturing fprintf fields

    public:
#//!\name Construct
                        QhullUser(QhullQh *qqh);
                        ~QhullUser();
    private:                // Disable default constructor, copy constructor, and assignment
                        QhullUser();
                        QhullUser(const QhullUser &);
        QhullUser &     operator=(const QhullUser &);
    private:

    public:
#//!\name GetSet
        void            appendCode(int msgCode) { fprintf_codes.push_back(msgCode); }
        void            appendDouble(double a) { fprintf_doubles.push_back(a); }
        void            appendInt(int i) { fprintf_ints.push_back(i); }
        void            appendAndClearDoubles() { doubles_vector.push_back(fprintf_doubles); fprintf_doubles.clear(); }
        void            appendAndClearInts() { ints_vector.push_back(fprintf_ints); fprintf_ints.clear(); }
        void            clear();
        void            clearDoubles() { fprintf_doubles.clear(); }
        void            clearDoublesVector() { doubles_vector.clear(); }
        void            clearInts() { fprintf_ints.clear(); }
        void            clearIntsVector() { ints_vector.clear(); }
        const std::vector &codes() const { return fprintf_codes; }
        int             delaunayDim() const { return delaunay_dim; }
        const std::vector > &doublesVector() const { return doubles_vector; }
        const std::vector &doubles() const { return fprintf_doubles; }
        int             firstCode() const { return (fprintf_codes.size() == 0 ? -1 : fprintf_codes[0]); }
        const std::vector &ints() const { return fprintf_ints; }
        const std::vector > &intsVector() const { return ints_vector; }
        int             numDoubles() const { return (int)doubles_vector.size();  }
        int             numFacets() const { return num_facets; }
        int             numInts() const { return (int)ints_vector.size(); }
        int             numNeighbors() const { return num_neighbors; }
        int             numNumbers() const { return num_numbers; }
        int             numPoints() const { return num_points; }
        int             numResults() const { return num_results; }
        int             numRidges() const { return num_ridges; }
        int             numVectors() const { return num_vectors; }
        int             numVertices() const { return num_vertices; }
        QhullQh *       qh() const { return qh_qh; }
        int             qhullDim() const { return qhull_dim; }
        void            setDelaunayDim(int i) { delaunay_dim= i; }
        void            setNumFacets(int i) { num_facets= i; }
        void            setNumResults(int i) { num_results= i; }
        void            setNumRidges(int i) { num_ridges= i; }
        void            setNumNeighbors(int i) { num_neighbors= i; }
        void            setNumNumbers(int i) { num_numbers= i; }
        void            setNumPoints(int i) { num_points= i; }
        void            setNumVectors(int i) { num_vectors= i; }
        void            setNumVertices(int i) { num_vertices= i; }
        void            setQhullDim(int i) { qhull_dim= i; }

#//!\name Methods
        void            captureOn();
        void            captureOff();
};//class QhullUser

}//namespace orgQhull

#endif // QhullUser_H
qhull-2020.2/src/libqhullcpp/QhullVertex.cpp0000644060175106010010000000674113706160344017277 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullVertex.cpp#4 $$Change: 3001 $
** $DateTime: 2020/07/24 20:43:28 $$Author: bbarber $
**
****************************************************************************/

#//! QhullVertex -- Qhull's vertex structure, vertexT, as a C++ class

#include "libqhullcpp/QhullVertex.h"

#include "libqhullcpp/Qhull.h"
#include "libqhullcpp/QhullPoint.h"
#include "libqhullcpp/QhullFacetSet.h"
#include "libqhullcpp/QhullFacet.h"

#ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
#pragma warning( disable : 4611)  // interaction between '_setjmp' and C++ object destruction is non-portable
#pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
#endif

namespace orgQhull {

#//!\name Class objects
vertexT QhullVertex::
s_empty_vertex= {NULL,NULL,NULL,NULL,0,0,       // must match vertexT -Wmissing-field-initializers
                false,false,false,false,false,false};

#//!\name Constructors

QhullVertex::QhullVertex(const Qhull &q)
: qh_vertex(&s_empty_vertex)
, qh_qh(q.qh())
{
}//Default

QhullVertex::QhullVertex(const Qhull &q, vertexT *v)
: qh_vertex(v ? v : &s_empty_vertex)
, qh_qh(q.qh())
{
}//vertexT

QhullVertex::QhullVertex(const QhullVertex &other)
: qh_vertex(other.qh_vertex)
, qh_qh(other.qh_qh) 
{
}//copy constructor

#//!\name foreach

//! Return neighboring facets for a vertex
//! If neither merging nor Voronoi diagram, requires Qhull::defineVertexNeighborFacets() beforehand.
QhullFacetSet QhullVertex::
neighborFacets() const
{
    if(!neighborFacetsDefined()){
        throw QhullError(10034, "Qhull error: neighboring facets of vertex %d not defined.  Please call Qhull::defineVertexNeighborFacets() beforehand.", id());
    }
    return QhullFacetSet(qh_qh, qh_vertex->neighbors);
}//neighborFacets

}//namespace orgQhull

#//!\name Global functions

using std::endl;
using std::ostream;
using std::string;
using std::vector;
using orgQhull::QhullPoint;
using orgQhull::QhullFacet;
using orgQhull::QhullFacetSet;
using orgQhull::QhullFacetSetIterator;
using orgQhull::QhullVertex;

//! Duplicate of qh_printvertex [io_r.c]
ostream &
operator<<(ostream &os, const QhullVertex::PrintVertex &pr)
{
    QhullVertex v= *pr.vertex;
    QhullPoint p= v.point();
    if(*pr.print_message){
        os << pr.print_message << " ";
    }else{
        os << "- ";
    }
    os << "p" << p.id() << " (v" << v.id() << "): ";
    const realT *c= p.coordinates();
    for(int k= p.dimension(); k--; ){
        os << " " << *c++; // QH11010 FIX: %5.2g
    }
    if(v.getVertexT()->deleted){
        os << " deleted";
    }
    if(v.getVertexT()->delridge){
        os << " delridge";
    }
    if(v.getVertexT()->newfacet){
      os << " newfacet";
    }
    if(v.getVertexT()->seen && v.qh()->IStracing){
      os << " seen";
    }
    if(v.getVertexT()->seen2 && v.qh()->IStracing){
      os << " seen2";
    }
    os << endl;
    if(v.neighborFacetsDefined()){
        QhullFacetSetIterator i= v.neighborFacets();
        if(i.hasNext()){
            os << " neighborFacets:";
            countT count= 0;
            while(i.hasNext()){
                if(++count % 100 == 0){
                    os << endl << "     ";
                }
                QhullFacet f= i.next();
                os << " f" << f.id();
            }
            os << endl;
        }
    }
    return os;
}//<< PrintVertex

qhull-2020.2/src/libqhullcpp/QhullVertex.h0000644060175106010010000001113613706160344016736 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullVertex.h#4 $$Change: 3001 $
** $DateTime: 2020/07/24 20:43:28 $$Author: bbarber $
**
****************************************************************************/

#ifndef QHULLVERTEX_H
#define QHULLVERTEX_H

#include "libqhull_r/qhull_ra.h"
#include "libqhullcpp/QhullPoint.h"
#include "libqhullcpp/QhullLinkedList.h"
#include "libqhullcpp/QhullSet.h"

#include 

namespace orgQhull {

#//!\name Used here
    class QhullFacetSet;

#//!\name Defined here
    //! QhullVertex -- Qhull's vertex structure, vertexT [libqhull_r.h], as a C++ class
    class QhullVertex;
    typedef QhullLinkedList QhullVertexList;
    typedef QhullLinkedListIterator QhullVertexListIterator;


/*********************
  topological information:
    next,previous       doubly-linked list of all vertices
    neighborFacets           set of adjacent facets (only if qh.VERTEXneighbors)

  geometric information:
    point               array of DIM coordinates
*/

class QhullVertex {

#//!\name Defined here
public:
    typedef vertexT *   base_type;  // for QhullVertexSet

private:
#//!\name Fields
    vertexT *           qh_vertex;  //!< Corresponding vertexT, never 0
    QhullQh *           qh_qh;      //!< QhullQh/qhT for vertexT, may be 0

#//!\name Class objects
    static vertexT      s_empty_vertex;  // needed for shallow copy

public:
#//!\name Constants

#//!\name Constructors
                        QhullVertex() : qh_vertex(&s_empty_vertex), qh_qh(0) {}
    explicit            QhullVertex(const Qhull &q);
                        QhullVertex(const Qhull &q, vertexT *v);
    explicit            QhullVertex(QhullQh *qqh) : qh_vertex(&s_empty_vertex), qh_qh(qqh) {}
                        QhullVertex(QhullQh *qqh, vertexT *v) : qh_vertex(v ? v : &s_empty_vertex), qh_qh(qqh) {}
                        // Creates an alias.  Does not copy QhullVertex.  Needed for return by value and parameter passing
                        QhullVertex(const QhullVertex &other);
                        // Creates an alias.  Does not copy QhullVertex.  Needed for vector
    QhullVertex &       operator=(const QhullVertex &other) { qh_vertex= other.qh_vertex; qh_qh= other.qh_qh; return *this; }
                        ~QhullVertex() {}

#//!\name GetSet
    int                 dimension() const { return (qh_qh ? qh_qh->hull_dim : 0); }
    vertexT *           getBaseT() const { return getVertexT(); } //!< For QhullSet
    vertexT *           getVertexT() const { return qh_vertex; }
    bool                hasNext() const { return (qh_vertex->next != NULL && qh_vertex->next != qh_qh->vertex_tail); }
    bool                hasPrevious() const { return (qh_vertex->previous != NULL); }
    countT              id() const { return qh_vertex->id; }
    bool                isValid() const { return (qh_qh && qh_vertex != &s_empty_vertex); }
                        //! True if defineVertexNeighborFacets() already called.  Auotomatically set for facet merging, Voronoi diagrams
    bool                neighborFacetsDefined() const { return qh_vertex->neighbors != 0; }
    QhullVertex         next() const { return QhullVertex(qh_qh, qh_vertex->next); }
    bool                operator==(const QhullVertex &other) const { return qh_vertex==other.qh_vertex; }
    bool                operator!=(const QhullVertex &other) const { return !operator==(other); }
    QhullPoint          point() const { return QhullPoint(qh_qh, qh_vertex->point); }
    QhullVertex         previous() const { return QhullVertex(qh_qh, qh_vertex->previous); }
    QhullQh *           qh() const { return qh_qh; }
    void                setVertexT(QhullQh *qqh, vertexT *vertex) { qh_qh= qqh; qh_vertex= vertex; }

#//!\name foreach
    //See also QhullVertexList
    QhullFacetSet       neighborFacets() const;

#//!\name IO
    struct PrintVertex{
        const QhullVertex *vertex;
        const char *    print_message;    //!< non-null message
                        PrintVertex(const char *message, const QhullVertex &v) : vertex(&v), print_message(message) {}
    };//PrintVertex
    PrintVertex         print(const char *message) const { return PrintVertex(message, *this); }
};//class QhullVertex

}//namespace orgQhull

#//!\name GLobal

std::ostream &operator<<(std::ostream &os, const orgQhull::QhullVertex::PrintVertex &pr);
inline std::ostream &operator<<(std::ostream &os, const orgQhull::QhullVertex &v) { os << v.print(""); return os; }

#endif // QHULLVERTEX_H
qhull-2020.2/src/libqhullcpp/QhullVertexSet.cpp0000644060175106010010000001221013661631133017736 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2009-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/QhullVertexSet.cpp#3 $$Change: 2953 $
** $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
**
****************************************************************************/

#//! QhullVertexSet -- Qhull's linked Vertexs, as a C++ class

#include "libqhullcpp/QhullVertexSet.h"

#include "libqhullcpp/QhullVertex.h"
#include "libqhullcpp/QhullPoint.h"
#include "libqhullcpp/QhullRidge.h"
#include "libqhullcpp/QhullVertex.h"
#include "libqhullcpp/Qhull.h"

using std::string;
using std::vector;

#ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
#pragma warning( disable : 4611)  /* interaction between '_setjmp' and C++ object destruction is non-portable */
                                    /* setjmp should not be implemented with 'catch' */
#endif

namespace orgQhull {

QhullVertexSet::
QhullVertexSet(const Qhull &q, facetT *facetlist, setT *facetset, bool allfacets)
: QhullSet(q.qh(), 0)
, qhsettemp_defined(false)
{
    QH_TRY_(q.qh()){ // no object creation -- destructors skipped on longjmp()
        setT *vertices= qh_facetvertices(q.qh(), facetlist, facetset, allfacets);
        defineAs(vertices);
        qhsettemp_defined= true;
    }
    q.qh()->NOerrexit= true;
    q.qh()->maybeThrowQhullMessage(QH_TRY_status);
}//QhullVertexSet facetlist facetset

//! Return tempory QhullVertexSet of vertices for a list and/or a set of facets
//! Sets qhsettemp_defined (disallows copy constructor and assignment to prevent double-free)
QhullVertexSet::
QhullVertexSet(QhullQh *qqh, facetT *facetlist, setT *facetset, bool allfacets)
: QhullSet(qqh, 0)
, qhsettemp_defined(false)
{
    QH_TRY_(qh()){ // no object creation -- destructors skipped on longjmp()
        setT *vertices= qh_facetvertices(qh(), facetlist, facetset, allfacets);
        defineAs(vertices);
        qhsettemp_defined= true;
    }
    qh()->NOerrexit= true;
    qh()->maybeThrowQhullMessage(QH_TRY_status);
}//QhullVertexSet facetlist facetset

//! Copy constructor for argument passing and returning a result
//! Only copies a pointer to the set.
//! Throws an error if qhsettemp_defined, otherwise have a double-free
//!\todo Convert QhullVertexSet to a shared pointer with reference counting
QhullVertexSet::
QhullVertexSet(const QhullVertexSet &other)
: QhullSet(other)
, qhsettemp_defined(false)
{
    if(other.qhsettemp_defined){
        throw QhullError(10077, "QhullVertexSet: Cannot use copy constructor since qhsettemp_defined (e.g., QhullVertexSet for a set and/or list of QhFacet).  Contains %d vertices", other.count());
    }
}//copy constructor

//! Copy assignment only copies a pointer to the set.
//! Throws an error if qhsettemp_defined, otherwise have a double-free
QhullVertexSet & QhullVertexSet::
operator=(const QhullVertexSet &other)
{
    QhullSet::operator=(other);
    qhsettemp_defined= false;
    if(other.qhsettemp_defined){
        throw QhullError(10078, "QhullVertexSet: Cannot use copy constructor since qhsettemp_defined (e.g., QhullVertexSet for a set and/or list of QhFacet).  Contains %d vertices", other.count());
    }
    return *this;
}//assignment

void QhullVertexSet::
freeQhSetTemp()
{
    if(qhsettemp_defined){
        qhsettemp_defined= false;
        QH_TRY_(qh()){ // no object creation -- destructors skipped on longjmp()
            qh_settempfree(qh(), referenceSetT()); // errors if not top of tempstack or if qhmem corrupted
        }
        qh()->NOerrexit= true;
        qh()->maybeThrowQhullMessage(QH_TRY_status, QhullError::NOthrow);
    }
}//freeQhSetTemp

QhullVertexSet::
~QhullVertexSet()
{
    freeQhSetTemp();
}//~QhullVertexSet

#ifndef QHULL_NO_STL
std::vector QhullVertexSet::
toStdVector() const
{
    QhullSetIterator i(*this);
    std::vector vs;
    while(i.hasNext()){
        QhullVertex v= i.next();
        vs.push_back(v);
    }
    return vs;
}//toStdVector
#endif //QHULL_NO_STL

#//!\name Class functions

}//namespace orgQhull

#//!\name Global functions

using std::endl;
using std::ostream;
using orgQhull::QhullPoint;
using orgQhull::QhullVertex;
using orgQhull::QhullVertexSet;
using orgQhull::QhullVertexSetIterator;

//! Print Vertex identifiers to stream.  Space prefix.  From qh_printVertexheader [io_r.c]
ostream &
operator<<(ostream &os, const QhullVertexSet::PrintIdentifiers &pr)
{
    os << pr.print_message;
    for(QhullVertexSet::const_iterator i= pr.vertex_set->begin(); i!=pr.vertex_set->end(); ++i){
        const QhullVertex v= *i;
        os << " v" << v.id();
    }
    os << endl;
    return os;
}//<

namespace orgQhull {

#//!\name Used here

#//!\name Defined here
    //! QhullVertexSet -- a set of QhullVertex, as a C++ class.
    //! See Qhull
    class QhullVertexSet;

    //! QhullVertexSetIterator is a Java-style iterator for QhullVertex in a QhullVertexSet
    //! QhullVertexSetIterator may be used on temporary results.  It copies the pointers in QhullVertexSet
    typedef QhullSetIterator QhullVertexSetIterator;

class QhullVertexSet : public QhullSet {

private:
#//!\name Fields
    bool                qhsettemp_defined;  //! Set was allocated with qh_settemp()

public:
#//!\name Constructor
                        QhullVertexSet(const Qhull &q, setT *s) : QhullSet(q, s), qhsettemp_defined(false) {}
                        QhullVertexSet(const Qhull &q, facetT *facetlist, setT *facetset, bool allfacets);
                        //Conversion from setT* is not type-safe.  Implicit conversion for void* to T
                        QhullVertexSet(QhullQh *qqh, setT *s) : QhullSet(qqh, s), qhsettemp_defined(false) {}
                        QhullVertexSet(QhullQh *qqh, facetT *facetlist, setT *facetset, bool allfacets);
                        //Copy constructor and assignment copies pointer but not contents.  Throws error if qhsettemp_defined.  Needed for return by value.
                        QhullVertexSet(const QhullVertexSet &other);
    QhullVertexSet &    operator=(const QhullVertexSet &other);
                        ~QhullVertexSet();

private:                //!Default constructor disabled.  Will implement allocation later
                        QhullVertexSet();
public:

#//!\name Destructor
    void                freeQhSetTemp();

#//!\name Conversion
#ifndef QHULL_NO_STL
    std::vector toStdVector() const;
#endif //QHULL_NO_STL
#ifdef QHULL_USES_QT
    QList   toQList() const;
#endif //QHULL_USES_QT

#//!\name Methods

#//!\name IO
    struct PrintVertexSet{
        const QhullVertexSet *vertex_set;
        const char *    print_message;     //!< non-null message
                        
                        PrintVertexSet(const char *message, const QhullVertexSet *s) : vertex_set(s), print_message(message) {}
    };//PrintVertexSet
    const PrintVertexSet print(const char *message) const { return PrintVertexSet(message, this); }

    struct PrintIdentifiers{
        const QhullVertexSet *vertex_set;
        const char *    print_message;    //!< non-null message
                        PrintIdentifiers(const char *message, const QhullVertexSet *s) : vertex_set(s), print_message(message) {}
    };//PrintIdentifiers
    PrintIdentifiers    printIdentifiers(const char *message) const { return PrintIdentifiers(message, this); }

};//class QhullVertexSet

}//namespace orgQhull

#//!\name Global

std::ostream &operator<<(std::ostream &os, const orgQhull::QhullVertexSet::PrintVertexSet &pr);
std::ostream &operator<<(std::ostream &os, const orgQhull::QhullVertexSet::PrintIdentifiers &p);
inline std::ostream &operator<<(std::ostream &os, const orgQhull::QhullVertexSet &vs) { os << vs.print(""); return os; }

#endif // QHULLVERTEXSET_H
qhull-2020.2/src/libqhullcpp/qt-qhull.cpp0000644060175106010010000000522713723533670016566 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2009-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/qt-qhull.cpp#7 $$Change: 3032 $
** $DateTime: 2020/09/01 17:08:51 $$Author: bbarber $
**
****************************************************************************/

#include 
#include "qhulltest/RoadTest.h"

#ifndef QHULL_USES_QT
#define QHULL_USES_QT 1
#endif

#include "Coordinates.h"
#include "QhullFacetList.h"
#include "QhullFacetSet.h"
#include "QhullHyperplane.h"
#include "QhullPoint.h"
#include "QhullPoints.h"
#include "QhullPointSet.h"
#include "QhullVertex.h"
#include "QhullVertexSet.h"

namespace orgQhull {

#//!\name Conversions

QList Coordinates::
toQList() const
{
    QList cs;
    for(int i= 0; i QhullFacetList::
toQList() const
{
    QhullLinkedListIterator i(*this);
    QList vs;
    while(i.hasNext()){
        QhullFacet f= i.next();
        if(isSelectAll() || f.isGood()){
            vs.append(f);
        }
    }
    return vs;
}//toQList

//! Same as PrintVertices
QList QhullFacetList::
vertices_toQList() const
{
    QList vs;
    QhullVertexSet qvs(qh(), first().getFacetT(), nullptr, isSelectAll());
    for(QhullVertexSet::iterator i=qvs.begin(); i!=qvs.end(); ++i){
        vs.push_back(*i);
    }
    return vs;
}//vertices_toQList

QList QhullFacetSet::
toQList() const
{
    QhullSetIterator i(*this);
    QList vs;
    while(i.hasNext()){
        QhullFacet f= i.next();
        if(isSelectAll() || f.isGood()){
            vs.append(f);
        }
    }
    return vs;
}//toQList

#ifdef QHULL_USES_QT
QList QhullHyperplane::
toQList() const
{
    QhullHyperplaneIterator i(*this);
    QList fs;
    while(i.hasNext()){
        fs.append(i.next());
    }
    fs.append(hyperplane_offset);
    return fs;
}//toQList
#endif //QHULL_USES_QT

QList QhullPoint::
toQList() const
{
    QhullPointIterator i(*this);
    QList vs;
    while(i.hasNext()){
        vs.append(i.next());
    }
    return vs;
}//toQList

QList QhullPoints::
toQList() const
{
    QhullPointsIterator i(*this);
    QList vs;
    while(i.hasNext()){
        vs.append(i.next());
    }
    return vs;
}//toQList

/******
QList QhullPointSet::
toQList() const
{
    QhullPointSetIterator i(*this);
    QList vs;
    while(i.hasNext()){
        vs.append(i.next());
    }
    return vs;
}//toQList
*/
}//orgQhull

qhull-2020.2/src/libqhullcpp/RboxPoints.cpp0000644060175106010010000001564613710645347017135 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/RboxPoints.cpp#8 $$Change: 2965 $
** $DateTime: 2020/06/04 15:37:41 $$Author: bbarber $
**
****************************************************************************/

#include "libqhullcpp/RboxPoints.h"

#include "libqhullcpp/QhullError.h"

#include 
#include 

using std::cerr;
using std::endl;
using std::istream;
using std::ostream;
using std::ostringstream;
using std::string;
using std::vector;
using std::ws;

#ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
#pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
#endif

namespace orgQhull {

#//! RboxPoints -- generate random PointCoordinates for qhull (rbox)


#//!\name Constructors
RboxPoints::
RboxPoints()
: PointCoordinates("rbox")
, rbox_new_count(0)
, rbox_status(qh_ERRnone)
, rbox_message()
{
    allocateQhullQh();
}

//! Allocate and generate points according to rboxCommand
//! For rbox commands, see http://www.qhull.org/html/rbox.htm or html/rbox.htm
//! Same as appendPoints()
RboxPoints::
RboxPoints(const char *rboxCommand)
: PointCoordinates("rbox")
, rbox_new_count(0)
, rbox_status(qh_ERRnone)
, rbox_message()
{
    allocateQhullQh();
    // rbox arguments added to comment() via qh_rboxpoints > qh_fprintf_rbox
    appendPoints(rboxCommand);
}

RboxPoints::
~RboxPoints()
{
    delete qh();
    resetQhullQh(0);
}

// RboxPoints and qh_rboxpoints has several fields in qhT (rbox_errexit..cpp_object)
// It shares last_random with qh_rand and qh_srand
// The other fields are unused
void RboxPoints::
allocateQhullQh()
{
    QHULL_LIB_CHECK /* Check for compatible library */
    resetQhullQh(new QhullQh);
}//allocateQhullQh

#//!\name Messaging

void RboxPoints::
clearRboxMessage()
{
    rbox_status= qh_ERRnone;
    rbox_message.clear();
}//clearRboxMessage

std::string RboxPoints::
rboxMessage() const
{
    if(rbox_status!=qh_ERRnone){
        return rbox_message;
    }
    if(isEmpty()){
        return "rbox warning: no points generated\n";
    }
    return "rbox: OK\n";
}//rboxMessage

int RboxPoints::
rboxStatus() const
{
    return rbox_status;
}

bool RboxPoints::
hasRboxMessage() const
{
    return (rbox_status!=qh_ERRnone);
}

#//!\name Methods

//! Appends points as defined by rboxCommand
//! If dimension previously defined, adds " Ddim" to rboxCommand
//! Appends rboxCommand to comment
//! For rbox commands, see http://www.qhull.org/html/rbox.htm or html/rbox.htm
void RboxPoints::
appendPoints(const char *rboxCommand)
{
    string s("rbox ");
    int dim= dimension(); // QhullPoints
    s += rboxCommand;
    if(dim==0){
        if(*rboxCommand=='D'){
            char *endDim= NULL;
            dim= (int)strtol(rboxCommand+1, &endDim, 10);
            if(*endDim=='\0' && dim>0){
                setDimension(dim);
                return;
            }
        }
    }else if(dim!=3){
        char dimStr[20]; // max dim is 200 (MAXdim)
        sprintf(dimStr, " D%d", dim);
        s += dimStr;
    }
    char *command= const_cast(s.c_str());
    if(qh()->cpp_object){
        throw QhullError(10001, "Qhull error: conflicting user of cpp_object for RboxPoints::appendPoints() or corrupted qh_qh");
    }
    if(extraCoordinatesCount()!=0){
        throw QhullError(10067, "Qhull error: Extra coordinates (%d) prior to calling RboxPoints::appendPoints.  Was %s", extraCoordinatesCount(), 0, 0.0, comment().c_str());
    }
    countT previousCount= count();
    qh()->cpp_object= this;           // for qh_fprintf_rbox()
    int status= qh_rboxpoints(qh(), command);
    qh()->cpp_object= 0;
    if(rbox_status==qh_ERRnone){
        rbox_status= status;
    }
    if(rbox_status!=qh_ERRnone){
        throw QhullError(rbox_status, rbox_message);
    }
    if(extraCoordinatesCount()!=0){
        throw QhullError(10002, "Qhull error: extra coordinates (%d) for PointCoordinates (%x)", extraCoordinatesCount(), 0, 0.0, coordinates());
    }
    if(previousCount+newCount()!=count()){
        throw QhullError(10068, "Qhull error: rbox specified %d points but got %d points for command '%s'", newCount(), count()-previousCount, 0.0, comment().c_str());
    }
}//appendPoints

}//namespace orgQhull

#//!\name Global functions

/*---------------------------------

  qh_fprintf_rbox(qh, fp, msgcode, format, list of args )
    fp is ignored (replaces qh_fprintf_rbox() in userprintf_rbox.c)
    cpp_object == RboxPoints

notes:
    only called from qh_rboxpoints()
    sets rbox_status to msgcode if error 6000..6999
    same as fprintf() and Qhull.qh_fprintf()
    fgets() is not trapped like fprintf()
    Do not throw errors from here.  Use qh_errexit_rbox;
    A similar technique can be used for qh_fprintf to capture all of its output
*/
extern "C"

void qh_fprintf_rbox(qhT *qh, FILE*, int msgcode, const char *fmt, ... ) {
    va_list args;

    using namespace orgQhull;

    if(!qh->cpp_object){
        fprintf(stderr, "QH10072 Qhull internal error (qh_fprintf_rbox): qh.cpp_object not defined.  Exit program\n");
        qh_errexit_rbox(qh, 72);
        /* never returns */
    }
    RboxPoints *out= reinterpret_cast(qh->cpp_object);
    va_start(args, fmt);
    if(msgcoderbox_message += newMessage;
        if(out->rbox_statusrbox_status>=MSG_STDERR){
            out->rbox_status= msgcode;
        }
        va_end(args);
        return;
    }
    switch(msgcode){
    case 9391:
    case 9392:
        out->rbox_message += "QH10010 Qhull input error (RboxPoints): options 'h', 'n' not supported.\n";
        qh_errexit_rbox(qh, 10);
        /* never returns */
        break;
    case 9393:  // QH11026 FIX: countT vs. int
        {
            int dimension= va_arg(args, int);
            string command(va_arg(args, char*));
            countT count= va_arg(args, countT);
            out->setDimension(dimension);
            out->appendComment(" \"");
            out->appendComment(command.substr(command.find(' ')+1));
            out->appendComment("\"");
            out->setNewCount(count);
            out->reservePoints();
        }
        break;
    case 9407:
        *out << va_arg(args, int);
        // fall through
    case 9405:
        *out << va_arg(args, int);
        // fall through
    case 9403:
        *out << va_arg(args, int);
        break;
    case 9408:
        *out << va_arg(args, double);
        // fall through
    case 9406:
        *out << va_arg(args, double);
        // fall through
    case 9404:
        *out << va_arg(args, double);
        break;
    default:
        // do nothing
        break;
    }
    va_end(args);
} /* qh_fprintf_rbox */

qhull-2020.2/src/libqhullcpp/RboxPoints.h0000644060175106010010000000457213664526033016574 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/RboxPoints.h#2 $$Change: 2953 $
** $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
**
****************************************************************************/

#ifndef RBOXPOINTS_H
#define RBOXPOINTS_H

#include "libqhull_r/qhull_ra.h"
#include "libqhullcpp/QhullPoint.h"
#include "libqhullcpp/PointCoordinates.h"

#include 
#include 
#include 
#include 
#include 
#include 

namespace orgQhull {

#//!\name Defined here
    //! RboxPoints -- generate random PointCoordinates for Qhull
    class RboxPoints;

class RboxPoints : public PointCoordinates {

private:
#//!\name Fields and friends
                        //! PointCoordinates.qh() is owned by RboxPoints
    countT              rbox_new_count;     //! Number of points for PointCoordinates
    int                 rbox_status;    //! error status from rboxpoints.  qh_ERRnone if none.
    std::string         rbox_message;   //! stderr from rboxpoints

    // '::' is required for friend references
    friend void ::qh_fprintf_rbox(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... );

public:
#//!\name Construct
                        RboxPoints();
    explicit            RboxPoints(const char *rboxCommand);
                        ~RboxPoints();
private:                // Disable copy constructor and assignment.  RboxPoints owns QhullQh.
                        RboxPoints(const RboxPoints &);
                        RboxPoints &operator=(const RboxPoints &);
private:
    void                allocateQhullQh();

public:
#//!\name GetSet
    void                clearRboxMessage();
    countT              newCount() const { return rbox_new_count; }
    std::string         rboxMessage() const;
    int                 rboxStatus() const;
    bool                hasRboxMessage() const;
    void                setNewCount(countT pointCount) { QHULL_ASSERT(pointCount>=0); rbox_new_count= pointCount; }

#//!\name Modify
    void                appendPoints(const char* rboxCommand);
    using               PointCoordinates::appendPoints;
    void                reservePoints() { reserveCoordinates((count()+newCount())*dimension()); }
};//class RboxPoints

}//namespace orgQhull

#endif // RBOXPOINTS_H
qhull-2020.2/src/libqhullcpp/RoadError.cpp0000644060175106010010000000670313661631133016710 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/RoadError.cpp#4 $$Change: 2953 $
** $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
**
****************************************************************************/

#//! RoadError -- All exceptions thrown by Qhull are RoadErrors
#//! Do not throw RoadError's from destructors.  Use e.logError() instead.

#include "libqhullcpp/RoadError.h"

#include 
#include 
#include 

using std::cerr;
using std::cout;
using std::string;

#ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
#endif

namespace orgQhull {

#//!\name Class fields

//! Identifies error messages from Qhull and Road for web searches.
//! See QhullError.h#QHULLlastError and user.h#MSG_ERROR
const char * RoadError::
ROADtag= "QH";

std::ostringstream RoadError::
global_log;

#//!\name Constructor

RoadError::
RoadError()
: error_code(0)
, log_event()
, error_message()
{ }

RoadError::
RoadError(const RoadError &other)
: error_code(other.error_code)
, log_event(other.log_event)
, error_message(other.error_message)
{
}//copy construct

RoadError::
RoadError(int code, const std::string &message)
: error_code(code)
, log_event(message.c_str())
, error_message(log_event.toString(ROADtag, error_code))
{
    log_event.cstr_1= error_message.c_str(); // overwrites initial value
}

RoadError::
RoadError(int code, const char *fmt)
: error_code(code)
, log_event(fmt)
, error_message()
{ }

RoadError::
RoadError(int code, const char *fmt, int d)
: error_code(code)
, log_event(fmt, d)
, error_message()
{ }

RoadError::
RoadError(int code, const char *fmt, int d, int d2)
: error_code(code)
, log_event(fmt, d, d2)
, error_message()
{ }

RoadError::
RoadError(int code, const char *fmt, int d, int d2, float f)
: error_code(code)
, log_event(fmt, d, d2, f)
, error_message()
{ }

RoadError::
RoadError(int code, const char *fmt, int d, int d2, float f, const char *s)
: error_code(code)
, log_event(fmt, d, d2, f, s)
, error_message(log_event.toString(ROADtag, code)) // char * may go out of scope
{ }

RoadError::
RoadError(int code, const char *fmt, int d, int d2, float f, const void *x)
: error_code(code)
, log_event(fmt, d, d2, f, x)
, error_message()
{ }

RoadError::
RoadError(int code, const char *fmt, int d, int d2, float f, int i)
: error_code(code)
, log_event(fmt, d, d2, f, i)
, error_message()
{ }

RoadError::
RoadError(int code, const char *fmt, int d, int d2, float f, long long i)
: error_code(code)
, log_event(fmt, d, d2, f, i)
, error_message()
{ }

RoadError::
RoadError(int code, const char *fmt, int d, int d2, float f, double e)
: error_code(code)
, log_event(fmt, d, d2, f, e)
, error_message()
{ }

RoadError & RoadError::
operator=(const RoadError &other)
{
    error_code= other.error_code;
    error_message= other.error_message;
    log_event= other.log_event;
    return *this;
}//operator=

#//!\name Virtual
const char * RoadError::
what() const throw()
{
    if(error_message.empty()){
        error_message= log_event.toString(ROADtag, error_code);
    }
    return error_message.c_str();
}//what

#//!\name Updates

//! Log error instead of throwing it.
//! Not reentrant, so avoid using it if possible
//!\todo Redesign with a thread-local stream or a reentrant ostringstream
void RoadError::
logErrorLastResort() const
{
    global_log << what() << endl;
}//logError


}//namespace orgQhull

qhull-2020.2/src/libqhullcpp/RoadError.h0000644060175106010010000000645013664065526016366 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/RoadError.h#7 $$Change: 2959 $
** $DateTime: 2020/05/28 22:25:29 $$Author: bbarber $
**
****************************************************************************/

#ifndef ROADERROR_H
#define ROADERROR_H

#include "libqhull_r/user_r.h"  /* for QHULL_CRTDBG */
#include "libqhullcpp/RoadLogEvent.h"

#include 
#include 
#include 
#include 

using std::endl;

namespace orgQhull {

#//!\name Defined here
    //! RoadError -- Report and log errors
    //!  See discussion in Saylan, G., "Practical C++ error handling in hybrid environments," Dr. Dobb's Journal, p. 50-55, March 2007.
    //!   He uses an auto_ptr to track a stringstream.  It constructs a string on the fly.  RoadError uses the copy constructor to transform RoadLogEvent into a string
    class RoadError;

class RoadError : public std::exception {

private:
#//!\name Fields
    int                 error_code;  //! Non-zero code (not logged), maybe returned as program status
    RoadLogEvent        log_event;   //! Format string w/ arguments
    mutable std::string error_message;  //! Formated error message.  Must be after log_event.

#//!\name Class fields
    static const char  *  ROADtag;
    static std::ostringstream  global_log; //!< May be replaced with any ostream object
                                    //!< Not reentrant -- only used by RoadError::logErrorLastResort()

public:
#//!\name Constants

#//!\name Constructors
    RoadError();
    RoadError(const RoadError &other);  //! Called on throw, generates error_message
    RoadError(int code, const std::string &message);
    RoadError(int code, const char *fmt);
    RoadError(int code, const char *fmt, int d);
    RoadError(int code, const char *fmt, int d, int d2);
    RoadError(int code, const char *fmt, int d, int d2, float f);
    RoadError(int code, const char *fmt, int d, int d2, float f, const char *s);
    RoadError(int code, const char *fmt, int d, int d2, float f, const void *x);
    RoadError(int code, const char *fmt, int d, int d2, float f, int i);
    RoadError(int code, const char *fmt, int d, int d2, float f, long long i);
    RoadError(int code, const char *fmt, int d, int d2, float f, double e);

    RoadError &         operator=(const RoadError &other);
                        ~RoadError() throw() {}

#//!\name Class methods

    static void         clearGlobalLog() { global_log.seekp(0); }
    static bool         emptyGlobalLog() { return global_log.tellp()<=0; }
    static std::string  stringGlobalLog() { return global_log.str(); }

#//!\name Virtual
    virtual const char *what() const throw();

#//!\name GetSet
    bool                isValid() const { return log_event.isValid(); }
    int                 errorCode() const { return error_code; }
   // QH11021 FIX: should RoadError provide errorMessage().  Currently what()
    RoadLogEvent        roadLogEvent() const { return log_event; }

#//!\name Update
    void                logErrorLastResort() const;
};//class RoadError

}//namespace orgQhull

#//!\name Global

inline std::ostream &   operator<<(std::ostream &os, const orgQhull::RoadError &e) { return os << e.what(); }

#endif // ROADERROR_H
qhull-2020.2/src/libqhullcpp/RoadLogEvent.cpp0000644060175106010010000000702213664304016017335 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/RoadLogEvent.cpp#3 $$Change: 2961 $
** $Date: 2020/06/01 $$Author: bbarber $
**
****************************************************************************/

#//! RoadLogEvent -- All exceptions thrown by Qhull are RoadErrors

#include "libqhullcpp/RoadLogEvent.h"

#include 
#include 
#include 
#include 

using std::cout;
using std::endl;
using std::ostringstream;
using std::string;

#ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
#endif

namespace orgQhull{

#//!\name Conversion
string RoadLogEvent::
toString(const char *tag, int code) const
{
    ostringstream os;
    size_t n= 0;
    if(tag && code){
        n= strlen(tag);
        if(format_string && strlen(format_string)>n+1 && isdigit(format_string[n+1]) && (strncmp(format_string, tag, n)==0 || strncmp(format_string+1, tag, n) == 0)){
            // format_string already starts with tag and a code, e.g., QH6024 qhull input error, or [QH1049] qh_addpoint...
        }else{
            os << tag << code;
            if(format_string && *format_string!='\0'){
                os << " ";
            }
        }
    }
    if(format_string==NULL || *format_string=='\0'){
        return os.str();
    }
    const char *s= format_string;
    int dCount= 0;  // Count of %d
    int fCount= 0;  // Count of %f
    char extraCode= '\0';
    while(*s){
        if(*s!='%'){
            os << *s++;
        }else{
            char c= *++s;
            s++;
            switch(c){
            case 'd':
                if(++dCount>2){
                    os << " ERROR_three_%d_in_format ";
                }else if(dCount==2){
                    os << int_2;
                }else{
                    os << int_1;
                }
                break;
            case 'e':
                if(firstExtraCode(os, c, &extraCode)){
                    os << double_1;
                }
                break;
            case 'f':
                if(++fCount>1){
                    os << " ERROR_two_%f_in_format ";
                }else{
                    os << float_1;
                }
                break;
            case 'i':
                if(firstExtraCode(os, c, &extraCode)){
                    os << int64_1;
                }
                break;
            case 's':
                if(firstExtraCode(os, c, &extraCode)){
                    os << cstr_1;
                }
                break;
            case 'u':
                if(firstExtraCode(os, c, &extraCode)){
                    os << "0x" << std::hex << int64_1 << std::dec;
                }
                break;
            case 'x':
                if(firstExtraCode(os, c, &extraCode)){
                    os << void_1;
                }
                break;
            case '%':
                os << c;
                break;
            default:
                os << " ERROR_%" << c << "_not_defined_in_format";
                break;
            }
        }
    }
    if(s[-1]!='\n'){
        os << endl;
    }
    return os.str();
}//toString

#//!\name Class helpers (static)

//! True if this char is the first extra code
bool RoadLogEvent::
firstExtraCode(std::ostream &os, char c, char *extraCode){
    if(*extraCode){
        os << " ERROR_%" << *extraCode << "_and_%" << c << "_in_format ";
        return false;
    }
    *extraCode= c;
    return true;
}//firstExtraCode

}//namespace orgQhull

qhull-2020.2/src/libqhullcpp/RoadLogEvent.h0000644060175106010010000000677113705655166017027 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/libqhullcpp/RoadLogEvent.h#3 $$Change: 2953 $
** $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
**
****************************************************************************/

#ifndef ROADLOGEVENT_H
#define ROADLOGEVENT_H

#include 
#include 
#include 

namespace orgQhull {

#//!\name Defined here
    //! RoadLogEvent -- Record an event for the RoadLog
    struct RoadLogEvent;

struct RoadLogEvent {

public:
#//!\name Fields
    const char *    format_string; //! Format string (a literal with format codes, for logging)
    int             int_1;       //! Integer argument (%d, for logging)
    int             int_2;       //! Integer argument (%d, for logging)
    float           float_1;     //! Float argument (%f, for logging)
    union {                      //! One additional argument (for logging)
        const char *cstr_1;      //!   Cstr argument (%s) -- type checked at construct-time
        const void *void_1;      //!   Void* argument (%x) -- Use upper-case codes for object types
        long long   int64_1;     //!   signed int64 (%i).  Ambiguous if unsigned is also defined.
        double      double_1;    //!   Double argument (%e)
    };

#//!\name Constants

#//!\name Constructors
    RoadLogEvent() : format_string(NULL), int_1(0), int_2(0), float_1(0), int64_1(0) {}
    explicit RoadLogEvent(const char *fmt) : format_string(fmt), int_1(0), int_2(0), float_1(0), int64_1(0) {}
    RoadLogEvent(const char *fmt, int d) : format_string(fmt), int_1(d), int_2(0), float_1(0), int64_1(0) {}
    RoadLogEvent(const char *fmt, int d, int d2) : format_string(fmt), int_1(d), int_2(d2), float_1(0), int64_1(0) {}
    RoadLogEvent(const char *fmt, int d, int d2, float f) : format_string(fmt), int_1(d), int_2(d2), float_1(f), int64_1(0) {}
    RoadLogEvent(const char *fmt, int d, int d2, float f, const char *s) : format_string(fmt), int_1(d), int_2(d2), float_1(f), cstr_1(s) {}
    RoadLogEvent(const char *fmt, int d, int d2, float f, const void *x) : format_string(fmt), int_1(d), int_2(d2), float_1(f), void_1(x) {}
    RoadLogEvent(const char *fmt, int d, int d2, float f, int i) : format_string(fmt), int_1(d), int_2(d2), float_1(f), int64_1(i) {}
    RoadLogEvent(const char *fmt, int d, int d2, float f, long long i) : format_string(fmt), int_1(d), int_2(d2), float_1(f), int64_1(i) {}
    RoadLogEvent(const char *fmt, int d, int d2, float f, double g) : format_string(fmt), int_1(d), int_2(d2), float_1(f), double_1(g) {}
    ~RoadLogEvent() {}
    //! Default copy constructor and assignment

#//!\name GetSet
    bool                isValid() const { return format_string!=NULL; }
    int                 int1() const { return int_1; }
    int                 int2() const { return int_2; }
    float               float1() const { return float_1; }
    const char *        format() const { return format_string; }
    const char *        cstr1() const { return cstr_1; }
    const void *        void1() const { return void_1; }
    long long           int64() const { return int64_1; }
    double              double1() const { return double_1; }

#//!\name Conversion

    std::string        toString(const char* tag, int code) const;

private:
#//!\name Class helpers
    static bool         firstExtraCode(std::ostream &os, char c, char *extraCode);


};//class RoadLogEvent

}//namespace orgQhull

#endif // ROADLOGEVENT_H
qhull-2020.2/src/libqhullcpp/usermem_r-cpp.cpp0000644060175106010010000000456612610604012017561 0ustar  bbarber/*
  ---------------------------------

   usermem_r-cpp.cpp

   Redefine qh_exit() as 'throw std::runtime_error("QH10003 ...")'

   This file is not included in the Qhull builds.

   qhull_r calls qh_exit() when qh_errexit() is not available.  For example,
   it calls qh_exit() if you linked the wrong qhull library.

   The C++ interface avoids most of the calls to qh_exit().

   If needed, include usermem_r-cpp.o before libqhullstatic_r.a.  You may need to
   override duplicate symbol errors (e.g. /FORCE:MULTIPLE for DevStudio).  It
   may produce a warning about throwing an error from C code.
*/

extern "C" {
    void    qh_exit(int exitcode);
}

#include 
#include 

/*---------------------------------

  qh_exit( exitcode )
    exit program

  notes:
    same as exit()
*/
void qh_exit(int exitcode) {
    exitcode= exitcode;
    throw std::runtime_error("QH10003 Qhull error.  See stderr or errfile.");
} /* exit */

/*---------------------------------

  qh_fprintf_stderr( msgcode, format, list of args )
    fprintf to stderr with msgcode (non-zero)

  notes:
    qh_fprintf_stderr() is called when qh->ferr is not defined, usually due to an initialization error

    It is typically followed by qh_errexit().

    Redefine this function to avoid using stderr

    Use qh_fprintf [userprintf_r.c] for normal printing
*/
void qh_fprintf_stderr(int msgcode, const char *fmt, ... ) {
    va_list args;

    va_start(args, fmt);
    if(msgcode)
      fprintf(stderr, "QH%.4d ", msgcode);
    vfprintf(stderr, fmt, args);
    va_end(args);
} /* fprintf_stderr */

/*---------------------------------

  qh_free(qhT *qh, mem )
    free memory

  notes:
    same as free()
    No calls to qh_errexit()
*/
void qh_free(void *mem) {
    free(mem);
} /* free */

/*---------------------------------

    qh_malloc( mem )
      allocate memory

    notes:
      same as malloc()
*/
void *qh_malloc(size_t size) {
    return malloc(size);
} /* malloc */


qhull-2020.2/src/libqhullstatic/0000755060175106010010000000000013724321405015002 5ustar  bbarberqhull-2020.2/src/libqhullstatic/libqhullstatic.pro0000644060175106010010000000104611710650027020547 0ustar  bbarber# -------------------------------------------------
# libqhullstatic.pro -- Qt project for Qhull static library
#   Built with qh_QHpointer=0.  See libqhullp.pro
# -------------------------------------------------

include(../qhull-warn.pri)
include(../qhull-libqhull-src.pri)

DESTDIR = ../../lib
TEMPLATE = lib
CONFIG += staticlib warn_on
CONFIG -= qt
build_pass:CONFIG(debug, debug|release):{
    TARGET = qhullstatic_d
    OBJECTS_DIR = Debug
}else:build_pass:CONFIG(release, debug|release):{
    TARGET = qhullstatic
    OBJECTS_DIR = Release
}
qhull-2020.2/src/libqhullstatic_r/0000755060175106010010000000000013724321406015324 5ustar  bbarberqhull-2020.2/src/libqhullstatic_r/libqhullstatic_r.pro0000644060175106010010000000103112541572122021405 0ustar  bbarber# -------------------------------------------------
# libqhullstatic_r.pro -- Qt project for Qhull static library
#
# It uses reeentrant Qhull
# -------------------------------------------------

include(../qhull-warn.pri)

DESTDIR = ../../lib
TEMPLATE = lib
CONFIG += staticlib warn_on
CONFIG -= qt
build_pass:CONFIG(debug, debug|release):{
    TARGET = qhullstatic_rd
    OBJECTS_DIR = Debug
}else:build_pass:CONFIG(release, debug|release):{
    TARGET = qhullstatic_r
    OBJECTS_DIR = Release
}

include(../qhull-libqhull-src_r.pri)
qhull-2020.2/src/libqhull_r/0000755060175106010010000000000013724321420014110 5ustar  bbarberqhull-2020.2/src/libqhull_r/geom2_r.c0000644060175106010010000022645113723600676015634 0ustar  bbarber/*
  ---------------------------------


   geom2_r.c
   infrequently used geometric routines of qhull

   see qh-geom_r.htm and geom_r.h

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull_r/geom2_r.c#17 $$Change: 3037 $
   $DateTime: 2020/09/03 17:28:32 $$Author: bbarber $

   frequently used code goes into geom_r.c
*/

#include "qhull_ra.h"

/*================== functions in alphabetic order ============*/

/*---------------------------------

  qh_copypoints(qh, points, numpoints, dimension )
    return qh_malloc'd copy of points

  notes:
    qh_free the returned points to avoid a memory leak
*/
coordT *qh_copypoints(qhT *qh, coordT *points, int numpoints, int dimension)
{
  int size;
  coordT *newpoints;

  size= numpoints * dimension * (int)sizeof(coordT);
  if (!(newpoints= (coordT *)qh_malloc((size_t)size))) {
    qh_fprintf(qh, qh->ferr, 6004, "qhull error: insufficient memory to copy %d points\n",
        numpoints);
    qh_errexit(qh, qh_ERRmem, NULL, NULL);
  }
  memcpy((char *)newpoints, (char *)points, (size_t)size); /* newpoints!=0 by QH6004 */
  return newpoints;
} /* copypoints */

/*---------------------------------

  qh_crossproduct( dim, vecA, vecB, vecC )
    crossproduct of 2 dim vectors
    C= A x B

  notes:
    from Glasner, Graphics Gems I, p. 639
    only defined for dim==3
*/
void qh_crossproduct(int dim, realT vecA[3], realT vecB[3], realT vecC[3]){

  if (dim == 3) {
    vecC[0]=   det2_(vecA[1], vecA[2],
                     vecB[1], vecB[2]);
    vecC[1]= - det2_(vecA[0], vecA[2],
                     vecB[0], vecB[2]);
    vecC[2]=   det2_(vecA[0], vecA[1],
                     vecB[0], vecB[1]);
  }
} /* vcross */

/*---------------------------------

  qh_determinant(qh, rows, dim, nearzero )
    compute signed determinant of a square matrix
    uses qh.NEARzero to test for degenerate matrices

  returns:
    determinant
    overwrites rows and the matrix
    if dim == 2 or 3
      nearzero iff determinant < qh->NEARzero[dim-1]
      (!quite correct, not critical)
    if dim >= 4
      nearzero iff diagonal[k] < qh->NEARzero[k]
*/
realT qh_determinant(qhT *qh, realT **rows, int dim, boolT *nearzero) {
  realT det=0;
  int i;
  boolT sign= False;

  *nearzero= False;
  if (dim < 2) {
    qh_fprintf(qh, qh->ferr, 6005, "qhull internal error (qh_determinate): only implemented for dimension >= 2\n");
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }else if (dim == 2) {
    det= det2_(rows[0][0], rows[0][1],
                 rows[1][0], rows[1][1]);
    if (fabs_(det) < 10*qh->NEARzero[1])  /* QH11031 FIX: 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) < 10*qh->NEARzero[2])  /* QH11031 FIX: what should this be?  det 5.5e-12 was flat for qh_maxsimplex of qdelaunay 0,0 27,27 -36,36 -9,63 */
      *nearzero= True;
  }else {
    qh_gausselim(qh, rows, dim, dim, &sign, nearzero);  /* if nearzero, diagonal still ok */
    det= 1.0;
    for (i=dim; i--; )
      det *= (rows[i])[i];
    if (sign)
      det= -det;
  }
  return det;
} /* determinant */

/*---------------------------------

  qh_detjoggle(qh, points, numpoints, dimension )
    determine default max joggle for point array
      as qh_distround * qh_JOGGLEdefault

  returns:
    initial value for JOGGLEmax from points and REALepsilon

  notes:
    computes DISTround since qh_maxmin not called yet
    if qh->SCALElast, last dimension will be scaled later to MAXwidth

    loop duplicated from qh_maxmin
*/
realT qh_detjoggle(qhT *qh, pointT *points, int numpoints, int dimension) {
  realT abscoord, distround, joggle, maxcoord, mincoord;
  pointT *point, *pointtemp;
  realT maxabs= -REALmax;
  realT sumabs= 0;
  realT maxwidth= 0;
  int k;

  if (qh->SETroundoff)
    distround= qh->DISTround; /* 'En' */
  else{
    for (k=0; k < dimension; k++) {
      if (qh->SCALElast && k == dimension-1)
        abscoord= maxwidth;
      else if (qh->DELAUNAY && k == dimension-1) /* will qh_setdelaunay() */
        abscoord= 2 * maxabs * maxabs;  /* may be low by qh->hull_dim/2 */
      else {
        maxcoord= -REALmax;
        mincoord= REALmax;
        FORALLpoint_(qh, points, numpoints) {
          maximize_(maxcoord, point[k]);
          minimize_(mincoord, point[k]);
        }
        maximize_(maxwidth, maxcoord-mincoord);
        abscoord= fmax_(maxcoord, -mincoord);
      }
      sumabs += abscoord;
      maximize_(maxabs, abscoord);
    } /* for k */
    distround= qh_distround(qh, qh->hull_dim, maxabs, sumabs);
  }
  joggle= distround * qh_JOGGLEdefault;
  maximize_(joggle, REALepsilon * qh_JOGGLEdefault);
  trace2((qh, qh->ferr, 2001, "qh_detjoggle: joggle=%2.2g maxwidth=%2.2g\n", joggle, maxwidth));
  return joggle;
} /* detjoggle */

/*---------------------------------

  qh_detmaxoutside(qh);
    determine qh.MAXoutside target for qh_RATIO... tests of distance
    updates option '_max-outside'

  notes:
    called from qh_addpoint and qh_detroundoff
    accounts for qh.ONEmerge, qh.DISTround, qh.MINoutside ('Wn'), qh.max_outside
    see qh_maxout for qh.max_outside with qh.DISTround
*/

void qh_detmaxoutside(qhT *qh) {
  realT maxoutside;

  maxoutside= fmax_(qh->max_outside, qh->ONEmerge + qh->DISTround);
  maximize_(maxoutside, qh->MINoutside);
  qh->MAXoutside= maxoutside;
  trace3((qh, qh->ferr, 3056, "qh_detmaxoutside: MAXoutside %2.2g from qh.max_outside %2.2g, ONEmerge %2.2g, MINoutside %2.2g, DISTround %2.2g\n",
      qh->MAXoutside, qh->max_outside, qh->ONEmerge, qh->MINoutside, qh->DISTround));
} /* detmaxoutside */

/*---------------------------------

  qh_detroundoff(qh)
    determine maximum roundoff errors from
      REALepsilon, REALmax, REALmin, qh.hull_dim, qh.MAXabs_coord,
      qh.MAXsumcoord, qh.MAXwidth, qh.MINdenom_1

    accounts for qh.SETroundoff, qh.RANDOMdist, qh->MERGEexact
      qh.premerge_cos, qh.postmerge_cos, qh.premerge_centrum,
      qh.postmerge_centrum, qh.MINoutside,
      qh_RATIOnearinside, qh_COPLANARratio, qh_WIDEcoplanar

  returns:
    sets qh.DISTround, etc. (see below)
    appends precision constants to qh.qhull_options

  see:
    qh_maxmin() for qh.NEARzero

  design:
    determine qh.DISTround for distance computations
    determine minimum denominators for qh_divzero
    determine qh.ANGLEround for angle computations
    adjust qh.premerge_cos,... for roundoff error
    determine qh.ONEmerge for maximum error due to a single merge
    determine qh.NEARinside, qh.MAXcoplanar, qh.MINvisible,
      qh.MINoutside, qh.WIDEfacet
    initialize qh.max_vertex and qh.minvertex
*/
void qh_detroundoff(qhT *qh) {

  qh_option(qh, "_max-width", NULL, &qh->MAXwidth);
  if (!qh->SETroundoff) {
    qh->DISTround= qh_distround(qh, qh->hull_dim, qh->MAXabs_coord, qh->MAXsumcoord);
    qh_option(qh, "Error-roundoff", NULL, &qh->DISTround);
  }
  qh->MINdenom= qh->MINdenom_1 * qh->MAXabs_coord;
  qh->MINdenom_1_2= sqrt(qh->MINdenom_1 * qh->hull_dim) ;  /* if will be normalized */
  qh->MINdenom_2= qh->MINdenom_1_2 * qh->MAXabs_coord;
                                              /* for inner product */
  qh->ANGLEround= 1.01 * qh->hull_dim * REALepsilon;
  if (qh->RANDOMdist) {
    qh->ANGLEround += qh->RANDOMfactor;
    trace4((qh, qh->ferr, 4096, "qh_detroundoff: increase qh.ANGLEround by option 'R%2.2g'\n", qh->RANDOMfactor));
  }
  if (qh->premerge_cos < REALmax/2) {
    qh->premerge_cos -= qh->ANGLEround;
    if (qh->RANDOMdist)
      qh_option(qh, "Angle-premerge-with-random", NULL, &qh->premerge_cos);
  }
  if (qh->postmerge_cos < REALmax/2) {
    qh->postmerge_cos -= qh->ANGLEround;
    if (qh->RANDOMdist)
      qh_option(qh, "Angle-postmerge-with-random", NULL, &qh->postmerge_cos);
  }
  qh->premerge_centrum += 2 * qh->DISTround;    /*2 for centrum and distplane()*/
  qh->postmerge_centrum += 2 * qh->DISTround;
  if (qh->RANDOMdist && (qh->MERGEexact || qh->PREmerge))
    qh_option(qh, "Centrum-premerge-with-random", NULL, &qh->premerge_centrum);
  if (qh->RANDOMdist && qh->POSTmerge)
    qh_option(qh, "Centrum-postmerge-with-random", NULL, &qh->postmerge_centrum);
  { /* compute ONEmerge, max vertex offset for merging simplicial facets */
    realT maxangle= 1.0, maxrho;

    minimize_(maxangle, qh->premerge_cos);
    minimize_(maxangle, qh->postmerge_cos);
    /* max diameter * sin theta + DISTround for vertex to its hyperplane */
    qh->ONEmerge= sqrt((realT)qh->hull_dim) * qh->MAXwidth *
      sqrt(1.0 - maxangle * maxangle) + qh->DISTround;
    maxrho= qh->hull_dim * qh->premerge_centrum + qh->DISTround;
    maximize_(qh->ONEmerge, maxrho);
    maxrho= qh->hull_dim * qh->postmerge_centrum + qh->DISTround;
    maximize_(qh->ONEmerge, maxrho);
    if (qh->MERGING)
      qh_option(qh, "_one-merge", NULL, &qh->ONEmerge);
  }
  qh->NEARinside= qh->ONEmerge * qh_RATIOnearinside; /* only used if qh->KEEPnearinside */
  if (qh->JOGGLEmax < REALmax/2 && (qh->KEEPcoplanar || qh->KEEPinside)) {
    realT maxdist;             /* adjust qh.NEARinside for joggle */
    qh->KEEPnearinside= True;
    maxdist= sqrt((realT)qh->hull_dim) * qh->JOGGLEmax + qh->DISTround;
    maxdist= 2*maxdist;        /* vertex and coplanar point can joggle in opposite directions */
    maximize_(qh->NEARinside, maxdist);  /* must agree with qh_nearcoplanar() */
  }
  if (qh->KEEPnearinside)
    qh_option(qh, "_near-inside", NULL, &qh->NEARinside);
  if (qh->JOGGLEmax < qh->DISTround) {
    qh_fprintf(qh, qh->ferr, 6006, "qhull option error: the joggle for 'QJn', %.2g, is below roundoff for distance computations, %.2g\n",
         qh->JOGGLEmax, qh->DISTround);
    qh_errexit(qh, qh_ERRinput, NULL, NULL);
  }
  if (qh->MINvisible > REALmax/2) {
    if (!qh->MERGING)
      qh->MINvisible= qh->DISTround;
    else if (qh->hull_dim <= 3)
      qh->MINvisible= qh->premerge_centrum;
    else
      qh->MINvisible= qh_COPLANARratio * qh->premerge_centrum;
    if (qh->APPROXhull && qh->MINvisible > qh->MINoutside)
      qh->MINvisible= qh->MINoutside;
    qh_option(qh, "Visible-distance", NULL, &qh->MINvisible);
  }
  if (qh->MAXcoplanar > REALmax/2) {
    qh->MAXcoplanar= qh->MINvisible;
    qh_option(qh, "U-max-coplanar", NULL, &qh->MAXcoplanar);
  }
  if (!qh->APPROXhull) {             /* user may specify qh->MINoutside */
    qh->MINoutside= 2 * qh->MINvisible;
    if (qh->premerge_cos < REALmax/2)
      maximize_(qh->MINoutside, (1- qh->premerge_cos) * qh->MAXabs_coord);
    qh_option(qh, "Width-outside", NULL, &qh->MINoutside);
  }
  qh->WIDEfacet= qh->MINoutside;
  maximize_(qh->WIDEfacet, qh_WIDEcoplanar * qh->MAXcoplanar);
  maximize_(qh->WIDEfacet, qh_WIDEcoplanar * qh->MINvisible);
  qh_option(qh, "_wide-facet", NULL, &qh->WIDEfacet);
  if (qh->MINvisible > qh->MINoutside + 3 * REALepsilon
  && !qh->BESToutside && !qh->FORCEoutput)
    qh_fprintf(qh, qh->ferr, 7001, "qhull input warning: minimum visibility V%.2g is greater than \nminimum outside W%.2g.  Flipped facets are likely.\n",
             qh->MINvisible, qh->MINoutside);
  qh->max_vertex= qh->DISTround;
  qh->min_vertex= -qh->DISTround;
  /* numeric constants reported in printsummary */
  qh_detmaxoutside(qh);
} /* detroundoff */

/*---------------------------------

  qh_detsimplex(qh, apex, points, dim, nearzero )
    compute determinant of a simplex with point apex and base points

  returns:
     signed determinant and nearzero from qh_determinant

  notes:
     called by qh_maxsimplex and qh_initialvertices
     uses qh.gm_matrix/qh.gm_row (assumes they're big enough)

  design:
    construct qm_matrix by subtracting apex from points
    compute determinate
*/
realT qh_detsimplex(qhT *qh, pointT *apex, setT *points, int dim, boolT *nearzero) {
  pointT *coorda, *coordp, *gmcoord, *point, **pointp;
  coordT **rows;
  int k,  i=0;
  realT det;

  zinc_(Zdetsimplex);
  gmcoord= qh->gm_matrix;
  rows= qh->gm_row;
  FOREACHpoint_(points) {
    if (i == dim)
      break;
    rows[i++]= gmcoord;
    coordp= point;
    coorda= apex;
    for (k=dim; k--; )
      *(gmcoord++)= *coordp++ - *coorda++;
  }
  if (i < dim) {
    qh_fprintf(qh, qh->ferr, 6007, "qhull internal error (qh_detsimplex): #points %d < dimension %d\n",
               i, dim);
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  det= qh_determinant(qh, rows, dim, nearzero);
  trace2((qh, qh->ferr, 2002, "qh_detsimplex: det=%2.2g for point p%d, dim %d, nearzero? %d\n",
          det, qh_pointid(qh, apex), dim, *nearzero));
  return det;
} /* detsimplex */

/*---------------------------------

  qh_distnorm( dim, point, normal, offset )
    return distance from point to hyperplane at normal/offset

  returns:
    dist

  notes:
    dist > 0 if point is outside of hyperplane

  see:
    qh_distplane in geom_r.c
*/
realT qh_distnorm(int dim, pointT *point, pointT *normal, realT *offsetp) {
  coordT *normalp= normal, *coordp= point;
  realT dist;
  int k;

  dist= *offsetp;
  for (k=dim; k--; )
    dist += *(coordp++) * *(normalp++);
  return dist;
} /* distnorm */

/*---------------------------------

  qh_distround(qh, dimension, maxabs, maxsumabs )
    compute maximum round-off error for a distance computation
      to a normalized hyperplane
    maxabs is the maximum absolute value of a coordinate
    maxsumabs is the maximum possible sum of absolute coordinate values
    if qh.RANDOMdist ('Qr'), adjusts qh_distround

  returns:
    max dist round for qh.REALepsilon and qh.RANDOMdist

  notes:
    calculate roundoff error according to Golub & van Loan, 1983, Lemma 3.2-1, "Rounding Errors"
    use sqrt(dim) since one vector is normalized
      or use maxsumabs since one vector is < 1
*/
realT qh_distround(qhT *qh, int dimension, realT maxabs, realT maxsumabs) {
  realT maxdistsum, maxround, delta;

  maxdistsum= sqrt((realT)dimension) * maxabs;
  minimize_( maxdistsum, maxsumabs);
  maxround= REALepsilon * (dimension * maxdistsum * 1.01 + maxabs);
              /* adds maxabs for offset */
  if (qh->RANDOMdist) {
    delta= qh->RANDOMfactor * maxabs;
    maxround += delta;
    trace4((qh, qh->ferr, 4092, "qh_distround: increase roundoff by random delta %2.2g for option 'R%2.2g'\n", delta, qh->RANDOMfactor));
  }
  trace4((qh, qh->ferr, 4008, "qh_distround: %2.2g, maxabs %2.2g, maxsumabs %2.2g, maxdistsum %2.2g\n",
            maxround, maxabs, maxsumabs, maxdistsum));
  return maxround;
} /* distround */

/*---------------------------------

  qh_divzero( numer, denom, mindenom1, zerodiv )
    divide by a number that's nearly zero
    mindenom1= minimum denominator for dividing into 1.0

  returns:
    quotient
    sets zerodiv and returns 0.0 if it would overflow

  design:
    if numer is nearly zero and abs(numer) < abs(denom)
      return numer/denom
    else if numer is nearly zero
      return 0 and zerodiv
    else if denom/numer non-zero
      return numer/denom
    else
      return 0 and zerodiv
*/
realT qh_divzero(realT numer, realT denom, realT mindenom1, boolT *zerodiv) {
  realT temp, numerx, denomx;


  if (numer < mindenom1 && numer > -mindenom1) {
    numerx= fabs_(numer);
    denomx= fabs_(denom);
    if (numerx < denomx) {
      *zerodiv= False;
      return numer/denom;
    }else {
      *zerodiv= True;
      return 0.0;
    }
  }
  temp= denom/numer;
  if (temp > mindenom1 || temp < -mindenom1) {
    *zerodiv= False;
    return numer/denom;
  }else {
    *zerodiv= True;
    return 0.0;
  }
} /* divzero */


/*---------------------------------

  qh_facetarea(qh, facet )
    return area for a facet

  notes:
    if non-simplicial,
      uses centrum to triangulate facet and sums the projected areas.
    if (qh->DELAUNAY),
      computes projected area instead for last coordinate
    assumes facet->normal exists
    projecting tricoplanar facets to the hyperplane does not appear to make a difference

  design:
    if simplicial
      compute area
    else
      for each ridge
        compute area from centrum to ridge
    negate area if upper Delaunay facet
*/
realT qh_facetarea(qhT *qh, facetT *facet) {
  vertexT *apex;
  pointT *centrum;
  realT area= 0.0;
  ridgeT *ridge, **ridgep;

  if (facet->simplicial) {
    apex= SETfirstt_(facet->vertices, vertexT);
    area= qh_facetarea_simplex(qh, qh->hull_dim, apex->point, facet->vertices,
                    apex, facet->toporient, facet->normal, &facet->offset);
  }else {
    if (qh->CENTERtype == qh_AScentrum)
      centrum= facet->center;
    else
      centrum= qh_getcentrum(qh, facet);
    FOREACHridge_(facet->ridges)
      area += qh_facetarea_simplex(qh, qh->hull_dim, centrum, ridge->vertices,
                 NULL, (boolT)(ridge->top == facet),  facet->normal, &facet->offset);
    if (qh->CENTERtype != qh_AScentrum)
      qh_memfree(qh, centrum, qh->normal_size);
  }
  if (facet->upperdelaunay && qh->DELAUNAY)
    area= -area;  /* the normal should be [0,...,1] */
  trace4((qh, qh->ferr, 4009, "qh_facetarea: f%d area %2.2g\n", facet->id, area));
  return area;
} /* facetarea */

/*---------------------------------

  qh_facetarea_simplex(qh, dim, apex, vertices, notvertex, toporient, normal, offset )
    return area for a simplex defined by
      an apex, a base of vertices, an orientation, and a unit normal
    if simplicial or tricoplanar facet,
      notvertex is defined and it is skipped in vertices

  returns:
    computes area of simplex projected to plane [normal,offset]
    returns 0 if vertex too far below plane (qh->WIDEfacet)
      vertex can't be apex of tricoplanar facet

  notes:
    if (qh->DELAUNAY),
      computes projected area instead for last coordinate
    uses qh->gm_matrix/gm_row and qh->hull_dim
    helper function for qh_facetarea

  design:
    if Notvertex
      translate simplex to apex
    else
      project simplex to normal/offset
      translate simplex to apex
    if Delaunay
      set last row/column to 0 with -1 on diagonal
    else
      set last row to Normal
    compute determinate
    scale and flip sign for area
*/
realT qh_facetarea_simplex(qhT *qh, int dim, coordT *apex, setT *vertices,
        vertexT *notvertex,  boolT toporient, coordT *normal, realT *offset) {
  pointT *coorda, *coordp, *gmcoord;
  coordT **rows, *normalp;
  int k,  i=0;
  realT area, dist;
  vertexT *vertex, **vertexp;
  boolT nearzero;

  gmcoord= qh->gm_matrix;
  rows= qh->gm_row;
  FOREACHvertex_(vertices) {
    if (vertex == notvertex)
      continue;
    rows[i++]= gmcoord;
    coorda= apex;
    coordp= vertex->point;
    normalp= normal;
    if (notvertex) {
      for (k=dim; k--; )
        *(gmcoord++)= *coordp++ - *coorda++;
    }else {
      dist= *offset;
      for (k=dim; k--; )
        dist += *coordp++ * *normalp++;
      if (dist < -qh->WIDEfacet) {
        zinc_(Znoarea);
        return 0.0;
      }
      coordp= vertex->point;
      normalp= normal;
      for (k=dim; k--; )
        *(gmcoord++)= (*coordp++ - dist * *normalp++) - *coorda++;
    }
  }
  if (i != dim-1) {
    qh_fprintf(qh, qh->ferr, 6008, "qhull internal error (qh_facetarea_simplex): #points %d != dim %d -1\n",
               i, dim);
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  rows[i]= gmcoord;
  if (qh->DELAUNAY) {
    for (i=0; i < dim-1; i++)
      rows[i][dim-1]= 0.0;
    for (k=dim; k--; )
      *(gmcoord++)= 0.0;
    rows[dim-1][dim-1]= -1.0;
  }else {
    normalp= normal;
    for (k=dim; k--; )
      *(gmcoord++)= *normalp++;
  }
  zinc_(Zdetfacetarea);
  area= qh_determinant(qh, rows, dim, &nearzero);
  if (toporient)
    area= -area;
  area *= qh->AREAfactor;
  trace4((qh, qh->ferr, 4010, "qh_facetarea_simplex: area=%2.2g for point p%d, toporient %d, nearzero? %d\n",
          area, qh_pointid(qh, apex), toporient, nearzero));
  return area;
} /* facetarea_simplex */

/*---------------------------------

  qh_facetcenter(qh, vertices )
    return Voronoi center (Voronoi vertex) for a facet's vertices

  returns:
    return temporary point equal to the center

  see:
    qh_voronoi_center()
*/
pointT *qh_facetcenter(qhT *qh, setT *vertices) {
  setT *points= qh_settemp(qh, qh_setsize(qh, vertices));
  vertexT *vertex, **vertexp;
  pointT *center;

  FOREACHvertex_(vertices)
    qh_setappend(qh, &points, vertex->point);
  center= qh_voronoi_center(qh, qh->hull_dim-1, points);
  qh_settempfree(qh, &points);
  return center;
} /* facetcenter */

/*---------------------------------

  qh_findgooddist(qh, point, facetA, dist, facetlist )
    find best good facet visible for point from facetA
    assumes facetA is visible from point

  returns:
    best facet, i.e., good facet that is furthest from point
      distance to best facet
      NULL if none

    moves good, visible facets (and some other visible facets)
      to end of qh->facet_list

  notes:
    uses qh->visit_id

  design:
    initialize bestfacet if facetA is good
    move facetA to end of facetlist
    for each facet on facetlist
      for each unvisited neighbor of facet
        move visible neighbors to end of facetlist
        update best good neighbor
        if no good neighbors, update best facet
*/
facetT *qh_findgooddist(qhT *qh, pointT *point, facetT *facetA, realT *distp,
               facetT **facetlist) {
  realT bestdist= -REALmax, dist;
  facetT *neighbor, **neighborp, *bestfacet=NULL, *facet;
  boolT goodseen= False;

  if (facetA->good) {
    zzinc_(Zcheckpart);  /* calls from check_bestdist occur after print stats */
    qh_distplane(qh, point, facetA, &bestdist);
    bestfacet= facetA;
    goodseen= True;
  }
  qh_removefacet(qh, facetA);
  qh_appendfacet(qh, facetA);
  *facetlist= facetA;
  facetA->visitid= ++qh->visit_id;
  FORALLfacet_(*facetlist) {
    FOREACHneighbor_(facet) {
      if (neighbor->visitid == qh->visit_id)
        continue;
      neighbor->visitid= qh->visit_id;
      if (goodseen && !neighbor->good)
        continue;
      zzinc_(Zcheckpart);
      qh_distplane(qh, point, neighbor, &dist);
      if (dist > 0) {
        qh_removefacet(qh, neighbor);
        qh_appendfacet(qh, neighbor);
        if (neighbor->good) {
          goodseen= True;
          if (dist > bestdist) {
            bestdist= dist;
            bestfacet= neighbor;
          }
        }
      }
    }
  }
  if (bestfacet) {
    *distp= bestdist;
    trace2((qh, qh->ferr, 2003, "qh_findgooddist: p%d is %2.2g above good facet f%d\n",
      qh_pointid(qh, point), bestdist, bestfacet->id));
    return bestfacet;
  }
  trace4((qh, qh->ferr, 4011, "qh_findgooddist: no good facet for p%d above f%d\n",
      qh_pointid(qh, point), facetA->id));
  return NULL;
}  /* findgooddist */

/*---------------------------------

  qh_furthestnewvertex(qh, unvisited, facet, &maxdist )
    return furthest unvisited, new vertex to a facet

  return:
    NULL if no vertex is above facet
    maxdist to facet
    updates v.visitid

  notes:
    Ignores vertices in facetB
    Does not change qh.vertex_visit.  Use in conjunction with qh_furthestvertex
*/
vertexT *qh_furthestnewvertex(qhT *qh, unsigned int unvisited, facetT *facet, realT *maxdistp /* qh.newvertex_list */) {
  vertexT *maxvertex= NULL, *vertex;
  coordT dist, maxdist= 0.0;

  FORALLvertex_(qh->newvertex_list) {
    if (vertex->newfacet && vertex->visitid <= unvisited) {
      vertex->visitid= qh->vertex_visit;
      qh_distplane(qh, vertex->point, facet, &dist);
      if (dist > maxdist) {
        maxdist= dist;
        maxvertex= vertex;
      }
    }
  }
  trace4((qh, qh->ferr, 4085, "qh_furthestnewvertex: v%d dist %2.2g is furthest new vertex for f%d\n",
    getid_(maxvertex), maxdist, facet->id));
  *maxdistp= maxdist;
  return maxvertex;
} /* furthestnewvertex */

/*---------------------------------

  qh_furthestvertex(qh, facetA, facetB, &maxdist, &mindist )
    return furthest vertex in facetA from facetB, or NULL if none

  return:
    maxdist and mindist to facetB or 0.0 if none
    updates qh.vertex_visit

  notes:
    Ignores vertices in facetB
*/
vertexT *qh_furthestvertex(qhT *qh, facetT *facetA, facetT *facetB, realT *maxdistp, realT *mindistp) {
  vertexT *maxvertex= NULL, *vertex, **vertexp;
  coordT dist, maxdist= -REALmax, mindist= REALmax;

  qh->vertex_visit++;
  FOREACHvertex_(facetB->vertices)
    vertex->visitid= qh->vertex_visit;
  FOREACHvertex_(facetA->vertices) {
    if (vertex->visitid != qh->vertex_visit) {
      vertex->visitid= qh->vertex_visit;
      zzinc_(Zvertextests);
      qh_distplane(qh, vertex->point, facetB, &dist);
      if (!maxvertex) {
        maxdist= dist;
        mindist= dist;
        maxvertex= vertex;
      }else if (dist > maxdist) {
        maxdist= dist;
        maxvertex= vertex;
      }else if (dist < mindist)
        mindist= dist;
    }
  }
  if (!maxvertex) {
    trace3((qh, qh->ferr, 3067, "qh_furthestvertex: all vertices of f%d are in f%d.  Returning 0.0 for max and mindist\n",
      facetA->id, facetB->id));
    maxdist= mindist= 0.0;
  }else {
    trace4((qh, qh->ferr, 4084, "qh_furthestvertex: v%d dist %2.2g is furthest (mindist %2.2g) of f%d above f%d\n",
      maxvertex->id, maxdist, mindist, facetA->id, facetB->id));
  }
  *maxdistp= maxdist;
  *mindistp= mindist;
  return maxvertex;
} /* furthestvertex */

/*---------------------------------

  qh_getarea(qh, facetlist )
    set area of all facets in facetlist
    collect statistics
    nop if hasAreaVolume

  returns:
    sets qh->totarea/totvol to total area and volume of convex hull
    for Delaunay triangulation, computes projected area of the lower or upper hull
      ignores upper hull if qh->ATinfinity

  notes:
    could compute outer volume by expanding facet area by rays from interior
    the following attempt at perpendicular projection underestimated badly:
      qh.totoutvol += (-dist + facet->maxoutside + qh->DISTround)
                            * area/ qh->hull_dim;
  design:
    for each facet on facetlist
      compute facet->area
      update qh.totarea and qh.totvol
*/
void qh_getarea(qhT *qh, facetT *facetlist) {
  realT area;
  realT dist;
  facetT *facet;

  if (qh->hasAreaVolume)
    return;
  if (qh->REPORTfreq)
    qh_fprintf(qh, qh->ferr, 8020, "computing area of each facet and volume of the convex hull\n");
  else
    trace1((qh, qh->ferr, 1001, "qh_getarea: computing area for each facet and its volume to qh.interior_point (dist*area/dim)\n"));
  qh->totarea= qh->totvol= 0.0;
  FORALLfacet_(facetlist) {
    if (!facet->normal)
      continue;
    if (facet->upperdelaunay && qh->ATinfinity)
      continue;
    if (!facet->isarea) {
      facet->f.area= qh_facetarea(qh, facet);
      facet->isarea= True;
    }
    area= facet->f.area;
    if (qh->DELAUNAY) {
      if (facet->upperdelaunay == qh->UPPERdelaunay)
        qh->totarea += area;
    }else {
      qh->totarea += area;
      qh_distplane(qh, qh->interior_point, facet, &dist);
      qh->totvol += -dist * area/ qh->hull_dim;
    }
    if (qh->PRINTstatistics) {
      wadd_(Wareatot, area);
      wmax_(Wareamax, area);
      wmin_(Wareamin, area);
    }
  }
  qh->hasAreaVolume= True;
} /* getarea */

/*---------------------------------

  qh_gram_schmidt(qh, dim, row )
    implements Gram-Schmidt orthogonalization by rows

  returns:
    false if zero norm
    overwrites rows[dim][dim]

  notes:
    see Golub & van Loan, 1983, Algorithm 6.2-2, "Modified Gram-Schmidt"
    overflow due to small divisors not handled

  design:
    for each row
      compute norm for row
      if non-zero, normalize row
      for each remaining rowA
        compute inner product of row and rowA
        reduce rowA by row * inner product
*/
boolT qh_gram_schmidt(qhT *qh, int dim, realT **row) {
  realT *rowi, *rowj, norm;
  int i, j, k;

  for (i=0; i < dim; i++) {
    rowi= row[i];
    for (norm=0.0, k=dim; k--; rowi++)
      norm += *rowi * *rowi;
    norm= sqrt(norm);
    wmin_(Wmindenom, norm);
    if (norm == 0.0)  /* either 0 or overflow due to sqrt */
      return False;
    for (k=dim; k--; )
      *(--rowi) /= norm;
    for (j=i+1; j < dim; j++) {
      rowj= row[j];
      for (norm=0.0, k=dim; k--; )
        norm += *rowi++ * *rowj++;
      for (k=dim; k--; )
        *(--rowj) -= *(--rowi) * norm;
    }
  }
  return True;
} /* gram_schmidt */


/*---------------------------------

  qh_inthresholds(qh, normal, angle )
    return True if normal within qh.lower_/upper_threshold

  returns:
    estimate of angle by summing of threshold diffs
      angle may be NULL
      smaller "angle" is better

  notes:
    invalid if qh.SPLITthresholds

  see:
    qh.lower_threshold in qh_initbuild()
    qh_initthresholds()

  design:
    for each dimension
      test threshold
*/
boolT qh_inthresholds(qhT *qh, coordT *normal, realT *angle) {
  boolT within= True;
  int k;
  realT threshold;

  if (angle)
    *angle= 0.0;
  for (k=0; k < qh->hull_dim; k++) {
    threshold= qh->lower_threshold[k];
    if (threshold > -REALmax/2) {
      if (normal[k] < threshold)
        within= False;
      if (angle) {
        threshold -= normal[k];
        *angle += fabs_(threshold);
      }
    }
    if (qh->upper_threshold[k] < REALmax/2) {
      threshold= qh->upper_threshold[k];
      if (normal[k] > threshold)
        within= False;
      if (angle) {
        threshold -= normal[k];
        *angle += fabs_(threshold);
      }
    }
  }
  return within;
} /* inthresholds */


/*---------------------------------

  qh_joggleinput(qh)
    randomly joggle input to Qhull by qh.JOGGLEmax
    initial input is qh.first_point/qh.num_points of qh.hull_dim
      repeated calls use qh.input_points/qh.num_points

  returns:
    joggles points at qh.first_point/qh.num_points
    copies data to qh.input_points/qh.input_malloc if first time
    determines qh.JOGGLEmax if it was zero
    if qh.DELAUNAY
      computes the Delaunay projection of the joggled points

  notes:
    if qh.DELAUNAY, unnecessarily joggles the last coordinate
    the initial 'QJn' may be set larger than qh_JOGGLEmaxincrease

  design:
    if qh.DELAUNAY
      set qh.SCALElast for reduced precision errors
    if first call
      initialize qh.input_points to the original input points
      if qh.JOGGLEmax == 0
        determine default qh.JOGGLEmax
    else
      increase qh.JOGGLEmax according to qh.build_cnt
    joggle the input by adding a random number in [-qh.JOGGLEmax,qh.JOGGLEmax]
    if qh.DELAUNAY
      sets the Delaunay projection
*/
void qh_joggleinput(qhT *qh) {
  int i, seed, size;
  coordT *coordp, *inputp;
  realT randr, randa, randb;

  if (!qh->input_points) { /* first call */
    qh->input_points= qh->first_point;
    qh->input_malloc= qh->POINTSmalloc;
    size= qh->num_points * qh->hull_dim * (int)sizeof(coordT);
    if (!(qh->first_point= (coordT *)qh_malloc((size_t)size))) {
      qh_fprintf(qh, qh->ferr, 6009, "qhull error: insufficient memory to joggle %d points\n",
          qh->num_points);
      qh_errexit(qh, qh_ERRmem, NULL, NULL);
    }
    qh->POINTSmalloc= True;
    if (qh->JOGGLEmax == 0.0) {
      qh->JOGGLEmax= qh_detjoggle(qh, qh->input_points, qh->num_points, qh->hull_dim);
      qh_option(qh, "QJoggle", NULL, &qh->JOGGLEmax);
    }
  }else {                 /* repeated call */
    if (!qh->RERUN && qh->build_cnt > qh_JOGGLEretry) {
      if (((qh->build_cnt-qh_JOGGLEretry-1) % qh_JOGGLEagain) == 0) {
        realT maxjoggle= qh->MAXwidth * qh_JOGGLEmaxincrease;
        if (qh->JOGGLEmax < maxjoggle) {
          qh->JOGGLEmax *= qh_JOGGLEincrease;
          minimize_(qh->JOGGLEmax, maxjoggle);
        }
      }
    }
    qh_option(qh, "QJoggle", NULL, &qh->JOGGLEmax);
  }
  if (qh->build_cnt > 1 && qh->JOGGLEmax > fmax_(qh->MAXwidth/4, 0.1)) {
      qh_fprintf(qh, qh->ferr, 6010, "qhull input error (qh_joggleinput): the current joggle for 'QJn', %.2g, is too large for the width\nof the input.  If possible, recompile Qhull with higher-precision reals.\n",
                qh->JOGGLEmax);
      qh_errexit(qh, qh_ERRinput, NULL, NULL);
  }
  /* for some reason, using qh->ROTATErandom and qh_RANDOMseed does not repeat the run. Use 'TRn' instead */
  seed= qh_RANDOMint;
  qh_option(qh, "_joggle-seed", &seed, NULL);
  trace0((qh, qh->ferr, 6, "qh_joggleinput: joggle input by %4.4g with seed %d\n",
    qh->JOGGLEmax, seed));
  inputp= qh->input_points;
  coordp= qh->first_point;
  randa= 2.0 * qh->JOGGLEmax/qh_RANDOMmax;
  randb= -qh->JOGGLEmax;
  size= qh->num_points * qh->hull_dim;
  for (i=size; i--; ) {
    randr= qh_RANDOMint;
    *(coordp++)= *(inputp++) + (randr * randa + randb);
  }
  if (qh->DELAUNAY) {
    qh->last_low= qh->last_high= qh->last_newhigh= REALmax;
    qh_setdelaunay(qh, qh->hull_dim, qh->num_points, qh->first_point);
  }
} /* joggleinput */

/*---------------------------------

  qh_maxabsval( normal, dim )
    return pointer to maximum absolute value of a dim vector
    returns NULL if dim=0
*/
realT *qh_maxabsval(realT *normal, int dim) {
  realT maxval= -REALmax;
  realT *maxp= NULL, *colp, absval;
  int k;

  for (k=dim, colp= normal; k--; colp++) {
    absval= fabs_(*colp);
    if (absval > maxval) {
      maxval= absval;
      maxp= colp;
    }
  }
  return maxp;
} /* maxabsval */


/*---------------------------------

  qh_maxmin(qh, points, numpoints, dimension )
    return max/min points for each dimension
    determine max and min coordinates

  returns:
    returns a temporary set of max and min points
      may include duplicate points. Does not include qh.GOODpoint
    sets qh.NEARzero, qh.MAXabs_coord, qh.MAXsumcoord, qh.MAXwidth
         qh.MAXlastcoord, qh.MINlastcoord
    initializes qh.max_outside, qh.min_vertex, qh.WAScoplanar, qh.ZEROall_ok

  notes:
    loop duplicated in qh_detjoggle()

  design:
    initialize global precision variables
    checks definition of REAL...
    for each dimension
      for each point
        collect maximum and minimum point
      collect maximum of maximums and minimum of minimums
      determine qh.NEARzero for Gaussian Elimination
*/
setT *qh_maxmin(qhT *qh, pointT *points, int numpoints, int dimension) {
  int k;
  realT maxcoord, temp;
  pointT *minimum, *maximum, *point, *pointtemp;
  setT *set;

  qh->max_outside= 0.0;
  qh->MAXabs_coord= 0.0;
  qh->MAXwidth= -REALmax;
  qh->MAXsumcoord= 0.0;
  qh->min_vertex= 0.0;
  qh->WAScoplanar= False;
  if (qh->ZEROcentrum)
    qh->ZEROall_ok= True;
  if (REALmin < REALepsilon && REALmin < REALmax && REALmin > -REALmax
  && REALmax > 0.0 && -REALmax < 0.0)
    ; /* all ok */
  else {
    qh_fprintf(qh, qh->ferr, 6011, "qhull error: one or more floating point constants in user_r.h are inconsistent. REALmin %g, -REALmax %g, 0.0, REALepsilon %g, REALmax %g\n",
          REALmin, -REALmax, REALepsilon, REALmax);
    qh_errexit(qh, qh_ERRinput, NULL, NULL);
  }
  set= qh_settemp(qh, 2*dimension);
  trace1((qh, qh->ferr, 8082, "qh_maxmin: dim             min             max           width    nearzero  min-point  max-point\n"));
  for (k=0; k < dimension; k++) {
    if (points == qh->GOODpointp)
      minimum= maximum= points + dimension;
    else
      minimum= maximum= points;
    FORALLpoint_(qh, points, numpoints) {
      if (point == qh->GOODpointp)
        continue;
      if (maximum[k] < point[k])
        maximum= point;
      else if (minimum[k] > point[k])
        minimum= point;
    }
    if (k == dimension-1) {
      qh->MINlastcoord= minimum[k];
      qh->MAXlastcoord= maximum[k];
    }
    if (qh->SCALElast && k == dimension-1)
      maxcoord= qh->MAXabs_coord;
    else {
      maxcoord= fmax_(maximum[k], -minimum[k]);
      if (qh->GOODpointp) {
        temp= fmax_(qh->GOODpointp[k], -qh->GOODpointp[k]);
        maximize_(maxcoord, temp);
      }
      temp= maximum[k] - minimum[k];
      maximize_(qh->MAXwidth, temp);
    }
    maximize_(qh->MAXabs_coord, maxcoord);
    qh->MAXsumcoord += maxcoord;
    qh_setappend(qh, &set, minimum);
    qh_setappend(qh, &set, maximum);
    /* calculation of qh NEARzero is based on Golub & van Loan, 1983,
       Eq. 4.4-13 for "Gaussian elimination with complete pivoting".
       Golub & van Loan say that n^3 can be ignored and 10 be used in
       place of rho */
    qh->NEARzero[k]= 80 * qh->MAXsumcoord * REALepsilon;
    trace1((qh, qh->ferr, 8106, "           %3d % 14.8e % 14.8e % 14.8e  %4.4e  p%-9d p%-d\n",
            k, minimum[k], maximum[k], maximum[k]-minimum[k], qh->NEARzero[k], qh_pointid(qh, minimum), qh_pointid(qh, maximum)));
    if (qh->SCALElast && k == dimension-1)
      trace1((qh, qh->ferr, 8107, "           last coordinate scaled to (%4.4g, %4.4g), width %4.4e for option 'Qbb'\n",
            qh->MAXabs_coord - qh->MAXwidth, qh->MAXabs_coord, qh->MAXwidth));
  }
  if (qh->IStracing >= 1)
    qh_printpoints(qh, qh->ferr, "qh_maxmin: found the max and min points (by dim):", set);
  return(set);
} /* maxmin */

/*---------------------------------

  qh_maxouter(qh)
    return maximum distance from facet to outer plane
    normally this is qh.max_outside+qh.DISTround
    does not include qh.JOGGLEmax

  see:
    qh_outerinner()

  notes:
    need to add another qh.DISTround if testing actual point with computation
    see qh_detmaxoutside for a qh_RATIO... target

  for joggle:
    qh_setfacetplane() updated qh.max_outer for Wnewvertexmax (max distance to vertex)
    need to use Wnewvertexmax since could have a coplanar point for a high
      facet that is replaced by a low facet
    need to add qh.JOGGLEmax if testing input points
*/
realT qh_maxouter(qhT *qh) {
  realT dist;

  dist= fmax_(qh->max_outside, qh->DISTround);
  dist += qh->DISTround;
  trace4((qh, qh->ferr, 4012, "qh_maxouter: max distance from facet to outer plane is %4.4g, qh.max_outside is %4.4g\n", dist, qh->max_outside));
  return dist;
} /* maxouter */

/*---------------------------------

  qh_maxsimplex(qh, dim, maxpoints, points, numpoints, simplex )
    determines maximum simplex for a set of points
    maxpoints is the subset of points with a min or max coordinate
    may start with points already in simplex
    skips qh.GOODpointp (assumes that it isn't in maxpoints)

  returns:
    simplex with dim+1 points

  notes:
    called by qh_initialvertices, qh_detvnorm, and qh_voronoi_center
    requires qh.MAXwidth to estimate determinate for each vertex
    assumes at least needed 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)
    create a simplex of dim+1 vertices as follows
      add point from maxpoints that maximizes the determinate of the point and the simplex vertices  
      if last point and maxdet/prevdet < qh_RATIOmaxsimplex (3.0e-2)
        flag maybe_falsenarrow
      if no maxpoint or maxnearzero or maybe_falsenarrow
        search all points for maximum determinate
        early exit if maybe_falsenarrow and !maxnearzero and maxdet > prevdet
*/
void qh_maxsimplex(qhT *qh, int dim, setT *maxpoints, pointT *points, int numpoints, setT **simplex) {
  pointT *point, **pointp, *pointtemp, *maxpoint, *minx=NULL, *maxx=NULL;
  boolT nearzero, maxnearzero= False, maybe_falsenarrow;
  int i, sizinit;
  realT maxdet= -1.0, prevdet= -1.0, det, mincoord= REALmax, maxcoord= -REALmax, mindet, ratio, targetdet;

  if (qh->MAXwidth <= 0.0) {
    qh_fprintf(qh, qh->ferr, 6421, "qhull internal error (qh_maxsimplex): qh.MAXwidth required for qh_maxsimplex.  Used to estimate determinate\n");
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  sizinit= qh_setsize(qh, *simplex);
  if (sizinit >= 2) {
    maxdet= pow(qh->MAXwidth, sizinit - 1);
  }else {
    if (qh_setsize(qh, maxpoints) >= 2) {
      FOREACHpoint_(maxpoints) {
        if (maxcoord < point[0]) {
          maxcoord= point[0];
          maxx= point;
        }
        if (mincoord > point[0]) {
          mincoord= point[0];
          minx= point;
        }
      }
    }else {
      FORALLpoint_(qh, points, numpoints) {
        if (point == qh->GOODpointp)
          continue;
        if (maxcoord < point[0]) {
          maxcoord= point[0];
          maxx= point;
        }
        if (mincoord > point[0]) {
          mincoord= point[0];
          minx= point;
        }
      }
    }
    maxdet= maxcoord - mincoord;
    qh_setunique(qh, simplex, minx);
    if (qh_setsize(qh, *simplex) < 2)
      qh_setunique(qh, simplex, maxx);
    sizinit= qh_setsize(qh, *simplex);
    if (sizinit < 2) {
      qh_joggle_restart(qh, "input has same x coordinate");
      if (zzval_(Zsetplane) > qh->hull_dim+1) {
        qh_fprintf(qh, qh->ferr, 6012, "qhull precision error (qh_maxsimplex for voronoi_center): %d points with the same x coordinate %4.4g\n",
                 qh_setsize(qh, maxpoints)+numpoints, mincoord);
        qh_errexit(qh, qh_ERRprec, NULL, NULL);
      }else {
        qh_fprintf(qh, qh->ferr, 6013, "qhull input error: input is less than %d-dimensional since all points have the same x coordinate %4.4g\n",
                 qh->hull_dim, mincoord);
        qh_errexit(qh, qh_ERRinput, NULL, NULL);
      }
    }
  }
  for (i=sizinit; i < dim+1; i++) {
    prevdet= maxdet;
    maxpoint= NULL;
    maxdet= -1.0;
    FOREACHpoint_(maxpoints) {
      if (!qh_setin(*simplex, point) && point != maxpoint) {
        det= qh_detsimplex(qh, point, *simplex, i, &nearzero); /* retests maxpoints if duplicate or multiple iterations */
        if ((det= fabs_(det)) > maxdet) {
          maxdet= det;
          maxpoint= point;
          maxnearzero= nearzero;
        }
      }
    }
    maybe_falsenarrow= False;
    ratio= 1.0;
    targetdet= prevdet * qh->MAXwidth;
    mindet= 10 * qh_RATIOmaxsimplex * targetdet;
    if (maxdet > 0.0) {
      ratio= maxdet / targetdet;
      if (ratio < qh_RATIOmaxsimplex)
        maybe_falsenarrow= True;
    }
    if (!maxpoint || maxnearzero || maybe_falsenarrow) {
      zinc_(Zsearchpoints);
      if (!maxpoint) {
        trace0((qh, qh->ferr, 7, "qh_maxsimplex: searching all points for %d-th initial vertex, better than mindet %4.4g, targetdet %4.4g\n",
                i+1, mindet, targetdet));
      }else if (qh->ALLpoints) {
        trace0((qh, qh->ferr, 30, "qh_maxsimplex: searching all points ('Qs') for %d-th initial vertex, better than p%d det %4.4g, targetdet %4.4g, ratio %4.4g\n",
                i+1, qh_pointid(qh, maxpoint), maxdet, targetdet, ratio));
      }else if (maybe_falsenarrow) {
        trace0((qh, qh->ferr, 17, "qh_maxsimplex: searching all points for %d-th initial vertex, better than p%d det %4.4g and mindet %4.4g, ratio %4.4g\n",
                i+1, qh_pointid(qh, maxpoint), maxdet, mindet, ratio));
      }else {
        trace0((qh, qh->ferr, 8, "qh_maxsimplex: searching all points for %d-th initial vertex, better than p%d det %2.2g and mindet %4.4g, targetdet %4.4g\n",
                i+1, qh_pointid(qh, maxpoint), maxdet, mindet, targetdet));
      }
      FORALLpoint_(qh, points, numpoints) {
        if (point == qh->GOODpointp)
          continue;
        if (!qh_setin(maxpoints, point) && !qh_setin(*simplex, point)) {
          det= qh_detsimplex(qh, point, *simplex, i, &nearzero);
          if ((det= fabs_(det)) > maxdet) {
            maxdet= det;
            maxpoint= point;
            maxnearzero= nearzero;
            if (!maxnearzero && !qh->ALLpoints && maxdet > mindet)
              break;
          }
        }
      }
    } /* !maxpoint */
    if (!maxpoint) {
      qh_fprintf(qh, qh->ferr, 6014, "qhull internal error (qh_maxsimplex): not enough points available\n");
      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
    }
    qh_setappend(qh, simplex, maxpoint);
    trace1((qh, qh->ferr, 1002, "qh_maxsimplex: selected point p%d for %d`th initial vertex, det=%4.4g, targetdet=%4.4g, mindet=%4.4g\n",
            qh_pointid(qh, maxpoint), i+1, maxdet, prevdet * qh->MAXwidth, mindet));
  } /* i */
} /* maxsimplex */

/*---------------------------------

  qh_minabsval( normal, dim )
    return minimum absolute value of a dim vector
*/
realT qh_minabsval(realT *normal, int dim) {
  realT minval= 0;
  realT maxval= 0;
  realT *colp;
  int k;

  for (k=dim, colp=normal; k--; colp++) {
    maximize_(maxval, *colp);
    minimize_(minval, *colp);
  }
  return fmax_(maxval, -minval);
} /* minabsval */


/*---------------------------------

  qh_mindif(qh, vecA, vecB, dim )
    return index of min abs. difference of two vectors
*/
int qh_mindiff(realT *vecA, realT *vecB, int dim) {
  realT mindiff= REALmax, diff;
  realT *vecAp= vecA, *vecBp= vecB;
  int k, mink= 0;

  for (k=0; k < dim; k++) {
    diff= *vecAp++ - *vecBp++;
    diff= fabs_(diff);
    if (diff < mindiff) {
      mindiff= diff;
      mink= k;
    }
  }
  return mink;
} /* mindiff */



/*---------------------------------

  qh_orientoutside(qh, facet  )
    make facet outside oriented via qh.interior_point

  returns:
    True if facet reversed orientation.
*/
boolT qh_orientoutside(qhT *qh, facetT *facet) {
  int k;
  realT dist;

  qh_distplane(qh, qh->interior_point, facet, &dist);
  if (dist > 0) {
    for (k=qh->hull_dim; k--; )
      facet->normal[k]= -facet->normal[k];
    facet->offset= -facet->offset;
    return True;
  }
  return False;
} /* orientoutside */

/*---------------------------------

  qh_outerinner(qh, facet, outerplane, innerplane  )
    if facet and qh.maxoutdone (i.e., qh_check_maxout)
      returns outer and inner plane for facet
    else
      returns maximum outer and inner plane
    accounts for qh.JOGGLEmax

  see:
    qh_maxouter(qh), qh_check_bestdist(), qh_check_points()

  notes:
    outerplaner or innerplane may be NULL
    facet is const
    Does not error (QhullFacet)

    includes qh.DISTround for actual points
    adds another qh.DISTround if testing with floating point arithmetic
*/
void qh_outerinner(qhT *qh, facetT *facet, realT *outerplane, realT *innerplane) {
  realT dist, mindist;
  vertexT *vertex, **vertexp;

  if (outerplane) {
    if (!qh_MAXoutside || !facet || !qh->maxoutdone) {
      *outerplane= qh_maxouter(qh);       /* includes qh.DISTround */
    }else { /* qh_MAXoutside ... */
#if qh_MAXoutside
      *outerplane= facet->maxoutside + qh->DISTround;
#endif

    }
    if (qh->JOGGLEmax < REALmax/2)
      *outerplane += qh->JOGGLEmax * sqrt((realT)qh->hull_dim);
  }
  if (innerplane) {
    if (facet) {
      mindist= REALmax;
      FOREACHvertex_(facet->vertices) {
        zinc_(Zdistio);
        qh_distplane(qh, vertex->point, facet, &dist);
        minimize_(mindist, dist);
      }
      *innerplane= mindist - qh->DISTround;
    }else
      *innerplane= qh->min_vertex - qh->DISTround;
    if (qh->JOGGLEmax < REALmax/2)
      *innerplane -= qh->JOGGLEmax * sqrt((realT)qh->hull_dim);
  }
} /* outerinner */

/*---------------------------------

  qh_pointdist( point1, point2, dim )
    return distance between two points

  notes:
    returns distance squared if 'dim' is negative
*/
coordT qh_pointdist(pointT *point1, pointT *point2, int dim) {
  coordT dist, diff;
  int k;

  dist= 0.0;
  for (k= (dim > 0 ? dim : -dim); k--; ) {
    diff= *point1++ - *point2++;
    dist += diff * diff;
  }
  if (dim > 0)
    return(sqrt(dist));
  return dist;
} /* pointdist */


/*---------------------------------

  qh_printmatrix(qh, fp, string, rows, numrow, numcol )
    print matrix to fp given by row vectors
    print string as header
    qh may be NULL if fp is defined

  notes:
    print a vector by qh_printmatrix(qh, fp, "", &vect, 1, len)
*/
void qh_printmatrix(qhT *qh, FILE *fp, const char *string, realT **rows, int numrow, int numcol) {
  realT *rowp;
  realT r; /*bug fix*/
  int i,k;

  qh_fprintf(qh, fp, 9001, "%s\n", string);
  for (i=0; i < numrow; i++) {
    rowp= rows[i];
    for (k=0; k < numcol; k++) {
      r= *rowp++;
      qh_fprintf(qh, fp, 9002, "%6.3g ", r);
    }
    qh_fprintf(qh, fp, 9003, "\n");
  }
} /* printmatrix */


/*---------------------------------

  qh_printpoints(qh, fp, string, points )
    print pointids to fp for a set of points
    if string, prints string and 'p' point ids
*/
void qh_printpoints(qhT *qh, FILE *fp, const char *string, setT *points) {
  pointT *point, **pointp;

  if (string) {
    qh_fprintf(qh, fp, 9004, "%s", string);
    FOREACHpoint_(points)
      qh_fprintf(qh, fp, 9005, " p%d", qh_pointid(qh, point));
    qh_fprintf(qh, fp, 9006, "\n");
  }else {
    FOREACHpoint_(points)
      qh_fprintf(qh, fp, 9007, " %d", qh_pointid(qh, point));
    qh_fprintf(qh, fp, 9008, "\n");
  }
} /* printpoints */


/*---------------------------------

  qh_projectinput(qh)
    project input points using qh.lower_bound/upper_bound and qh->DELAUNAY
    if qh.lower_bound[k]=qh.upper_bound[k]= 0,
      removes dimension k
    if halfspace intersection
      removes dimension k from qh.feasible_point
    input points in qh->first_point, num_points, input_dim

  returns:
    new point array in qh->first_point of qh->hull_dim coordinates
    sets qh->POINTSmalloc
    if qh->DELAUNAY
      projects points to paraboloid
      lowbound/highbound is also projected
    if qh->ATinfinity
      adds point "at-infinity"
    if qh->POINTSmalloc
      frees old point array

  notes:
    checks that qh.hull_dim agrees with qh.input_dim, PROJECTinput, and DELAUNAY


  design:
    sets project[k] to -1 (delete), 0 (keep), 1 (add for Delaunay)
    determines newdim and newnum for qh->hull_dim and qh->num_points
    projects points to newpoints
    projects qh.lower_bound to itself
    projects qh.upper_bound to itself
    if qh->DELAUNAY
      if qh->ATINFINITY
        projects points to paraboloid
        computes "infinity" point as vertex average and 10% above all points
      else
        uses qh_setdelaunay to project points to paraboloid
*/
void qh_projectinput(qhT *qh) {
  int k,i;
  int newdim= qh->input_dim, newnum= qh->num_points;
  signed char *project;
  int projectsize= (qh->input_dim + 1) * (int)sizeof(*project);
  pointT *newpoints, *coord, *infinity;
  realT paraboloid, maxboloid= 0;

  project= (signed char *)qh_memalloc(qh, projectsize);
  memset((char *)project, 0, (size_t)projectsize);
  for (k=0; k < qh->input_dim; k++) {   /* skip Delaunay bound */
    if (qh->lower_bound[k] == 0.0 && qh->upper_bound[k] == 0.0) {
      project[k]= -1;
      newdim--;
    }
  }
  if (qh->DELAUNAY) {
    project[k]= 1;
    newdim++;
    if (qh->ATinfinity)
      newnum++;
  }
  if (newdim != qh->hull_dim) {
    qh_memfree(qh, project, projectsize);
    qh_fprintf(qh, qh->ferr, 6015, "qhull internal error (qh_projectinput): dimension after projection %d != hull_dim %d\n", newdim, qh->hull_dim);
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  if (!(newpoints= qh->temp_malloc= (coordT *)qh_malloc((size_t)(newnum * newdim) * sizeof(coordT)))) {
    qh_memfree(qh, project, projectsize);
    qh_fprintf(qh, qh->ferr, 6016, "qhull error: insufficient memory to project %d points\n",
           qh->num_points);
    qh_errexit(qh, qh_ERRmem, NULL, NULL);
  }
  /* qh_projectpoints throws error if mismatched dimensions */
  qh_projectpoints(qh, project, qh->input_dim+1, qh->first_point,
                    qh->num_points, qh->input_dim, newpoints, newdim);
  trace1((qh, qh->ferr, 1003, "qh_projectinput: updating lower and upper_bound\n"));
  qh_projectpoints(qh, project, qh->input_dim+1, qh->lower_bound,
                    1, qh->input_dim+1, qh->lower_bound, newdim+1);
  qh_projectpoints(qh, project, qh->input_dim+1, qh->upper_bound,
                    1, qh->input_dim+1, qh->upper_bound, newdim+1);
  if (qh->HALFspace) {
    if (!qh->feasible_point) {
      qh_memfree(qh, project, projectsize);
      qh_fprintf(qh, qh->ferr, 6017, "qhull internal error (qh_projectinput): HALFspace defined without qh.feasible_point\n");
      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
    }
    qh_projectpoints(qh, project, qh->input_dim, qh->feasible_point,
                      1, qh->input_dim, qh->feasible_point, newdim);
  }
  qh_memfree(qh, project, projectsize);
  if (qh->POINTSmalloc)
    qh_free(qh->first_point);
  qh->first_point= newpoints;
  qh->POINTSmalloc= True;
  qh->temp_malloc= NULL;
  if (qh->DELAUNAY && qh->ATinfinity) {
    coord= qh->first_point;
    infinity= qh->first_point + qh->hull_dim * qh->num_points;
    for (k=qh->hull_dim-1; k--; )
      infinity[k]= 0.0;
    for (i=qh->num_points; i--; ) {
      paraboloid= 0.0;
      for (k=0; k < qh->hull_dim-1; k++) {
        paraboloid += *coord * *coord;
        infinity[k] += *coord;
        coord++;
      }
      *(coord++)= paraboloid;
      maximize_(maxboloid, paraboloid);
    }
    /* coord == infinity */
    for (k=qh->hull_dim-1; k--; )
      *(coord++) /= qh->num_points;
    *(coord++)= maxboloid * 1.1;
    qh->num_points++;
    trace0((qh, qh->ferr, 9, "qh_projectinput: projected points to paraboloid for Delaunay\n"));
  }else if (qh->DELAUNAY)  /* !qh->ATinfinity */
    qh_setdelaunay(qh, qh->hull_dim, qh->num_points, qh->first_point);
} /* projectinput */


/*---------------------------------

  qh_projectpoints(qh, project, n, points, numpoints, dim, newpoints, newdim )
    project points/numpoints/dim to newpoints/newdim
    if project[k] == -1
      delete dimension k
    if project[k] == 1
      add dimension k by duplicating previous column
    n is size of project

  notes:
    newpoints may be points if only adding dimension at end

  design:
    check that 'project' and 'newdim' agree
    for each dimension
      if project == -1
        skip dimension
      else
        determine start of column in newpoints
        determine start of column in points
          if project == +1, duplicate previous column
        copy dimension (column) from points to newpoints
*/
void qh_projectpoints(qhT *qh, signed char *project, int n, realT *points,
        int numpoints, int dim, realT *newpoints, int newdim) {
  int testdim= dim, oldk=0, newk=0, i,j=0,k;
  realT *newp, *oldp;

  for (k=0; k < n; k++)
    testdim += project[k];
  if (testdim != newdim) {
    qh_fprintf(qh, qh->ferr, 6018, "qhull internal error (qh_projectpoints): newdim %d should be %d after projection\n",
      newdim, testdim);
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  for (j=0; j= dim)
          continue;
        oldp= points+oldk;
      }else
        oldp= points+oldk++;
      for (i=numpoints; i--; ) {
        *newp= *oldp;
        newp += newdim;
        oldp += dim;
      }
    }
    if (oldk >= dim)
      break;
  }
  trace1((qh, qh->ferr, 1004, "qh_projectpoints: projected %d points from dim %d to dim %d\n",
    numpoints, dim, newdim));
} /* projectpoints */


/*---------------------------------

  qh_rotateinput(qh, rows )
    rotate input using row matrix
    input points given by qh->first_point, num_points, hull_dim
    assumes rows[dim] is a scratch buffer
    if qh->POINTSmalloc, overwrites input points, else mallocs a new array

  returns:
    rotated input
    sets qh->POINTSmalloc

  design:
    see qh_rotatepoints
*/
void qh_rotateinput(qhT *qh, realT **rows) {

  if (!qh->POINTSmalloc) {
    qh->first_point= qh_copypoints(qh, qh->first_point, qh->num_points, qh->hull_dim);
    qh->POINTSmalloc= True;
  }
  qh_rotatepoints(qh, qh->first_point, qh->num_points, qh->hull_dim, rows);
}  /* rotateinput */

/*---------------------------------

  qh_rotatepoints(qh, points, numpoints, dim, row )
    rotate numpoints points by a d-dim row matrix
    assumes rows[dim] is a scratch buffer

  returns:
    rotated points in place

  design:
    for each point
      for each coordinate
        use row[dim] to compute partial inner product
      for each coordinate
        rotate by partial inner product
*/
void qh_rotatepoints(qhT *qh, realT *points, int numpoints, int dim, realT **row) {
  realT *point, *rowi, *coord= NULL, sum, *newval;
  int i,j,k;

  if (qh->IStracing >= 1)
    qh_printmatrix(qh, qh->ferr, "qh_rotatepoints: rotate points by", row, dim, dim);
  for (point=points, j=numpoints; j--; point += dim) {
    newval= row[dim];
    for (i=0; i < dim; i++) {
      rowi= row[i];
      coord= point;
      for (sum=0.0, k=dim; k--; )
        sum += *rowi++ * *coord++;
      *(newval++)= sum;
    }
    for (k=dim; k--; )
      *(--coord)= *(--newval);
  }
} /* rotatepoints */


/*---------------------------------

  qh_scaleinput(qh)
    scale input points using qh->low_bound/high_bound
    input points given by qh->first_point, num_points, hull_dim
    if qh->POINTSmalloc, overwrites input points, else mallocs a new array

  returns:
    scales coordinates of points to low_bound[k], high_bound[k]
    sets qh->POINTSmalloc

  design:
    see qh_scalepoints
*/
void qh_scaleinput(qhT *qh) {

  if (!qh->POINTSmalloc) {
    qh->first_point= qh_copypoints(qh, qh->first_point, qh->num_points, qh->hull_dim);
    qh->POINTSmalloc= True;
  }
  qh_scalepoints(qh, qh->first_point, qh->num_points, qh->hull_dim,
       qh->lower_bound, qh->upper_bound);
}  /* scaleinput */

/*---------------------------------

  qh_scalelast(qh, points, numpoints, dim, low, high, newhigh )
    scale last coordinate to [0.0, newhigh], for Delaunay triangulation
    input points given by points, numpoints, dim

  returns:
    changes scale of last coordinate from [low, high] to [0.0, newhigh]
    overwrites last coordinate of each point
    saves low/high/newhigh in qh.last_low, etc. for qh_setdelaunay()

  notes:
    to reduce precision issues, qh_scalelast makes the last coordinate similar to other coordinates
      the last coordinate for Delaunay triangulation is the sum of squares of input coordinates
      note that the range [0.0, newwidth] is wrong for narrow distributions with large positive coordinates (e.g., [995933.64, 995963.48])

    when called by qh_setdelaunay, low/high may not match the data passed to qh_setdelaunay

  design:
    compute scale and shift factors
    apply to last coordinate of each point
*/
void qh_scalelast(qhT *qh, coordT *points, int numpoints, int dim, coordT low,
                   coordT high, coordT newhigh) {
  realT scale, shift;
  coordT *coord, newlow;
  int i;
  boolT nearzero= False;

  newlow= 0.0;
  trace4((qh, qh->ferr, 4013, "qh_scalelast: scale last coordinate from [%2.2g, %2.2g] to [%2.2g, %2.2g]\n",
    low, high, newlow, newhigh));
  qh->last_low= low;
  qh->last_high= high;
  qh->last_newhigh= newhigh;
  scale= qh_divzero(newhigh - newlow, high - low,
                  qh->MINdenom_1, &nearzero);
  if (nearzero) {
    if (qh->DELAUNAY)
      qh_fprintf(qh, qh->ferr, 6019, "qhull input error (qh_scalelast): can not scale last coordinate to [%4.4g, %4.4g].  Input is cocircular or cospherical.   Use option 'Qz' to add a point at infinity.\n",
             newlow, newhigh);
    else
      qh_fprintf(qh, qh->ferr, 6020, "qhull input error (qh_scalelast): can not scale last coordinate to [%4.4g, %4.4g].  New bounds are too wide for compared to existing bounds [%4.4g, %4.4g] (width %4.4g)\n",
             newlow, newhigh, low, high, high-low);
    qh_errexit(qh, qh_ERRinput, NULL, NULL);
  }
  shift= newlow - low * scale;
  coord= points + dim - 1;
  for (i=numpoints; i--; coord += dim)
    *coord= *coord * scale + shift;
} /* scalelast */

/*---------------------------------

  qh_scalepoints(qh, points, numpoints, dim, newlows, newhighs )
    scale points to new lowbound and highbound
    retains old bound when newlow= -REALmax or newhigh= +REALmax

  returns:
    scaled points
    overwrites old points

  design:
    for each coordinate
      compute current low and high bound
      compute scale and shift factors
      scale all points
      enforce new low and high bound for all points
*/
void qh_scalepoints(qhT *qh, pointT *points, int numpoints, int dim,
        realT *newlows, realT *newhighs) {
  int i,k;
  realT shift, scale, *coord, low, high, newlow, newhigh, mincoord, maxcoord;
  boolT nearzero= False;

  for (k=0; k < dim; k++) {
    newhigh= newhighs[k];
    newlow= newlows[k];
    if (newhigh > REALmax/2 && newlow < -REALmax/2)
      continue;
    low= REALmax;
    high= -REALmax;
    for (i=numpoints, coord=points+k; i--; coord += dim) {
      minimize_(low, *coord);
      maximize_(high, *coord);
    }
    if (newhigh > REALmax/2)
      newhigh= high;
    if (newlow < -REALmax/2)
      newlow= low;
    if (qh->DELAUNAY && k == dim-1 && newhigh < newlow) {
      qh_fprintf(qh, qh->ferr, 6021, "qhull input error: 'Qb%d' or 'QB%d' inverts paraboloid since high bound %.2g < low bound %.2g\n",
               k, k, newhigh, newlow);
      qh_errexit(qh, qh_ERRinput, NULL, NULL);
    }
    scale= qh_divzero(newhigh - newlow, high - low,
                  qh->MINdenom_1, &nearzero);
    if (nearzero) {
      qh_fprintf(qh, qh->ferr, 6022, "qhull input error: %d'th dimension's new bounds [%2.2g, %2.2g] too wide for\nexisting bounds [%2.2g, %2.2g]\n",
              k, newlow, newhigh, low, high);
      qh_errexit(qh, qh_ERRinput, NULL, NULL);
    }
    shift= (newlow * high - low * newhigh)/(high-low);
    coord= points+k;
    for (i=numpoints; i--; coord += dim)
      *coord= *coord * scale + shift;
    coord= points+k;
    if (newlow < newhigh) {
      mincoord= newlow;
      maxcoord= newhigh;
    }else {
      mincoord= newhigh;
      maxcoord= newlow;
    }
    for (i=numpoints; i--; coord += dim) {
      minimize_(*coord, maxcoord);  /* because of roundoff error */
      maximize_(*coord, mincoord);
    }
    trace0((qh, qh->ferr, 10, "qh_scalepoints: scaled %d'th coordinate [%2.2g, %2.2g] to [%.2g, %.2g] for %d points by %2.2g and shifted %2.2g\n",
      k, low, high, newlow, newhigh, numpoints, scale, shift));
  }
} /* scalepoints */


/*---------------------------------

  qh_setdelaunay(qh, dim, count, points )
    project count points to dim-d paraboloid for Delaunay triangulation

    dim is one more than the dimension of the input set
    assumes dim is at least 3 (i.e., at least a 2-d Delaunay triangulation)

    points is a dim*count realT array.  The first dim-1 coordinates
    are the coordinates of the first input point.  array[dim] is
    the first coordinate of the second input point.  array[2*dim] is
    the first coordinate of the third input point.

    if qh.last_low defined (i.e., 'Qbb' called qh_scalelast)
      calls qh_scalelast to scale the last coordinate the same as the other points

  returns:
    for each point
      sets point[dim-1] to sum of squares of coordinates
    scale points to 'Qbb' if needed

  notes:
    to project one point, use
      qh_setdelaunay(qh, qh->hull_dim, 1, point)

    Do not use options 'Qbk', 'QBk', or 'QbB' since they scale
    the coordinates after the original projection.

*/
void qh_setdelaunay(qhT *qh, int dim, int count, pointT *points) {
  int i, k;
  coordT *coordp, coord;
  realT paraboloid;

  trace0((qh, qh->ferr, 11, "qh_setdelaunay: project %d points to paraboloid for Delaunay triangulation\n", count));
  coordp= points;
  for (i=0; i < count; i++) {
    coord= *coordp++;
    paraboloid= coord*coord;
    for (k=dim-2; k--; ) {
      coord= *coordp++;
      paraboloid += coord*coord;
    }
    *coordp++= paraboloid;
  }
  if (qh->last_low < REALmax/2)
    qh_scalelast(qh, points, count, dim, qh->last_low, qh->last_high, qh->last_newhigh);
} /* setdelaunay */


/*---------------------------------

  qh_sethalfspace(qh, dim, coords, nextp, normal, offset, feasible )
    set point to dual of halfspace relative to feasible point
    halfspace is normal coefficients and offset.

  returns:
    false and prints error if feasible point is outside of hull
    overwrites coordinates for point at dim coords
    nextp= next point (coords)
    does not call qh_errexit

  design:
    compute distance from feasible point to halfspace
    divide each normal coefficient by -dist
*/
boolT qh_sethalfspace(qhT *qh, int dim, coordT *coords, coordT **nextp,
         coordT *normal, coordT *offset, coordT *feasible) {
  coordT *normp= normal, *feasiblep= feasible, *coordp= coords;
  realT dist;
  realT r; /*bug fix*/
  int k;
  boolT zerodiv;

  dist= *offset;
  for (k=dim; k--; )
    dist += *(normp++) * *(feasiblep++);
  if (dist > 0)
    goto LABELerroroutside;
  normp= normal;
  if (dist < -qh->MINdenom) {
    for (k=dim; k--; )
      *(coordp++)= *(normp++) / -dist;
  }else {
    for (k=dim; k--; ) {
      *(coordp++)= qh_divzero(*(normp++), -dist, qh->MINdenom_1, &zerodiv);
      if (zerodiv)
        goto LABELerroroutside;
    }
  }
  *nextp= coordp;
#ifndef qh_NOtrace
  if (qh->IStracing >= 4) {
    qh_fprintf(qh, qh->ferr, 8021, "qh_sethalfspace: halfspace at offset %6.2g to point: ", *offset);
    for (k=dim, coordp=coords; k--; ) {
      r= *coordp++;
      qh_fprintf(qh, qh->ferr, 8022, " %6.2g", r);
    }
    qh_fprintf(qh, qh->ferr, 8023, "\n");
  }
#endif
  return True;
LABELerroroutside:
  feasiblep= feasible;
  normp= normal;
  qh_fprintf(qh, qh->ferr, 6023, "qhull input error: feasible point is not clearly inside halfspace\nfeasible point: ");
  for (k=dim; k--; )
    qh_fprintf(qh, qh->ferr, 8024, qh_REAL_1, r=*(feasiblep++));
  qh_fprintf(qh, qh->ferr, 8025, "\n     halfspace: ");
  for (k=dim; k--; )
    qh_fprintf(qh, qh->ferr, 8026, qh_REAL_1, r=*(normp++));
  qh_fprintf(qh, qh->ferr, 8027, "\n     at offset: ");
  qh_fprintf(qh, qh->ferr, 8028, qh_REAL_1, *offset);
  qh_fprintf(qh, qh->ferr, 8029, " and distance: ");
  qh_fprintf(qh, qh->ferr, 8030, qh_REAL_1, dist);
  qh_fprintf(qh, qh->ferr, 8031, "\n");
  return False;
} /* sethalfspace */

/*---------------------------------

  qh_sethalfspace_all(qh, dim, count, halfspaces, feasible )
    generate dual for halfspace intersection with feasible point
    array of count halfspaces
      each halfspace is normal coefficients followed by offset
      the origin is inside the halfspace if the offset is negative
    feasible is a point inside all halfspaces (http://www.qhull.org/html/qhalf.htm#notes)

  returns:
    malloc'd array of count X dim-1 points

  notes:
    call before qh_init_B or qh_initqhull_globals
    free memory when done
    unused/untested code: please email bradb@shore.net if this works ok for you
    if using option 'Fp', qh.feasible_point must be set (e.g., to 'feasible')
    qh->feasible_point is a malloc'd array that is freed by qh_freebuffers.

  design:
    see qh_sethalfspace
*/
coordT *qh_sethalfspace_all(qhT *qh, int dim, int count, coordT *halfspaces, pointT *feasible) {
  int i, newdim;
  pointT *newpoints;
  coordT *coordp, *normalp, *offsetp;

  trace0((qh, qh->ferr, 12, "qh_sethalfspace_all: compute dual for halfspace intersection\n"));
  newdim= dim - 1;
  if (!(newpoints= (coordT *)qh_malloc((size_t)(count * newdim) * sizeof(coordT)))){
    qh_fprintf(qh, qh->ferr, 6024, "qhull error: insufficient memory to compute dual of %d halfspaces\n",
          count);
    qh_errexit(qh, qh_ERRmem, NULL, NULL);
  }
  coordp= newpoints;
  normalp= halfspaces;
  for (i=0; i < count; i++) {
    offsetp= normalp + newdim;
    if (!qh_sethalfspace(qh, newdim, coordp, &coordp, normalp, offsetp, feasible)) {
      qh_free(newpoints);  /* feasible is not inside halfspace as reported by qh_sethalfspace */
      qh_fprintf(qh, qh->ferr, 8032, "The halfspace was at index %d\n", i);
      qh_errexit(qh, qh_ERRinput, NULL, NULL);
    }
    normalp= offsetp + 1;
  }
  return newpoints;
} /* sethalfspace_all */


/*---------------------------------

  qh_sharpnewfacets(qh)

  returns:
    true if could be an acute angle (facets in different quadrants)

  notes:
    for qh_findbest

  design:
    for all facets on qh.newfacet_list
      if two facets are in different quadrants
        set issharp
*/
boolT qh_sharpnewfacets(qhT *qh) {
  facetT *facet;
  boolT issharp= False;
  int *quadrant, k;

  quadrant= (int *)qh_memalloc(qh, qh->hull_dim * (int)sizeof(int));
  FORALLfacet_(qh->newfacet_list) {
    if (facet == qh->newfacet_list) {
      for (k=qh->hull_dim; k--; )
        quadrant[ k]= (facet->normal[ k] > 0);
    }else {
      for (k=qh->hull_dim; k--; ) {
        if (quadrant[ k] != (facet->normal[ k] > 0)) {
          issharp= True;
          break;
        }
      }
    }
    if (issharp)
      break;
  }
  qh_memfree(qh, quadrant, qh->hull_dim * (int)sizeof(int));
  trace3((qh, qh->ferr, 3001, "qh_sharpnewfacets: %d\n", issharp));
  return issharp;
} /* sharpnewfacets */

/*---------------------------------

  qh_vertex_bestdist(qh, vertices )
  qh_vertex_bestdist2(qh, vertices, vertexp, vertexp2 )
    return nearest distance between vertices
    optionally returns vertex and vertex2

  notes:
    called by qh_partitioncoplanar, qh_mergefacet, qh_check_maxout, qh_checkpoint
*/
coordT qh_vertex_bestdist(qhT *qh, setT *vertices) {
  vertexT *vertex, *vertex2;

  return qh_vertex_bestdist2(qh, vertices, &vertex, &vertex2);
} /* vertex_bestdist */

coordT qh_vertex_bestdist2(qhT *qh, setT *vertices, vertexT **vertexp/*= NULL*/, vertexT **vertexp2/*= NULL*/) {
  vertexT *vertex, *vertexA, *bestvertex= NULL, *bestvertex2= NULL;
  coordT dist, bestdist= REALmax;
  int k, vertex_i, vertex_n;

  FOREACHvertex_i_(qh, vertices) {
    for (k= vertex_i+1; k < vertex_n; k++) {
      vertexA= SETelemt_(vertices, k, vertexT);
      dist= qh_pointdist(vertex->point, vertexA->point, -qh->hull_dim);
      if (dist < bestdist) {
        bestdist= dist;
        bestvertex= vertex;
        bestvertex2= vertexA;
      }
    }
  }
  *vertexp= bestvertex;
  *vertexp2= bestvertex2;
  return sqrt(bestdist);
} /* vertex_bestdist */

/*---------------------------------

  qh_voronoi_center(qh, dim, points )
    return Voronoi center for a set of points
    dim is the orginal dimension of the points
    gh.gm_matrix/qh.gm_row are scratch buffers

  returns:
    center as a temporary point (qh_memalloc)
    if non-simplicial,
      returns center for max simplex of points

  notes:
    only called by qh_facetcenter
    from Bowyer & Woodwark, A Programmer's Geometry, 1983, p. 65

  design:
    if non-simplicial
      determine max simplex for points
    translate point0 of simplex to origin
    compute sum of squares of diagonal
    compute determinate
    compute Voronoi center (see Bowyer & Woodwark)
*/
pointT *qh_voronoi_center(qhT *qh, int dim, setT *points) {
  pointT *point, **pointp, *point0;
  pointT *center= (pointT *)qh_memalloc(qh, qh->center_size);
  setT *simplex;
  int i, j, k, size= qh_setsize(qh, points);
  coordT *gmcoord;
  realT *diffp, sum2, *sum2row, *sum2p, det, factor;
  boolT nearzero, infinite;

  if (size == dim+1)
    simplex= points;
  else if (size < dim+1) {
    qh_memfree(qh, center, qh->center_size);
    qh_fprintf(qh, qh->ferr, 6025, "qhull internal error (qh_voronoi_center):  need at least %d points to construct a Voronoi center\n",
             dim+1);
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
    simplex= points;  /* never executed -- avoids warning */
  }else {
    simplex= qh_settemp(qh, dim+1);
    qh_maxsimplex(qh, dim, points, NULL, 0, &simplex);
  }
  point0= SETfirstt_(simplex, pointT);
  gmcoord= qh->gm_matrix;
  for (k=0; k < dim; k++) {
    qh->gm_row[k]= gmcoord;
    FOREACHpoint_(simplex) {
      if (point != point0)
        *(gmcoord++)= point[k] - point0[k];
    }
  }
  sum2row= gmcoord;
  for (i=0; i < dim; i++) {
    sum2= 0.0;
    for (k=0; k < dim; k++) {
      diffp= qh->gm_row[k] + i;
      sum2 += *diffp * *diffp;
    }
    *(gmcoord++)= sum2;
  }
  det= qh_determinant(qh, qh->gm_row, dim, &nearzero);
  factor= qh_divzero(0.5, det, qh->MINdenom, &infinite);
  if (infinite) {
    for (k=dim; k--; )
      center[k]= qh_INFINITE;
    if (qh->IStracing)
      qh_printpoints(qh, qh->ferr, "qh_voronoi_center: at infinity for ", simplex);
  }else {
    for (i=0; i < dim; i++) {
      gmcoord= qh->gm_matrix;
      sum2p= sum2row;
      for (k=0; k < dim; k++) {
        qh->gm_row[k]= gmcoord;
        if (k == i) {
          for (j=dim; j--; )
            *(gmcoord++)= *sum2p++;
        }else {
          FOREACHpoint_(simplex) {
            if (point != point0)
              *(gmcoord++)= point[k] - point0[k];
          }
        }
      }
      center[i]= qh_determinant(qh, qh->gm_row, dim, &nearzero)*factor + point0[i];
    }
#ifndef qh_NOtrace
    if (qh->IStracing >= 3) {
      qh_fprintf(qh, qh->ferr, 3061, "qh_voronoi_center: det %2.2g factor %2.2g ", det, factor);
      qh_printmatrix(qh, qh->ferr, "center:", ¢er, 1, dim);
      if (qh->IStracing >= 5) {
        qh_printpoints(qh, qh->ferr, "points", simplex);
        FOREACHpoint_(simplex)
          qh_fprintf(qh, qh->ferr, 8034, "p%d dist %.2g, ", qh_pointid(qh, point),
                   qh_pointdist(point, center, dim));
        qh_fprintf(qh, qh->ferr, 8035, "\n");
      }
    }
#endif
  }
  if (simplex != points)
    qh_settempfree(qh, &simplex);
  return center;
} /* voronoi_center */

qhull-2020.2/src/libqhull_r/geom_r.c0000644060175106010010000013251113661631132015533 0ustar  bbarber/*
  ---------------------------------

   geom_r.c
   geometric routines of qhull

   see qh-geom_r.htm and geom_r.h

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull_r/geom_r.c#5 $$Change: 2953 $
   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $

   infrequent code goes into geom2_r.c
*/

#include "qhull_ra.h"

/*---------------------------------

  qh_distplane(qh, point, facet, dist )
    return distance from point to facet

  returns:
    dist
    if qh.RANDOMdist, joggles result

  notes:
    dist > 0 if point is above facet (i.e., outside)
    does not error (for qh_sortfacets, qh_outerinner)
    for nearly coplanar points, the returned values may be duplicates
      for example pairs of nearly incident points, rbox 175 C1,2e-13 t1538759579 | qhull d T4
      622 qh_distplane: e-014  # count of two or more duplicate values for unique calls
      258 qh_distplane: e-015
      38 qh_distplane: e-016
      40 qh_distplane: e-017
      6 qh_distplane: e-018
      5 qh_distplane: -e-018
      33 qh_distplane: -e-017
         3153 qh_distplane: -2.775557561562891e-017  # duplicated value for 3153 unique calls
      42 qh_distplane: -e-016
      307 qh_distplane: -e-015
      1271 qh_distplane: -e-014
      13 qh_distplane: -e-013

  see:
    qh_distnorm in geom2_r.c
    qh_distplane [geom_r.c], QhullFacet::distance, and QhullHyperplane::distance are copies
*/
void qh_distplane(qhT *qh, pointT *point, facetT *facet, realT *dist) {
  coordT *normal= facet->normal, *coordp, randr;
  int k;

  switch (qh->hull_dim){
  case 2:
    *dist= facet->offset + point[0] * normal[0] + point[1] * normal[1];
    break;
  case 3:
    *dist= facet->offset + point[0] * normal[0] + point[1] * normal[1] + point[2] * normal[2];
    break;
  case 4:
    *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3];
    break;
  case 5:
    *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4];
    break;
  case 6:
    *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5];
    break;
  case 7:
    *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6];
    break;
  case 8:
    *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6]+point[7]*normal[7];
    break;
  default:
    *dist= facet->offset;
    coordp= point;
    for (k=qh->hull_dim; k--; )
      *dist += *coordp++ * *normal++;
    break;
  }
  zzinc_(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;
  }
#ifndef qh_NOtrace
  if (qh->IStracing >= 4) {
    qh_fprintf(qh, qh->ferr, 8001, "qh_distplane: ");
    qh_fprintf(qh, qh->ferr, 8002, qh_REAL_1, *dist);
    qh_fprintf(qh, qh->ferr, 8003, "from p%d to f%d\n", qh_pointid(qh, point), facet->id);
  }
#endif
  return;
} /* distplane */


/*---------------------------------

  qh_findbest(qh, point, startfacet, bestoutside, qh_ISnewfacets, qh_NOupper, dist, isoutside, numpart )
    find facet that is furthest below a point
    for upperDelaunay facets
      returns facet only if !qh_NOupper and clearly above

  input:
    starts search at 'startfacet' (can not be flipped)
    if !bestoutside(qh_ALL), stops at qh.MINoutside

  returns:
    best facet (reports error if NULL)
    early out if isoutside defined and bestdist > qh.MINoutside
    dist is distance to facet
    isoutside is true if point is outside of facet
    numpart counts the number of distance tests

  see also:
    qh_findbestnew()

  notes:
    If merging (testhorizon), searches horizon facets of coplanar best facets because
    after qh_distplane, this and qh_partitionpoint are the most expensive in 3-d
      avoid calls to distplane, function calls, and real number operations.
    caller traces result
    Optimized for outside points.   Tried recording a search set for qh_findhorizon.
    Made code more complicated.

  when called by qh_partitionvisible():
    indicated by qh_ISnewfacets
    qh.newfacet_list is list of simplicial, new facets
    qh_findbestnew set if qh_sharpnewfacets returns True (to use qh_findbestnew)
    qh.bestfacet_notsharp set if qh_sharpnewfacets returns False

  when called by qh_findfacet(), qh_partitionpoint(), qh_partitioncoplanar(),
                 qh_check_bestdist(), qh_addpoint()
    indicated by !qh_ISnewfacets
    returns best facet in neighborhood of given facet
      this is best facet overall if dist >= -qh.MAXcoplanar
        or hull has at least a "spherical" curvature

  design:
    initialize and test for early exit
    repeat while there are better facets
      for each neighbor of facet
        exit if outside facet found
        test for better facet
    if point is inside and partitioning
      test for new facets with a "sharp" intersection
      if so, future calls go to qh_findbestnew()
    test horizon facets
*/
facetT *qh_findbest(qhT *qh, pointT *point, facetT *startfacet,
                     boolT bestoutside, boolT isnewfacets, boolT noupper,
                     realT *dist, boolT *isoutside, int *numpart) {
  realT bestdist= -REALmax/2 /* avoid underflow */;
  facetT *facet, *neighbor, **neighborp;
  facetT *bestfacet= NULL, *lastfacet= NULL;
  int oldtrace= qh->IStracing;
  unsigned int visitid= ++qh->visit_id;
  int numpartnew=0;
  boolT testhorizon= True; /* needed if precise, e.g., rbox c D6 | qhull Q0 Tv */

  zinc_(Zfindbest);
#ifndef qh_NOtrace
  if (qh->IStracing >= 4 || (qh->TRACElevel && qh->TRACEpoint >= 0 && qh->TRACEpoint == qh_pointid(qh, point))) {
    if (qh->TRACElevel > qh->IStracing)
      qh->IStracing= qh->TRACElevel;
    qh_fprintf(qh, qh->ferr, 8004, "qh_findbest: point p%d starting at f%d isnewfacets? %d, unless %d exit if > %2.2g,",
             qh_pointid(qh, point), startfacet->id, isnewfacets, bestoutside, qh->MINoutside);
    qh_fprintf(qh, qh->ferr, 8005, " testhorizon? %d, noupper? %d,", testhorizon, noupper);
    qh_fprintf(qh, qh->ferr, 8006, " Last qh_addpoint p%d,", qh->furthest_id);
    qh_fprintf(qh, qh->ferr, 8007, " Last merge #%d, max_outside %2.2g\n", zzval_(Ztotmerge), qh->max_outside);
  }
#endif
  if (isoutside)
    *isoutside= True;
  if (!startfacet->flipped) {  /* test startfacet before testing its neighbors */
    *numpart= 1;
    qh_distplane(qh, point, startfacet, dist);  /* this code is duplicated below */
    if (!bestoutside && *dist >= qh->MINoutside
    && (!startfacet->upperdelaunay || !noupper)) {
      bestfacet= startfacet;
      goto LABELreturn_best;
    }
    bestdist= *dist;
    if (!startfacet->upperdelaunay) {
      bestfacet= startfacet;
    }
  }else
    *numpart= 0;
  startfacet->visitid= visitid;
  facet= startfacet;
  while (facet) {
    trace4((qh, qh->ferr, 4001, "qh_findbest: neighbors of f%d, bestdist %2.2g f%d\n",
                facet->id, bestdist, getid_(bestfacet)));
    lastfacet= facet;
    FOREACHneighbor_(facet) {
      if (!neighbor->newfacet && isnewfacets)
        continue;
      if (neighbor->visitid == visitid)
        continue;
      neighbor->visitid= visitid;
      if (!neighbor->flipped) {  /* code duplicated above */
        (*numpart)++;
        qh_distplane(qh, point, neighbor, dist);
        if (*dist > bestdist) {
          if (!bestoutside && *dist >= qh->MINoutside
          && (!neighbor->upperdelaunay || !noupper)) {
            bestfacet= neighbor;
            goto LABELreturn_best;
          }
          if (!neighbor->upperdelaunay) {
            bestfacet= neighbor;
            bestdist= *dist;
            break; /* switch to neighbor */
          }else if (!bestfacet) {
            bestdist= *dist;
            break; /* switch to neighbor */
          }
        } /* end of *dist>bestdist */
      } /* end of !flipped */
    } /* end of FOREACHneighbor */
    facet= neighbor;  /* non-NULL only if *dist>bestdist */
  } /* end of while facet (directed search) */
  if (isnewfacets) {
    if (!bestfacet) { /* startfacet is upperdelaunay (or flipped) w/o !flipped newfacet neighbors */
      bestdist= -REALmax/2;
      bestfacet= qh_findbestnew(qh, point, qh->newfacet_list, &bestdist, bestoutside, isoutside, &numpartnew);
      testhorizon= False; /* qh_findbestnew calls qh_findbesthorizon */
    }else if (!qh->findbest_notsharp && bestdist < -qh->DISTround) {
      if (qh_sharpnewfacets(qh)) {
        /* seldom used, qh_findbestnew will retest all facets */
        zinc_(Zfindnewsharp);
        bestfacet= qh_findbestnew(qh, point, bestfacet, &bestdist, bestoutside, isoutside, &numpartnew);
        testhorizon= False; /* qh_findbestnew calls qh_findbesthorizon */
        qh->findbestnew= True;
      }else
        qh->findbest_notsharp= True;
    }
  }
  if (!bestfacet)
    bestfacet= qh_findbestlower(qh, lastfacet, point, &bestdist, numpart); /* lastfacet is non-NULL because startfacet is non-NULL */
  if (testhorizon) /* qh_findbestnew not called */
    bestfacet= qh_findbesthorizon(qh, !qh_IScheckmax, point, bestfacet, noupper, &bestdist, &numpartnew);
  *dist= bestdist;
  if (isoutside && bestdist < qh->MINoutside)
    *isoutside= False;
LABELreturn_best:
  zadd_(Zfindbesttot, *numpart);
  zmax_(Zfindbestmax, *numpart);
  (*numpart) += numpartnew;
  qh->IStracing= oldtrace;
  return bestfacet;
}  /* findbest */


/*---------------------------------

  qh_findbesthorizon(qh, qh_IScheckmax, point, startfacet, qh_NOupper, &bestdist, &numpart )
    search coplanar and better horizon facets from startfacet/bestdist
    ischeckmax turns off statistics and minsearch update
    all arguments must be initialized, including *bestdist and *numpart
    qh.coplanarfacetset used to maintain current search set, reset whenever best facet is substantially better
  returns(ischeckmax):
    best facet
    updates f.maxoutside for neighbors of searched facets (if qh_MAXoutside)
  returns(!ischeckmax):
    best facet that is not upperdelaunay or newfacet (qh.first_newfacet)
    allows upperdelaunay that is clearly outside
  returns:
    bestdist is distance to bestfacet
    numpart -- updates number of distance tests

  notes:
    called by qh_findbest if point is not outside a facet (directed search)
    called by qh_findbestnew if point is not outside a new facet
    called by qh_check_maxout for each point in hull
    called by qh_check_bestdist for each point in hull (rarely used)

    no early out -- use qh_findbest() or qh_findbestnew()
    Searches coplanar or better horizon facets

  when called by qh_check_maxout() (qh_IScheckmax)
    startfacet must be closest to the point
      Otherwise, if point is beyond and below startfacet, startfacet may be a local minimum
      even though other facets are below the point.
    updates facet->maxoutside for good, visited facets
    may return NULL

    searchdist is qh.max_outside + 2 * DISTround
      + max( MINvisible('Vn'), MAXcoplanar('Un'));
    This setting is a guess.  It must be at least max_outside + 2*DISTround
    because a facet may have a geometric neighbor across a vertex

  design:
    for each horizon facet of coplanar best facets
      continue if clearly inside
      unless upperdelaunay or clearly outside
         update best facet
*/
facetT *qh_findbesthorizon(qhT *qh, boolT ischeckmax, pointT* point, facetT *startfacet, boolT noupper, realT *bestdist, int *numpart) {
  facetT *bestfacet= startfacet;
  realT dist;
  facetT *neighbor, **neighborp, *facet;
  facetT *nextfacet= NULL; /* optimize last facet of coplanarfacetset */
  int numpartinit= *numpart, coplanarfacetset_size, numcoplanar= 0, numfacet= 0;
  unsigned int visitid= ++qh->visit_id;
  boolT newbest= False; /* for tracing */
  realT minsearch, searchdist;  /* skip facets that are too far from point */
  boolT is_5x_minsearch;

  if (!ischeckmax) {
    zinc_(Zfindhorizon);
  }else {
#if qh_MAXoutside
    if ((!qh->ONLYgood || startfacet->good) && *bestdist > startfacet->maxoutside)
      startfacet->maxoutside= *bestdist;
#endif
  }
  searchdist= qh_SEARCHdist; /* an expression, a multiple of qh.max_outside and precision constants */
  minsearch= *bestdist - searchdist;
  if (ischeckmax) {
    /* Always check coplanar facets.  Needed for RBOX 1000 s Z1 G1e-13 t996564279 | QHULL Tv */
    minimize_(minsearch, -searchdist);
  }
  coplanarfacetset_size= 0;
  startfacet->visitid= visitid;
  facet= startfacet;
  while (True) {
    numfacet++;
    is_5x_minsearch= (ischeckmax && facet->nummerge > 10 && qh_setsize(qh, facet->neighbors) > 100);  /* QH11033 FIX: qh_findbesthorizon: many tests for facets with many merges and neighbors.  Can hide coplanar facets, e.g., 'rbox 1000 s Z1 G1e-13' with 4400+ neighbors */
    trace4((qh, qh->ferr, 4002, "qh_findbesthorizon: test neighbors of f%d bestdist %2.2g f%d ischeckmax? %d noupper? %d minsearch %2.2g is_5x? %d searchdist %2.2g\n",
                facet->id, *bestdist, getid_(bestfacet), ischeckmax, noupper,
                minsearch, is_5x_minsearch, searchdist));
    FOREACHneighbor_(facet) {
      if (neighbor->visitid == visitid)
        continue;
      neighbor->visitid= visitid;
      if (!neighbor->flipped) {  /* neighbors of flipped facets always searched via nextfacet */
        qh_distplane(qh, point, neighbor, &dist); /* duplicate qh_distpane for new facets, they may be coplanar */
        (*numpart)++;
        if (dist > *bestdist) {
          if (!neighbor->upperdelaunay || ischeckmax || (!noupper && dist >= qh->MINoutside)) {
            if (!ischeckmax) {
              minsearch= dist - searchdist;
              if (dist > *bestdist + searchdist) {
                zinc_(Zfindjump);  /* everything in qh.coplanarfacetset at least searchdist below */
                coplanarfacetset_size= 0;
              }
            }
            bestfacet= neighbor;
            *bestdist= dist;
            newbest= True;
          }
        }else if (is_5x_minsearch) {
          if (dist < 5 * minsearch)
            continue; /* skip this neighbor, do not set nextfacet.  dist is negative */
        }else if (dist < minsearch)
          continue;  /* skip this neighbor, do not set nextfacet.  If ischeckmax, dist can't be positive */
#if qh_MAXoutside
        if (ischeckmax && dist > neighbor->maxoutside)
          neighbor->maxoutside= dist;
#endif
      } /* end of !flipped, need to search neighbor */
      if (nextfacet) {
        numcoplanar++;
        if (!coplanarfacetset_size++) {
          SETfirst_(qh->coplanarfacetset)= nextfacet;
          SETtruncate_(qh->coplanarfacetset, 1);
        }else
          qh_setappend(qh, &qh->coplanarfacetset, nextfacet); /* Was needed for RBOX 1000 s W1e-13 P0 t996547055 | QHULL d Qbb Qc Tv
                                                 and RBOX 1000 s Z1 G1e-13 t996564279 | qhull Tv  */
      }
      nextfacet= neighbor;
    } /* end of EACHneighbor */
    facet= nextfacet;
    if (facet)
      nextfacet= NULL;
    else if (!coplanarfacetset_size)
      break;
    else if (!--coplanarfacetset_size) {
      facet= SETfirstt_(qh->coplanarfacetset, facetT);
      SETtruncate_(qh->coplanarfacetset, 0);
    }else
      facet= (facetT *)qh_setdellast(qh->coplanarfacetset);
  } /* while True, i.e., "for each facet in qh.coplanarfacetset" */
  if (!ischeckmax) {
    zadd_(Zfindhorizontot, *numpart - numpartinit);
    zmax_(Zfindhorizonmax, *numpart - numpartinit);
    if (newbest)
      zinc_(Znewbesthorizon);
  }
  trace4((qh, qh->ferr, 4003, "qh_findbesthorizon: p%d, newbest? %d, bestfacet f%d, bestdist %2.2g, numfacet %d, coplanarfacets %d, numdist %d\n",
    qh_pointid(qh, point), newbest, getid_(bestfacet), *bestdist, numfacet, numcoplanar, *numpart - numpartinit));
  return bestfacet;
}  /* findbesthorizon */

/*---------------------------------

  qh_findbestnew(qh, point, startfacet, dist, isoutside, numpart )
    find best newfacet for point
    searches all of qh.newfacet_list starting at startfacet
    searches horizon facets of coplanar best newfacets
    searches all facets if startfacet == qh.facet_list
  returns:
    best new or horizon facet that is not upperdelaunay
    early out if isoutside and not 'Qf'
    dist is distance to facet
    isoutside is true if point is outside of facet
    numpart is number of distance tests

  notes:
    Always used for merged new facets (see qh_USEfindbestnew)
    Avoids upperdelaunay facet unless (isoutside and outside)

    Uses qh.visit_id, qh.coplanarfacetset.
    If share visit_id with qh_findbest, coplanarfacetset is incorrect.

    If merging (testhorizon), searches horizon facets of coplanar best facets because
    a point maybe coplanar to the bestfacet, below its horizon facet,
    and above a horizon facet of a coplanar newfacet.  For example,
      rbox 1000 s Z1 G1e-13 | qhull
      rbox 1000 s W1e-13 P0 t992110337 | QHULL d Qbb Qc

    qh_findbestnew() used if
       qh_sharpnewfacets -- newfacets contains a sharp angle
       if many merges, qh_premerge found a merge, or 'Qf' (qh.findbestnew)

  see also:
    qh_partitionall() and qh_findbest()

  design:
    for each new facet starting from startfacet
      test distance from point to facet
      return facet if clearly outside
      unless upperdelaunay and a lowerdelaunay exists
         update best facet
    test horizon facets
*/
facetT *qh_findbestnew(qhT *qh, pointT *point, facetT *startfacet,
           realT *dist, boolT bestoutside, boolT *isoutside, int *numpart) {
  realT bestdist= -REALmax/2;
  facetT *bestfacet= NULL, *facet;
  int oldtrace= qh->IStracing, i;
  unsigned int visitid= ++qh->visit_id;
  realT distoutside= 0.0;
  boolT isdistoutside; /* True if distoutside is defined */
  boolT testhorizon= True; /* needed if precise, e.g., rbox c D6 | qhull Q0 Tv */

  if (!startfacet || !startfacet->next) {
    if (qh->MERGING) {
      qh_fprintf(qh, qh->ferr, 6001, "qhull topology error (qh_findbestnew): merging has formed and deleted a cone of new facets.  Can not continue.\n");
      qh_errexit(qh, qh_ERRtopology, NULL, NULL);
    }else {
      qh_fprintf(qh, qh->ferr, 6002, "qhull internal error (qh_findbestnew): no new facets for point p%d\n",
              qh->furthest_id);
      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
    }
  }
  zinc_(Zfindnew);
  if (qh->BESToutside || bestoutside)
    isdistoutside= False;
  else {
    isdistoutside= True;
    distoutside= qh_DISToutside; /* multiple of qh.MINoutside & qh.max_outside, see user_r.h */
  }
  if (isoutside)
    *isoutside= True;
  *numpart= 0;
#ifndef qh_NOtrace
  if (qh->IStracing >= 4 || (qh->TRACElevel && qh->TRACEpoint >= 0 && qh->TRACEpoint == qh_pointid(qh, point))) {
    if (qh->TRACElevel > qh->IStracing)
      qh->IStracing= qh->TRACElevel;
    qh_fprintf(qh, qh->ferr, 8008, "qh_findbestnew: point p%d facet f%d. Stop? %d if dist > %2.2g,",
             qh_pointid(qh, point), startfacet->id, isdistoutside, distoutside);
    qh_fprintf(qh, qh->ferr, 8009, " Last qh_addpoint p%d, qh.visit_id %d, vertex_visit %d,",  qh->furthest_id, visitid, qh->vertex_visit);
    qh_fprintf(qh, qh->ferr, 8010, " Last merge #%d\n", zzval_(Ztotmerge));
  }
#endif
  /* visit all new facets starting with startfacet, maybe qh->facet_list */
  for (i=0, facet=startfacet; i < 2; i++, facet= qh->newfacet_list) {
    FORALLfacet_(facet) {
      if (facet == startfacet && i)
        break;
      facet->visitid= visitid;
      if (!facet->flipped) {
        qh_distplane(qh, point, facet, dist);
        (*numpart)++;
        if (*dist > bestdist) {
          if (!facet->upperdelaunay || *dist >= qh->MINoutside) {
            bestfacet= facet;
            if (isdistoutside && *dist >= distoutside)
              goto LABELreturn_bestnew;
            bestdist= *dist;
          }
        }
      } /* end of !flipped */
    } /* FORALLfacet from startfacet or qh->newfacet_list */
  }
  if (testhorizon || !bestfacet) /* testhorizon is always True.  Keep the same code as qh_findbest */
    bestfacet= qh_findbesthorizon(qh, !qh_IScheckmax, point, bestfacet ? bestfacet : startfacet,
                                        !qh_NOupper, &bestdist, numpart);
  *dist= bestdist;
  if (isoutside && *dist < qh->MINoutside)
    *isoutside= False;
LABELreturn_bestnew:
  zadd_(Zfindnewtot, *numpart);
  zmax_(Zfindnewmax, *numpart);
  trace4((qh, qh->ferr, 4004, "qh_findbestnew: bestfacet f%d bestdist %2.2g for p%d f%d bestoutside? %d \n",
    getid_(bestfacet), *dist, qh_pointid(qh, point), startfacet->id, bestoutside));
  qh->IStracing= oldtrace;
  return bestfacet;
}  /* findbestnew */

/* ============ hyperplane functions -- keep code together [?] ============ */

/*---------------------------------

  qh_backnormal(qh, rows, numrow, numcol, sign, normal, nearzero )
    given an upper-triangular rows array and a sign,
    solve for normal equation x using back substitution over rows U

  returns:
     normal= x

     if will not be able to divzero() when normalized(qh.MINdenom_2 and qh.MINdenom_1_2),
       if fails on last row
         this means that the hyperplane intersects [0,..,1]
         sets last coordinate of normal to sign
       otherwise
         sets tail of normal to [...,sign,0,...], i.e., solves for b= [0...0]
         sets nearzero

  notes:
     assumes numrow == numcol-1

     see Golub & van Loan, 1983, Eq. 4.4-9 for "Gaussian elimination with complete pivoting"

     solves Ux=b where Ax=b and PA=LU
     b= [0,...,0,sign or 0]  (sign is either -1 or +1)
     last row of A= [0,...,0,1]

     1) Ly=Pb == y=b since P only permutes the 0's of   b

  design:
    for each row from end
      perform back substitution
      if near zero
        use qh_divzero for division
        if zero divide and not last row
          set tail of normal to 0
*/
void qh_backnormal(qhT *qh, realT **rows, int numrow, int numcol, boolT sign,
        coordT *normal, boolT *nearzero) {
  int i, j;
  coordT *normalp, *normal_tail, *ai, *ak;
  realT diagonal;
  boolT waszero;
  int zerocol= -1;

  normalp= normal + numcol - 1;
  *normalp--= (sign ? -1.0 : 1.0);
  for (i=numrow; i--; ) {
    *normalp= 0.0;
    ai= rows[i] + i + 1;
    ak= normalp+1;
    for (j=i+1; j < numcol; j++)
      *normalp -= *ai++ * *ak++;
    diagonal= (rows[i])[i];
    if (fabs_(diagonal) > qh->MINdenom_2)
      *(normalp--) /= diagonal;
    else {
      waszero= False;
      *normalp= qh_divzero(*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) {
    *nearzero= True;
    trace4((qh, qh->ferr, 4005, "qh_backnormal: zero diagonal at column %d.\n", i));
    zzinc_(Zback0);
    qh_joggle_restart(qh, "zero diagonal on back substitution");
  }
} /* backnormal */

/*---------------------------------

  qh_gausselim(qh, rows, numrow, numcol, sign )
    Gaussian elimination with partial pivoting

  returns:
    rows is upper triangular (includes row exchanges)
    flips sign for each row exchange
    sets nearzero if pivot[k] < qh.NEARzero[k], else clears it

  notes:
    if nearzero, the determinant's sign may be incorrect.
    assumes numrow <= numcol

  design:
    for each row
      determine pivot and exchange rows if necessary
      test for near zero
      perform gaussian elimination step
*/
void qh_gausselim(qhT *qh, realT **rows, int numrow, int numcol, boolT *sign, boolT *nearzero) {
  realT *ai, *ak, *rowp, *pivotrow;
  realT n, pivot, pivot_abs= 0.0, temp;
  int i, j, k, pivoti, flip=0;

  *nearzero= False;
  for (k=0; k < numrow; k++) {
    pivot_abs= fabs_((rows[k])[k]);
    pivoti= k;
    for (i=k+1; i < numrow; i++) {
      if ((temp= fabs_((rows[i])[k])) > pivot_abs) {
        pivot_abs= temp;
        pivoti= i;
      }
    }
    if (pivoti != k) {
      rowp= rows[pivoti];
      rows[pivoti]= rows[k];
      rows[k]= rowp;
      *sign ^= 1;
      flip ^= 1;
    }
    if (pivot_abs <= qh->NEARzero[k]) {
      *nearzero= True;
      if (pivot_abs == 0.0) {   /* remainder of column == 0 */
#ifndef qh_NOtrace
        if (qh->IStracing >= 4) {
          qh_fprintf(qh, qh->ferr, 8011, "qh_gausselim: 0 pivot at column %d. (%2.2g < %2.2g)\n", k, pivot_abs, qh->DISTround);
          qh_printmatrix(qh, qh->ferr, "Matrix:", rows, numrow, numcol);
        }
#endif
        zzinc_(Zgauss0);
        qh_joggle_restart(qh, "zero pivot for Gaussian elimination");
        goto LABELnextcol;
      }
    }
    pivotrow= rows[k] + k;
    pivot= *pivotrow++;  /* signed value of pivot, and remainder of row */
    for (i=k+1; i < numrow; i++) {
      ai= rows[i] + k;
      ak= pivotrow;
      n= (*ai++)/pivot;   /* divzero() not needed since |pivot| >= |*ai| */
      for (j= numcol - (k+1); j--; )
        *ai++ -= n * *ak++;
    }
  LABELnextcol:
    ;
  }
  wmin_(Wmindenom, pivot_abs);  /* last pivot element */
  if (qh->IStracing >= 5)
    qh_printmatrix(qh, qh->ferr, "qh_gausselem: result", rows, numrow, numcol);
} /* gausselim */


/*---------------------------------

  qh_getangle(qh, vect1, vect2 )
    returns the dot product of two vectors
    if qh.RANDOMdist, joggles result

  notes:
    the angle may be > 1.0 or < -1.0 because of roundoff errors

*/
realT qh_getangle(qhT *qh, pointT *vect1, pointT *vect2) {
  realT angle= 0, randr;
  int k;

  for (k=qh->hull_dim; k--; )
    angle += *vect1++ * *vect2++;
  if (qh->RANDOMdist) {
    randr= qh_RANDOMint;
    angle += (2.0 * randr / qh_RANDOMmax - 1.0) *
      qh->RANDOMfactor;
  }
  trace4((qh, qh->ferr, 4006, "qh_getangle: %4.4g\n", angle));
  return(angle);
} /* getangle */


/*---------------------------------

  qh_getcenter(qh, vertices )
    returns arithmetic center of a set of vertices as a new point

  notes:
    allocates point array for center
*/
pointT *qh_getcenter(qhT *qh, setT *vertices) {
  int k;
  pointT *center, *coord;
  vertexT *vertex, **vertexp;
  int count= qh_setsize(qh, vertices);

  if (count < 2) {
    qh_fprintf(qh, qh->ferr, 6003, "qhull internal error (qh_getcenter): not defined for %d points\n", count);
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  center= (pointT *)qh_memalloc(qh, qh->normal_size);
  for (k=0; k < qh->hull_dim; k++) {
    coord= center+k;
    *coord= 0.0;
    FOREACHvertex_(vertices)
      *coord += vertex->point[k];
    *coord /= count;  /* count>=2 by QH6003 */
  }
  return(center);
} /* getcenter */


/*---------------------------------

  qh_getcentrum(qh, facet )
    returns the centrum for a facet as a new point

  notes:
    allocates the centrum
*/
pointT *qh_getcentrum(qhT *qh, facetT *facet) {
  realT dist;
  pointT *centrum, *point;

  point= qh_getcenter(qh, facet->vertices);
  zzinc_(Zcentrumtests);
  qh_distplane(qh, point, facet, &dist);
  centrum= qh_projectpoint(qh, point, facet, dist);
  qh_memfree(qh, point, qh->normal_size);
  trace4((qh, qh->ferr, 4007, "qh_getcentrum: for f%d, %d vertices dist= %2.2g\n",
          facet->id, qh_setsize(qh, facet->vertices), dist));
  return centrum;
} /* getcentrum */


/*---------------------------------

  qh_getdistance(qh, facet, neighbor, mindist, maxdist )
    returns the min and max distance to neighbor of non-neighbor vertices in facet

  returns:
    the max absolute value

  design:
    for each vertex of facet that is not in neighbor
      test the distance from vertex to neighbor
*/
coordT qh_getdistance(qhT *qh, facetT *facet, facetT *neighbor, coordT *mindist, coordT *maxdist) {
  vertexT *vertex, **vertexp;
  coordT dist, maxd, mind;

  FOREACHvertex_(facet->vertices)
    vertex->seen= False;
  FOREACHvertex_(neighbor->vertices)
    vertex->seen= True;
  mind= 0.0;
  maxd= 0.0;
  FOREACHvertex_(facet->vertices) {
    if (!vertex->seen) {
      zzinc_(Zbestdist);
      qh_distplane(qh, vertex->point, neighbor, &dist);
      if (dist < mind)
        mind= dist;
      else if (dist > maxd)
        maxd= dist;
    }
  }
  *mindist= mind;
  *maxdist= maxd;
  mind= -mind;
  if (maxd > mind)
    return maxd;
  else
    return mind;
} /* getdistance */


/*---------------------------------

  qh_normalize(qh, normal, dim, toporient )
    normalize a vector and report if too small
    does not use min norm

  see:
    qh_normalize2
*/
void qh_normalize(qhT *qh, coordT *normal, int dim, boolT toporient) {
  qh_normalize2(qh, normal, dim, toporient, NULL, NULL);
} /* normalize */

/*---------------------------------

  qh_normalize2(qh, normal, dim, toporient, minnorm, ismin )
    normalize a vector and report if too small
    qh.MINdenom/MINdenom1 are the upper limits for divide overflow

  returns:
    normalized vector
    flips sign if !toporient
    if minnorm non-NULL,
      sets ismin if normal < minnorm

  notes:
    if zero norm
       sets all elements to sqrt(1.0/dim)
    if divide by zero (divzero())
       sets largest element to   +/-1
       bumps Znearlysingular

  design:
    computes norm
    test for minnorm
    if not near zero
      normalizes normal
    else if zero norm
      sets normal to standard value
    else
      uses qh_divzero to normalize
      if nearzero
        sets norm to direction of maximum value
*/
void qh_normalize2(qhT *qh, coordT *normal, int dim, boolT toporient,
            realT *minnorm, boolT *ismin) {
  int k;
  realT *colp, *maxp, norm= 0, temp, *norm1, *norm2, *norm3;
  boolT zerodiv;

  norm1= normal+1;
  norm2= normal+2;
  norm3= normal+3;
  if (dim == 2)
    norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1));
  else if (dim == 3)
    norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2));
  else if (dim == 4) {
    norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2)
               + (*norm3)*(*norm3));
  }else if (dim > 4) {
    norm= (*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2)
               + (*norm3)*(*norm3);
    for (k=dim-4, colp=normal+4; k--; colp++)
      norm += (*colp) * (*colp);
    norm= sqrt(norm);
  }
  if (minnorm) {
    if (norm < *minnorm)
      *ismin= True;
    else
      *ismin= False;
  }
  wmin_(Wmindenom, norm);
  if (norm > qh->MINdenom) {
    if (!toporient)
      norm= -norm;
    *normal /= norm;
    *norm1 /= norm;
    if (dim == 2)
      ; /* all done */
    else if (dim == 3)
      *norm2 /= norm;
    else if (dim == 4) {
      *norm2 /= norm;
      *norm3 /= norm;
    }else if (dim >4) {
      *norm2 /= norm;
      *norm3 /= norm;
      for (k=dim-4, colp=normal+4; k--; )
        *colp++ /= norm;
    }
  }else if (norm == 0.0) {
    temp= sqrt(1.0/dim);
    for (k=dim, colp=normal; k--; )
      *colp++= temp;
  }else {
    if (!toporient)
      norm= -norm;
    for (k=dim, colp=normal; k--; colp++) { /* k used below */
      temp= qh_divzero(*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);
        /* qh_joggle_restart ignored for Znearlysingular, normal part of qh_sethyperplane_gauss */
        trace0((qh, qh->ferr, 1, "qh_normalize: norm=%2.2g too small during p%d\n",
               norm, qh->furthest_id));
        return;
      }
    }
  }
} /* normalize */


/*---------------------------------

  qh_projectpoint(qh, point, facet, dist )
    project point onto a facet by dist

  returns:
    returns a new point

  notes:
    if dist= distplane(point,facet)
      this projects point to hyperplane
    assumes qh_memfree_() is valid for normal_size
*/
pointT *qh_projectpoint(qhT *qh, pointT *point, facetT *facet, realT dist) {
  pointT *newpoint, *np, *normal;
  int normsize= qh->normal_size;
  int k;
  void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */

  qh_memalloc_(qh, normsize, freelistp, newpoint, pointT);
  np= newpoint;
  normal= facet->normal;
  for (k=qh->hull_dim; k--; )
    *(np++)= *point++ - dist * *normal++;
  return(newpoint);
} /* projectpoint */


/*---------------------------------

  qh_setfacetplane(qh, facet )
    sets the hyperplane for a facet
    if qh.RANDOMdist, joggles hyperplane

  notes:
    uses global buffers qh.gm_matrix and qh.gm_row
    overwrites facet->normal if already defined
    updates Wnewvertex if PRINTstatistics
    sets facet->upperdelaunay if upper envelope of Delaunay triangulation

  design:
    copy vertex coordinates to qh.gm_matrix/gm_row
    compute determinate
    if nearzero
      recompute determinate with gaussian elimination
      if nearzero
        force outside orientation by testing interior point
*/
void qh_setfacetplane(qhT *qh, facetT *facet) {
  pointT *point;
  vertexT *vertex, **vertexp;
  int normsize= qh->normal_size;
  int k,i, oldtrace= 0;
  realT dist;
  void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */
  coordT *coord, *gmcoord;
  pointT *point0= SETfirstt_(facet->vertices, vertexT)->point;
  boolT nearzero= False;

  zzinc_(Zsetplane);
  if (!facet->normal)
    qh_memalloc_(qh, normsize, freelistp, facet->normal, coordT);
#ifndef qh_NOtrace
  if (facet == qh->tracefacet) {
    oldtrace= qh->IStracing;
    qh->IStracing= 5;
    qh_fprintf(qh, qh->ferr, 8012, "qh_setfacetplane: facet f%d created.\n", facet->id);
    qh_fprintf(qh, qh->ferr, 8013, "  Last point added to hull was p%d.", qh->furthest_id);
    if (zzval_(Ztotmerge))
      qh_fprintf(qh, qh->ferr, 8014, "  Last merge was #%d.", zzval_(Ztotmerge));
    qh_fprintf(qh, qh->ferr, 8015, "\n\nCurrent summary is:\n");
      qh_printsummary(qh, qh->ferr);
  }
#endif
  if (qh->hull_dim <= 4) {
    i= 0;
    if (qh->RANDOMdist) {
      gmcoord= qh->gm_matrix;
      FOREACHvertex_(facet->vertices) {
        qh->gm_row[i++]= gmcoord;
        coord= vertex->point;
        for (k=qh->hull_dim; k--; )
          *(gmcoord++)= *coord++ * qh_randomfactor(qh, qh->RANDOMa, qh->RANDOMb);
      }
    }else {
      FOREACHvertex_(facet->vertices)
       qh->gm_row[i++]= vertex->point;
    }
    qh_sethyperplane_det(qh, qh->hull_dim, qh->gm_row, point0, facet->toporient,
                facet->normal, &facet->offset, &nearzero);
  }
  if (qh->hull_dim > 4 || nearzero) {
    i= 0;
    gmcoord= qh->gm_matrix;
    FOREACHvertex_(facet->vertices) {
      if (vertex->point != point0) {
        qh->gm_row[i++]= gmcoord;
        coord= vertex->point;
        point= point0;
        for (k=qh->hull_dim; k--; )
          *(gmcoord++)= *coord++ - *point++;
      }
    }
    qh->gm_row[i]= gmcoord;  /* for areasimplex */
    if (qh->RANDOMdist) {
      gmcoord= qh->gm_matrix;
      for (i=qh->hull_dim-1; i--; ) {
        for (k=qh->hull_dim; k--; )
          *(gmcoord++) *= qh_randomfactor(qh, qh->RANDOMa, qh->RANDOMb);
      }
    }
    qh_sethyperplane_gauss(qh, qh->hull_dim, qh->gm_row, point0, facet->toporient,
                facet->normal, &facet->offset, &nearzero);
    if (nearzero) {
      if (qh_orientoutside(qh, facet)) {
        trace0((qh, qh->ferr, 2, "qh_setfacetplane: flipped orientation due to nearzero gauss and interior_point test.  During p%d\n", qh->furthest_id));
      /* this is part of using Gaussian Elimination.  For example in 5-d
           1 1 1 1 0
           1 1 1 1 1
           0 0 0 1 0
           0 1 0 0 0
           1 0 0 0 0
           norm= 0.38 0.38 -0.76 0.38 0
         has a determinate of 1, but g.e. after subtracting pt. 0 has
         0's in the diagonal, even with full pivoting.  It does work
         if you subtract pt. 4 instead. */
      }
    }
  }
  facet->upperdelaunay= False;
  if (qh->DELAUNAY) {
    if (qh->UPPERdelaunay) {     /* matches qh_triangulate_facet and qh.lower_threshold in qh_initbuild */
      if (facet->normal[qh->hull_dim -1] >= qh->ANGLEround * qh_ZEROdelaunay)
        facet->upperdelaunay= True;
    }else {
      if (facet->normal[qh->hull_dim -1] > -qh->ANGLEround * qh_ZEROdelaunay)
        facet->upperdelaunay= True;
    }
  }
  if (qh->PRINTstatistics || qh->IStracing || qh->TRACElevel || qh->JOGGLEmax < REALmax) {
    qh->old_randomdist= qh->RANDOMdist;
    qh->RANDOMdist= False;
    FOREACHvertex_(facet->vertices) {
      if (vertex->point != point0) {
        boolT istrace= False;
        zinc_(Zdiststat);
        qh_distplane(qh, vertex->point, facet, &dist);
        dist= fabs_(dist);
        zinc_(Znewvertex);
        wadd_(Wnewvertex, dist);
        if (dist > wwval_(Wnewvertexmax)) {
          wwval_(Wnewvertexmax)= dist;
          if (dist > qh->max_outside) {
            qh->max_outside= dist;  /* used by qh_maxouter(qh) */
            if (dist > qh->TRACEdist)
              istrace= True;
          }
        }else if (-dist > qh->TRACEdist)
          istrace= True;
        if (istrace) {
          qh_fprintf(qh, qh->ferr, 3060, "qh_setfacetplane: ====== vertex p%d(v%d) increases max_outside to %2.2g for new facet f%d last p%d\n",
                qh_pointid(qh, vertex->point), vertex->id, dist, facet->id, qh->furthest_id);
          qh_errprint(qh, "DISTANT", facet, NULL, NULL, NULL);
        }
      }
    }
    qh->RANDOMdist= qh->old_randomdist;
  }
#ifndef qh_NOtrace
  if (qh->IStracing >= 4) {
    qh_fprintf(qh, qh->ferr, 8017, "qh_setfacetplane: f%d offset %2.2g normal: ",
             facet->id, facet->offset);
    for (k=0; k < qh->hull_dim; k++)
      qh_fprintf(qh, qh->ferr, 8018, "%2.2g ", facet->normal[k]);
    qh_fprintf(qh, qh->ferr, 8019, "\n");
  }
#endif
  qh_checkflipped(qh, facet, NULL, qh_ALL);
  if (facet == qh->tracefacet) {
    qh->IStracing= oldtrace;
    qh_printfacet(qh, qh->ferr, facet);
  }
} /* setfacetplane */


/*---------------------------------

  qh_sethyperplane_det(qh, dim, rows, point0, toporient, normal, offset, nearzero )
    given dim X dim array indexed by rows[], one row per point,
        toporient(flips all signs),
        and point0 (any row)
    set normalized hyperplane equation from oriented simplex

  returns:
    normal (normalized)
    offset (places point0 on the hyperplane)
    sets nearzero if hyperplane not through points

  notes:
    only defined for dim == 2..4
    rows[] is not modified
    solves det(P-V_0, V_n-V_0, ..., V_1-V_0)=0, i.e. every point is on hyperplane
    see Bower & Woodworth, A programmer's geometry, Butterworths 1983.

  derivation of 3-d minnorm
    Goal: all vertices V_i within qh.one_merge of hyperplane
    Plan: exactly translate the facet so that V_0 is the origin
          exactly rotate the facet so that V_1 is on the x-axis and y_2=0.
          exactly rotate the effective perturbation to only effect n_0
             this introduces a factor of sqrt(3)
    n_0 = ((y_2-y_0)*(z_1-z_0) - (z_2-z_0)*(y_1-y_0)) / norm
    Let M_d be the max coordinate difference
    Let M_a be the greater of M_d and the max abs. coordinate
    Let u be machine roundoff and distround be max error for distance computation
    The max error for n_0 is sqrt(3) u M_a M_d / norm.  n_1 is approx. 1 and n_2 is approx. 0
    The max error for distance of V_1 is sqrt(3) u M_a M_d M_d / norm.  Offset=0 at origin
    Then minnorm = 1.8 u M_a M_d M_d / qh.ONEmerge
    Note that qh.one_merge is approx. 45.5 u M_a and norm is usually about M_d M_d

  derivation of 4-d minnorm
    same as above except rotate the facet so that V_1 on x-axis and w_2, y_3, w_3=0
     [if two vertices fixed on x-axis, can rotate the other two in yzw.]
    n_0 = det3_(...) = y_2 det2_(z_1, w_1, z_3, w_3) = - y_2 w_1 z_3
     [all other terms contain at least two factors nearly zero.]
    The max error for n_0 is sqrt(4) u M_a M_d M_d / norm
    Then minnorm = 2 u M_a M_d M_d M_d / qh.ONEmerge
    Note that qh.one_merge is approx. 82 u M_a and norm is usually about M_d M_d M_d
*/
void qh_sethyperplane_det(qhT *qh, int dim, coordT **rows, coordT *point0,
          boolT toporient, coordT *normal, realT *offset, boolT *nearzero) {
  realT maxround, dist;
  int i;
  pointT *point;


  if (dim == 2) {
    normal[0]= dY(1,0);
    normal[1]= dX(0,1);
    qh_normalize2(qh, normal, dim, toporient, NULL, NULL);
    *offset= -(point0[0]*normal[0]+point0[1]*normal[1]);
    *nearzero= False;  /* since nearzero norm => incident points */
  }else if (dim == 3) {
    normal[0]= det2_(dY(2,0), dZ(2,0),
                     dY(1,0), dZ(1,0));
    normal[1]= det2_(dX(1,0), dZ(1,0),
                     dX(2,0), dZ(2,0));
    normal[2]= det2_(dX(2,0), dY(2,0),
                     dX(1,0), dY(1,0));
    qh_normalize2(qh, normal, dim, toporient, NULL, NULL);
    *offset= -(point0[0]*normal[0] + point0[1]*normal[1]
               + point0[2]*normal[2]);
    maxround= qh->DISTround;
    for (i=dim; i--; ) {
      point= rows[i];
      if (point != point0) {
        dist= *offset + (point[0]*normal[0] + point[1]*normal[1]
               + point[2]*normal[2]);
        if (dist > maxround || dist < -maxround) {
          *nearzero= True;
          break;
        }
      }
    }
  }else if (dim == 4) {
    normal[0]= - det3_(dY(2,0), dZ(2,0), dW(2,0),
                        dY(1,0), dZ(1,0), dW(1,0),
                        dY(3,0), dZ(3,0), dW(3,0));
    normal[1]=   det3_(dX(2,0), dZ(2,0), dW(2,0),
                        dX(1,0), dZ(1,0), dW(1,0),
                        dX(3,0), dZ(3,0), dW(3,0));
    normal[2]= - det3_(dX(2,0), dY(2,0), dW(2,0),
                        dX(1,0), dY(1,0), dW(1,0),
                        dX(3,0), dY(3,0), dW(3,0));
    normal[3]=   det3_(dX(2,0), dY(2,0), dZ(2,0),
                        dX(1,0), dY(1,0), dZ(1,0),
                        dX(3,0), dY(3,0), dZ(3,0));
    qh_normalize2(qh, normal, dim, toporient, NULL, NULL);
    *offset= -(point0[0]*normal[0] + point0[1]*normal[1]
               + point0[2]*normal[2] + point0[3]*normal[3]);
    maxround= qh->DISTround;
    for (i=dim; i--; ) {
      point= rows[i];
      if (point != point0) {
        dist= *offset + (point[0]*normal[0] + point[1]*normal[1]
               + point[2]*normal[2] + point[3]*normal[3]);
        if (dist > maxround || dist < -maxround) {
          *nearzero= True;
          break;
        }
      }
    }
  }
  if (*nearzero) {
    zzinc_(Zminnorm);
    /* qh_joggle_restart not needed, will call qh_sethyperplane_gauss instead */
    trace0((qh, qh->ferr, 3, "qh_sethyperplane_det: degenerate norm during p%d, use qh_sethyperplane_gauss instead.\n", qh->furthest_id));
  }
} /* sethyperplane_det */


/*---------------------------------

  qh_sethyperplane_gauss(qh, dim, rows, point0, toporient, normal, offset, nearzero )
    given(dim-1) X dim array of rows[i]= V_{i+1} - V_0 (point0)
    set normalized hyperplane equation from oriented simplex

  returns:
    normal (normalized)
    offset (places point0 on the hyperplane)

  notes:
    if nearzero
      orientation may be incorrect because of incorrect sign flips in gausselim
    solves [V_n-V_0,...,V_1-V_0, 0 .. 0 1] * N == [0 .. 0 1]
        or [V_n-V_0,...,V_1-V_0, 0 .. 0 1] * N == [0]
    i.e., N is normal to the hyperplane, and the unnormalized
        distance to [0 .. 1] is either 1 or   0

  design:
    perform gaussian elimination
    flip sign for negative values
    perform back substitution
    normalize result
    compute offset
*/
void qh_sethyperplane_gauss(qhT *qh, int dim, coordT **rows, pointT *point0,
                boolT toporient, coordT *normal, coordT *offset, boolT *nearzero) {
  coordT *pointcoord, *normalcoef;
  int k;
  boolT sign= toporient, nearzero2= False;

  qh_gausselim(qh, rows, dim-1, dim, &sign, nearzero);
  for (k=dim-1; k--; ) {
    if ((rows[k])[k] < 0)
      sign ^= 1;
  }
  if (*nearzero) {
    zzinc_(Znearlysingular);
    /* qh_joggle_restart ignored for Znearlysingular, normal part of qh_sethyperplane_gauss */
    trace0((qh, qh->ferr, 4, "qh_sethyperplane_gauss: nearly singular or axis parallel hyperplane during p%d.\n", qh->furthest_id));
    qh_backnormal(qh, rows, dim-1, dim, sign, normal, &nearzero2);
  }else {
    qh_backnormal(qh, rows, dim-1, dim, sign, normal, &nearzero2);
    if (nearzero2) {
      zzinc_(Znearlysingular);
      trace0((qh, qh->ferr, 5, "qh_sethyperplane_gauss: singular or axis parallel hyperplane at normalization during p%d.\n", qh->furthest_id));
    }
  }
  if (nearzero2)
    *nearzero= True;
  qh_normalize2(qh, normal, dim, True, NULL, NULL);
  pointcoord= point0;
  normalcoef= normal;
  *offset= -(*pointcoord++ * *normalcoef++);
  for (k=dim-1; k--; )
    *offset -= *pointcoord++ * *normalcoef++;
} /* sethyperplane_gauss */



qhull-2020.2/src/libqhull_r/geom_r.h0000644060175106010010000001765713661631132015555 0ustar  bbarber/*
  ---------------------------------

  geom_r.h
    header file for geometric routines

   see qh-geom_r.htm and geom_r.c

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull_r/geom_r.h#2 $$Change: 2953 $
   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
*/

#ifndef qhDEFgeom
#define qhDEFgeom 1

#include "libqhull_r.h"

/* ============ -macros- ======================== */

/*----------------------------------

  fabs_(a)
    returns the absolute value of a
*/
#define fabs_( a ) ((( a ) < 0 ) ? -( a ):( a ))

/*----------------------------------

  fmax_(a,b)
    returns the maximum value of a and b
*/
#define fmax_( a,b )  ( ( a ) < ( b ) ? ( b ) : ( a ) )

/*----------------------------------

  fmin_(a,b)
    returns the minimum value of a and b
*/
#define fmin_( a,b )  ( ( a ) > ( b ) ? ( b ) : ( a ) )

/*----------------------------------

  maximize_(maxval, val)
    set maxval to val if val is greater than maxval
*/
#define maximize_( maxval, val ) { if (( maxval ) < ( val )) ( maxval )= ( val ); }

/*----------------------------------

  minimize_(minval, val)
    set minval to val if val is less than minval
*/
#define minimize_( minval, val ) { if (( minval ) > ( val )) ( minval )= ( val ); }

/*----------------------------------

  det2_(a1, a2,
        b1, b2)

    compute a 2-d determinate
*/
#define det2_( a1,a2,b1,b2 ) (( a1 )*( b2 ) - ( a2 )*( b1 ))

/*----------------------------------

  det3_(a1, a2, a3,
       b1, b2, b3,
       c1, c2, c3)

    compute a 3-d determinate
*/
#define det3_( a1,a2,a3,b1,b2,b3,c1,c2,c3 ) ( ( a1 )*det2_( b2,b3,c2,c3 ) \
                - ( b1 )*det2_( a2,a3,c2,c3 ) + ( c1 )*det2_( a2,a3,b2,b3 ) )

/*----------------------------------

  dX( p1, p2 )
  dY( p1, p2 )
  dZ( p1, p2 )

    given two indices into rows[],

    compute the difference between X, Y, or Z coordinates
*/
#define dX( p1,p2 )  ( *( rows[p1] ) - *( rows[p2] ))
#define dY( p1,p2 )  ( *( rows[p1]+1 ) - *( rows[p2]+1 ))
#define dZ( p1,p2 )  ( *( rows[p1]+2 ) - *( rows[p2]+2 ))
#define dW( p1,p2 )  ( *( rows[p1]+3 ) - *( rows[p2]+3 ))

/*============= prototypes in alphabetical order, infrequent at end ======= */

#ifdef __cplusplus
extern "C" {
#endif

void    qh_backnormal(qhT *qh, realT **rows, int numrow, int numcol, boolT sign, coordT *normal, boolT *nearzero);
void    qh_distplane(qhT *qh, pointT *point, facetT *facet, realT *dist);
facetT *qh_findbest(qhT *qh, pointT *point, facetT *startfacet,
                     boolT bestoutside, boolT isnewfacets, boolT noupper,
                     realT *dist, boolT *isoutside, int *numpart);
facetT *qh_findbesthorizon(qhT *qh, boolT ischeckmax, pointT *point,
                     facetT *startfacet, boolT noupper, realT *bestdist, int *numpart);
facetT *qh_findbestnew(qhT *qh, pointT *point, facetT *startfacet, realT *dist,
                     boolT bestoutside, boolT *isoutside, int *numpart);
void    qh_gausselim(qhT *qh, realT **rows, int numrow, int numcol, boolT *sign, boolT *nearzero);
realT   qh_getangle(qhT *qh, pointT *vect1, pointT *vect2);
pointT *qh_getcenter(qhT *qh, setT *vertices);
pointT *qh_getcentrum(qhT *qh, facetT *facet);
coordT  qh_getdistance(qhT *qh, facetT *facet, facetT *neighbor, coordT *mindist, coordT *maxdist);
void    qh_normalize(qhT *qh, coordT *normal, int dim, boolT toporient);
void    qh_normalize2(qhT *qh, coordT *normal, int dim, boolT toporient,
            realT *minnorm, boolT *ismin);
pointT *qh_projectpoint(qhT *qh, pointT *point, facetT *facet, realT dist);

void    qh_setfacetplane(qhT *qh, facetT *newfacets);
void    qh_sethyperplane_det(qhT *qh, int dim, coordT **rows, coordT *point0,
              boolT toporient, coordT *normal, realT *offset, boolT *nearzero);
void    qh_sethyperplane_gauss(qhT *qh, int dim, coordT **rows, pointT *point0,
             boolT toporient, coordT *normal, coordT *offset, boolT *nearzero);
boolT   qh_sharpnewfacets(qhT *qh);

/*========= infrequently used code in geom2_r.c =============*/

coordT *qh_copypoints(qhT *qh, coordT *points, int numpoints, int dimension);
void    qh_crossproduct(int dim, realT vecA[3], realT vecB[3], realT vecC[3]);
realT   qh_determinant(qhT *qh, realT **rows, int dim, boolT *nearzero);
realT   qh_detjoggle(qhT *qh, pointT *points, int numpoints, int dimension);
void    qh_detmaxoutside(qhT *qh);
void    qh_detroundoff(qhT *qh);
realT   qh_detsimplex(qhT *qh, pointT *apex, setT *points, int dim, boolT *nearzero);
realT   qh_distnorm(int dim, pointT *point, pointT *normal, realT *offsetp);
realT   qh_distround(qhT *qh, int dimension, realT maxabs, realT maxsumabs);
realT   qh_divzero(realT numer, realT denom, realT mindenom1, boolT *zerodiv);
realT   qh_facetarea(qhT *qh, facetT *facet);
realT   qh_facetarea_simplex(qhT *qh, int dim, coordT *apex, setT *vertices,
          vertexT *notvertex,  boolT toporient, coordT *normal, realT *offset);
pointT *qh_facetcenter(qhT *qh, setT *vertices);
facetT *qh_findgooddist(qhT *qh, pointT *point, facetT *facetA, realT *distp, facetT **facetlist);
vertexT *qh_furthestnewvertex(qhT *qh, unsigned int unvisited, facetT *facet, realT *maxdistp /* qh.newvertex_list */);
vertexT *qh_furthestvertex(qhT *qh, facetT *facetA, facetT *facetB, realT *maxdistp, realT *mindistp);
void    qh_getarea(qhT *qh, facetT *facetlist);
boolT   qh_gram_schmidt(qhT *qh, int dim, realT **rows);
boolT   qh_inthresholds(qhT *qh, coordT *normal, realT *angle);
void    qh_joggleinput(qhT *qh);
realT  *qh_maxabsval(realT *normal, int dim);
setT   *qh_maxmin(qhT *qh, pointT *points, int numpoints, int dimension);
realT   qh_maxouter(qhT *qh);
void    qh_maxsimplex(qhT *qh, int dim, setT *maxpoints, pointT *points, int numpoints, setT **simplex);
realT   qh_minabsval(realT *normal, int dim);
int     qh_mindiff(realT *vecA, realT *vecB, int dim);
boolT   qh_orientoutside(qhT *qh, facetT *facet);
void    qh_outerinner(qhT *qh, facetT *facet, realT *outerplane, realT *innerplane);
coordT  qh_pointdist(pointT *point1, pointT *point2, int dim);
void    qh_printmatrix(qhT *qh, FILE *fp, const char *string, realT **rows, int numrow, int numcol);
void    qh_printpoints(qhT *qh, FILE *fp, const char *string, setT *points);
void    qh_projectinput(qhT *qh);
void    qh_projectpoints(qhT *qh, signed char *project, int n, realT *points,
             int numpoints, int dim, realT *newpoints, int newdim);
void    qh_rotateinput(qhT *qh, realT **rows);
void    qh_rotatepoints(qhT *qh, realT *points, int numpoints, int dim, realT **rows);
void    qh_scaleinput(qhT *qh);
void    qh_scalelast(qhT *qh, coordT *points, int numpoints, int dim, coordT low,
                   coordT high, coordT newhigh);
void    qh_scalepoints(qhT *qh, pointT *points, int numpoints, int dim,
                realT *newlows, realT *newhighs);
boolT   qh_sethalfspace(qhT *qh, int dim, coordT *coords, coordT **nextp,
              coordT *normal, coordT *offset, coordT *feasible);
coordT *qh_sethalfspace_all(qhT *qh, int dim, int count, coordT *halfspaces, pointT *feasible);
coordT  qh_vertex_bestdist(qhT *qh, setT *vertices);
coordT  qh_vertex_bestdist2(qhT *qh, setT *vertices, vertexT **vertexp, vertexT **vertexp2);
pointT *qh_voronoi_center(qhT *qh, int dim, setT *points);

#ifdef __cplusplus
} /* extern "C"*/
#endif

#endif /* qhDEFgeom */



qhull-2020.2/src/libqhull_r/global_r.c0000644060175106010010000024333613724257514016064 0ustar  bbarber
/*
  ---------------------------------

   global_r.c
   initializes all the globals of the qhull application

   see README

   see libqhull_r.h for qh.globals and function prototypes

   see qhull_ra.h for internal functions

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull_r/global_r.c#19 $$Change: 3037 $
   $DateTime: 2020/09/03 17:28:32 $$Author: bbarber $
 */

#include "qhull_ra.h"

/*========= qh->definition -- globals defined in libqhull_r.h =======================*/

/*----------------------------------

  qh_version
    version string by year and date
    qh_version2 for Unix users and -V

    the revision increases on code changes only

  notes:
    change date:    Changes.txt, Announce.txt, index.htm, README.txt,
                    qhull-news.html, Eudora signatures, CMakeLists.txt
    change version: README.txt, qh-get.htm, File_id.diz, Makefile.txt, CMakeLists.txt
    check that CMakeLists.txt @version is the same as qh_version2
    change year:    Copying.txt
    check download size
    recompile user_eg_r.c, rbox_r.c, libqhull_r.c, qconvex_r.c, qdelaun_r.c qvoronoi_r.c, qhalf_r.c, testqset_r.c
*/

const char qh_version[]= "2020.2.r 2020/08/31";
const char qh_version2[]= "qhull_r 8.0.2 (2020.2.r 2020/08/31)";

/*---------------------------------

  qh_appendprint(qh, printFormat )
    append printFormat to qh.PRINTout unless already defined
*/
void qh_appendprint(qhT *qh, qh_PRINT format) {
  int i;

  for (i=0; i < qh_PRINTEND; i++) {
    if (qh->PRINTout[i] == format && format != qh_PRINTqhull)
      break;
    if (!qh->PRINTout[i]) {
      qh->PRINTout[i]= format;
      break;
    }
  }
} /* appendprint */

/*---------------------------------

  qh_checkflags(qh, commandStr, hiddenFlags )
    errors if commandStr contains hiddenFlags
    hiddenFlags starts and ends with a space and is space delimited (checked)

  notes:
    ignores first word (e.g., "qconvex i")
    use qh_strtol/strtod since strtol/strtod may or may not skip trailing spaces

  see:
    qh_initflags() initializes Qhull according to commandStr
*/
void qh_checkflags(qhT *qh, char *command, char *hiddenflags) {
  char *s= command, *t, *chkerr; /* qh_skipfilename is non-const */
  char key, opt, prevopt;
  char chkkey[]=  "   ";    /* check one character options ('s') */
  char chkopt[]=  "    ";   /* check two character options ('Ta') */
  char chkopt2[]= "     ";  /* check three character options ('Q12') */
  boolT waserr= False;

  if (*hiddenflags != ' ' || hiddenflags[strlen(hiddenflags)-1] != ' ') {
    qh_fprintf(qh, qh->ferr, 6026, "qhull internal error (qh_checkflags): hiddenflags must start and end with a space: \"%s\"\n", hiddenflags);
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  if (strpbrk(hiddenflags, ",\n\r\t")) {
    qh_fprintf(qh, qh->ferr, 6027, "qhull internal error (qh_checkflags): hiddenflags contains commas, newlines, or tabs: \"%s\"\n", hiddenflags);
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  while (*s && !isspace(*s))  /* skip program name */
    s++;
  while (*s) {
    while (*s && isspace(*s))
      s++;
    if (*s == '-')
      s++;
    if (!*s)
      break;
    key= *s++;
    chkerr= NULL;
    if (key == 'T' && (*s == 'I' || *s == 'O')) {  /* TI or TO 'file name' */
      s= qh_skipfilename(qh, ++s);
      continue;
    }
    chkkey[1]= key;
    if (strstr(hiddenflags, chkkey)) {
      chkerr= chkkey;
    }else if (isupper(key)) {
      opt= ' ';
      prevopt= ' ';
      chkopt[1]= key;
      chkopt2[1]= key;
      while (!chkerr && *s && !isspace(*s)) {
        opt= *s++;
        if (isalpha(opt)) {
          chkopt[2]= opt;
          if (strstr(hiddenflags, chkopt))
            chkerr= chkopt;
          if (prevopt != ' ') {
            chkopt2[2]= prevopt;
            chkopt2[3]= opt;
            if (strstr(hiddenflags, chkopt2))
              chkerr= chkopt2;
          }
        }else if (key == 'Q' && isdigit(opt) && prevopt != 'b'
              && (prevopt == ' ' || islower(prevopt))) {
            if (isdigit(*s)) {  /* Q12 */
              chkopt2[2]= opt;
              chkopt2[3]= *s++;
              if (strstr(hiddenflags, chkopt2))
                chkerr= chkopt2;
            }else {
              chkopt[2]= opt;
              if (strstr(hiddenflags, chkopt))
                chkerr= chkopt;
            }
        }else {
          qh_strtod(s-1, &t);
          if (s < t)
            s= t;
        }
        prevopt= opt;
      }
    }
    if (chkerr) {
      *chkerr= '\'';
      chkerr[strlen(chkerr)-1]=  '\'';
      qh_fprintf(qh, qh->ferr, 6029, "qhull option error: option %s is not used with this program.\n             It may be used with qhull.\n", chkerr);
      waserr= True;
    }
  }
  if (waserr)
    qh_errexit(qh, qh_ERRinput, NULL, NULL);
} /* checkflags */

/*---------------------------------

  qh_clear_outputflags(qh)
    Clear output flags for QhullPoints
*/
void qh_clear_outputflags(qhT *qh) {
  int i,k;

  qh->ANNOTATEoutput= False;
  qh->DOintersections= False;
  qh->DROPdim= -1;
  qh->FORCEoutput= False;
  qh->GETarea= False;
  qh->GOODpoint= 0;
  qh->GOODpointp= NULL;
  qh->GOODthreshold= False;
  qh->GOODvertex= 0;
  qh->GOODvertexp= NULL;
  qh->IStracing= 0;
  qh->KEEParea= False;
  qh->KEEPmerge= False;
  qh->KEEPminArea= REALmax;
  qh->PRINTcentrums= False;
  qh->PRINTcoplanar= False;
  qh->PRINTdots= False;
  qh->PRINTgood= False;
  qh->PRINTinner= False;
  qh->PRINTneighbors= False;
  qh->PRINTnoplanes= False;
  qh->PRINToptions1st= False;
  qh->PRINTouter= False;
  qh->PRINTprecision= True;
  qh->PRINTridges= False;
  qh->PRINTspheres= False;
  qh->PRINTstatistics= False;
  qh->PRINTsummary= False;
  qh->PRINTtransparent= False;
  qh->SPLITthresholds= False;
  qh->TRACElevel= 0;
  qh->TRInormals= False;
  qh->USEstdout= False;
  qh->VERIFYoutput= False;
  for (k=qh->input_dim+1; k--; ) {  /* duplicated in qh_initqhull_buffers and qh_clear_outputflags */
    qh->lower_threshold[k]= -REALmax;
    qh->upper_threshold[k]= REALmax;
    qh->lower_bound[k]= -REALmax;
    qh->upper_bound[k]= REALmax;
  }

  for (i=0; i < qh_PRINTEND; i++) {
    qh->PRINTout[i]= qh_PRINTnone;
  }

  if (!qh->qhull_commandsiz2)
      qh->qhull_commandsiz2= (int)strlen(qh->qhull_command); /* WARN64 */
  else {
      qh->qhull_command[qh->qhull_commandsiz2]= '\0';
  }
  if (!qh->qhull_optionsiz2)
    qh->qhull_optionsiz2= (int)strlen(qh->qhull_options);  /* WARN64 */
  else {
    qh->qhull_options[qh->qhull_optionsiz2]= '\0';
    qh->qhull_optionlen= qh_OPTIONline;  /* start a new line */
  }
} /* clear_outputflags */

/*---------------------------------

  qh_clock()
    return user CPU time in 100ths (qh_SECtick)
    only defined for qh_CLOCKtype == 2

  notes:
    use first value to determine time 0
    from Stevens '92 8.15
*/
unsigned long qh_clock(qhT *qh) {

#if (qh_CLOCKtype == 2)
  struct tms time;
  static long clktck;  /* initialized first call and never updated */
  double ratio, cpu;
  unsigned long ticks;

  if (!clktck) {
    if ((clktck= sysconf(_SC_CLK_TCK)) < 0) {
      qh_fprintf(qh, qh->ferr, 6030, "qhull internal error (qh_clock): sysconf() failed.  Use qh_CLOCKtype 1 in user_r.h\n");
      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
    }
  }
  if (times(&time) == -1) {
    qh_fprintf(qh, qh->ferr, 6031, "qhull internal error (qh_clock): times() failed.  Use qh_CLOCKtype 1 in user_r.h\n");
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  ratio= qh_SECticks / (double)clktck;
  ticks= time.tms_utime * ratio;
  return ticks;
#else
  qh_fprintf(qh, qh->ferr, 6032, "qhull internal error (qh_clock): use qh_CLOCKtype 2 in user_r.h\n");
  qh_errexit(qh, qh_ERRqhull, NULL, NULL); /* never returns */
  return 0;
#endif
} /* clock */

/*---------------------------------

  qh_freebuffers()
    free up global memory buffers

  notes:
    must match qh_initbuffers()
*/
void qh_freebuffers(qhT *qh) {

  trace5((qh, qh->ferr, 5001, "qh_freebuffers: freeing up global memory buffers\n"));
  /* allocated by qh_initqhull_buffers */
  qh_setfree(qh, &qh->other_points);
  qh_setfree(qh, &qh->del_vertices);
  qh_setfree(qh, &qh->coplanarfacetset);
  qh_memfree(qh, qh->NEARzero, qh->hull_dim * (int)sizeof(realT));
  qh_memfree(qh, qh->lower_threshold, (qh->input_dim+1) * (int)sizeof(realT));
  qh_memfree(qh, qh->upper_threshold, (qh->input_dim+1) * (int)sizeof(realT));
  qh_memfree(qh, qh->lower_bound, (qh->input_dim+1) * (int)sizeof(realT));
  qh_memfree(qh, qh->upper_bound, (qh->input_dim+1) * (int)sizeof(realT));
  qh_memfree(qh, qh->gm_matrix, (qh->hull_dim+1) * qh->hull_dim * (int)sizeof(coordT));
  qh_memfree(qh, qh->gm_row, (qh->hull_dim+1) * (int)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;

  if (qh->line)                /* allocated by qh_readinput, freed if no error */
    qh_free(qh->line);
  if (qh->half_space)
    qh_free(qh->half_space);
  if (qh->temp_malloc)
    qh_free(qh->temp_malloc);
  if (qh->feasible_point)      /* allocated by qh_readfeasible */
    qh_free(qh->feasible_point);
  if (qh->feasible_string)     /* allocated by qh_initflags */
    qh_free(qh->feasible_string);
  qh->line= qh->feasible_string= NULL;
  qh->half_space= qh->feasible_point= qh->temp_malloc= NULL;
  /* usually allocated by qh_readinput */
  if (qh->first_point && qh->POINTSmalloc) {
    qh_free(qh->first_point);
    qh->first_point= NULL;
  }
  if (qh->input_points && qh->input_malloc) { /* set by qh_joggleinput */
    qh_free(qh->input_points);
    qh->input_points= NULL;
  }
  trace5((qh, qh->ferr, 5002, "qh_freebuffers: finished\n"));
} /* freebuffers */


/*---------------------------------

  qh_freebuild(qh, allmem )
    free global memory used by qh_initbuild and qh_buildhull
    if !allmem,
      does not free short memory (e.g., facetT, freed by qh_memfreeshort)

  design:
    free centrums
    free each vertex
    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 sets
    free temporary sets
*/
void qh_freebuild(qhT *qh, boolT allmem) {
  facetT *facet, *previousfacet= NULL;
  vertexT *vertex, *previousvertex= NULL;
  ridgeT *ridge, **ridgep, *previousridge= NULL;
  mergeT *merge, **mergep;
  int newsize;
  boolT freeall;

  /* free qhT global sets first, includes references from qh_buildhull */
  trace5((qh, qh->ferr, 5004, "qh_freebuild: free global sets\n"));
  FOREACHmerge_(qh->facet_mergeset)  /* usually empty */
    qh_memfree(qh, merge, (int)sizeof(mergeT));
  FOREACHmerge_(qh->degen_mergeset)  /* usually empty */
    qh_memfree(qh, merge, (int)sizeof(mergeT));
  FOREACHmerge_(qh->vertex_mergeset)  /* usually empty */
    qh_memfree(qh, merge, (int)sizeof(mergeT));
  qh->facet_mergeset= NULL;  /* temp set freed by qh_settempfree_all */
  qh->degen_mergeset= NULL;  /* temp set freed by qh_settempfree_all */
  qh->vertex_mergeset= NULL;  /* temp set freed by qh_settempfree_all */
  qh_setfree(qh, &(qh->hash_table));
  trace5((qh, qh->ferr, 5003, "qh_freebuild: free temporary sets (qh_settempfree_all)\n"));
  qh_settempfree_all(qh);
  trace1((qh, qh->ferr, 1005, "qh_freebuild: free memory from qh_inithull and qh_buildhull\n"));
  if (qh->del_vertices)
    qh_settruncate(qh, qh->del_vertices, 0);
  if (allmem) {
    while ((vertex= qh->vertex_list)) {
      if (vertex->next)
        qh_delvertex(qh, vertex);
      else {
        qh_memfree(qh, vertex, (int)sizeof(vertexT)); /* sentinel */
        qh->newvertex_list= qh->vertex_list= NULL;
        break;
      }
      previousvertex= vertex; /* in case of memory fault */
      QHULL_UNUSED(previousvertex)
    }
  }else if (qh->VERTEXneighbors) {
    FORALLvertices
      qh_setfreelong(qh, &(vertex->neighbors));
  }
  qh->VERTEXneighbors= False;
  qh->GOODclosest= NULL;
  if (allmem) {
    FORALLfacets {
      FOREACHridge_(facet->ridges)
        ridge->seen= False;
    }
    while ((facet= qh->facet_list)) {
      if (!facet->newfacet || !qh->NEWtentative || qh_setsize(qh, facet->ridges) > 1) { /* skip tentative horizon ridges */
        trace4((qh, qh->ferr, 4095, "qh_freebuild: delete the previously-seen ridges of f%d\n", facet->id));
        FOREACHridge_(facet->ridges) {
          if (ridge->seen)
            qh_delridge(qh, ridge);
          else
            ridge->seen= True;
          previousridge= ridge; /* in case of memory fault */
          QHULL_UNUSED(previousridge)
        }
      }
      qh_setfree(qh, &(facet->outsideset));
      qh_setfree(qh, &(facet->coplanarset));
      qh_setfree(qh, &(facet->neighbors));
      qh_setfree(qh, &(facet->ridges));
      qh_setfree(qh, &(facet->vertices));
      if (facet->next)
        qh_delfacet(qh, facet);
      else {
        qh_memfree(qh, facet, (int)sizeof(facetT));
        qh->visible_list= qh->newfacet_list= qh->facet_list= NULL;
      }
      previousfacet= facet; /* in case of memory fault */
      QHULL_UNUSED(previousfacet)
    }
  }else {
    freeall= True;
    if (qh_setlarger_quick(qh, qh->hull_dim + 1, &newsize))
      freeall= False;
    FORALLfacets {
      qh_setfreelong(qh, &(facet->outsideset));
      qh_setfreelong(qh, &(facet->coplanarset));
      if (!facet->simplicial || freeall) {
        qh_setfreelong(qh, &(facet->neighbors));
        qh_setfreelong(qh, &(facet->ridges));
        qh_setfreelong(qh, &(facet->vertices));
      }
    }
  }
  /* qh internal constants */
  qh_memfree(qh, qh->interior_point, qh->normal_size);
  qh->interior_point= NULL;
} /* freebuild */

/*---------------------------------

  qh_freeqhull(qh, allmem )

  free global memory and set qhT to 0
  if !allmem,
    does not free short memory (freed by qh_memfreeshort unless qh_NOmem)

notes:
  sets qh.NOerrexit in case caller forgets to
  Does not throw errors

see:
  see qh_initqhull_start2()
  For libqhull_r, qhstatT is part of qhT

design:
  free global and temporary memory from qh_initbuild and qh_buildhull
  free buffers
*/
void qh_freeqhull(qhT *qh, boolT allmem) {

  qh->NOerrexit= True;  /* no more setjmp since called at exit and ~QhullQh */
  trace1((qh, qh->ferr, 1006, "qh_freeqhull: free global memory\n"));
  qh_freebuild(qh, allmem);
  qh_freebuffers(qh);
  trace1((qh, qh->ferr, 1061, "qh_freeqhull: clear qhT except for qh.qhmem and qh.qhstat\n"));
  /* memset is the same in qh_freeqhull() and qh_initqhull_start2() */
  memset((char *)qh, 0, sizeof(qhT)-sizeof(qhmemT)-sizeof(qhstatT));
  qh->NOerrexit= True;
} /* freeqhull */

/*---------------------------------

  qh_init_A(qh, infile, outfile, errfile, argc, argv )
    initialize memory and stdio files
    convert input options to option string (qh.qhull_command)

  notes:
    infile may be NULL if qh_readpoints() is not called

    errfile should always be defined.  It is used for reporting
    errors.  outfile is used for output and format options.

    argc/argv may be 0/NULL

    called before error handling initialized
    qh_errexit() may not be used
*/
void qh_init_A(qhT *qh, FILE *infile, FILE *outfile, FILE *errfile, int argc, char *argv[]) {
  qh_meminit(qh, errfile);
  qh_initqhull_start(qh, infile, outfile, errfile);
  qh_init_qhull_command(qh, argc, argv);
} /* init_A */

/*---------------------------------

  qh_init_B(qh, points, numpoints, dim, ismalloc )
    initialize globals for points array

    points has numpoints dim-dimensional points
      points[0] is the first coordinate of the first point
      points[1] is the second coordinate of the first point
      points[dim] is the first coordinate of the second point

    ismalloc=True
      Qhull will call qh_free(points) on exit or input transformation
    ismalloc=False
      Qhull will allocate a new point array if needed for input transformation

    qh.qhull_command
      is the option string.
      It is defined by qh_init_B(), qh_qhull_command(), or qh_initflags

  returns:
    if qh.PROJECTinput or (qh.DELAUNAY and qh.PROJECTdelaunay)
      projects the input to a new point array

        if qh.DELAUNAY,
          qh.hull_dim is increased by one
        if qh.ATinfinity,
          qh_projectinput adds point-at-infinity for Delaunay tri.

    if qh.SCALEinput
      changes the upper and lower bounds of the input, see qh_scaleinput

    if qh.ROTATEinput
      rotates the input by a random rotation, see qh_rotateinput
      if qh.DELAUNAY
        rotates about the last coordinate

  notes:
    called after points are defined
    qh_errexit() may be used
*/
void qh_init_B(qhT *qh, coordT *points, int numpoints, int dim, boolT ismalloc) {
  qh_initqhull_globals(qh, points, numpoints, dim, ismalloc);
  if (qh->qhmem.LASTsize == 0)
    qh_initqhull_mem(qh);
  /* mem_r.c and qset_r.c are initialized */
  qh_initqhull_buffers(qh);
  qh_initthresholds(qh, qh->qhull_command);
  if (qh->PROJECTinput || (qh->DELAUNAY && qh->PROJECTdelaunay))
    qh_projectinput(qh);
  if (qh->SCALEinput)
    qh_scaleinput(qh);
  if (qh->ROTATErandom >= 0) {
    qh_randommatrix(qh, qh->gm_matrix, qh->hull_dim, qh->gm_row);
    if (qh->DELAUNAY) {
      int k, lastk= qh->hull_dim-1;
      for (k=0; k < lastk; k++) {
        qh->gm_row[k][lastk]= 0.0;
        qh->gm_row[lastk][k]= 0.0;
      }
      qh->gm_row[lastk][lastk]= 1.0;
    }
    qh_gram_schmidt(qh, qh->hull_dim, qh->gm_row);
    qh_rotateinput(qh, qh->gm_row);
  }
} /* init_B */

/*---------------------------------

  qh_init_qhull_command(qh, argc, argv )
    build qh.qhull_command from argc/argv
    Calls qh_exit if qhull_command is too short

  returns:
    a space-delimited string of options (just as typed)

  notes:
    makes option string easy to input and output

    argc/argv may be 0/NULL
*/
void qh_init_qhull_command(qhT *qh, int argc, char *argv[]) {

  if (!qh_argv_to_command(argc, argv, qh->qhull_command, (int)sizeof(qh->qhull_command))){
    /* Assumes qh.ferr is defined. */
    qh_fprintf(qh, qh->ferr, 6033, "qhull input error: more than %d characters in command line.\n",
          (int)sizeof(qh->qhull_command));
    qh_exit(qh_ERRinput);  /* error reported, can not use qh_errexit */
  }
} /* init_qhull_command */

/*---------------------------------

  qh_initflags(qh, commandStr )
    set flags and initialized constants from commandStr
    calls qh_exit() if qh.NOerrexit

  returns:
    sets qh.qhull_command to command if needed

  notes:
    ignores first word (e.g., 'qhull' in "qhull d")
    use qh_strtol/strtod since strtol/strtod may or may not skip trailing spaces

  see:
    qh_initthresholds() continues processing of 'Pdn' and 'PDn'
    'prompt' in unix_r.c for documentation

  design:
    for each space-delimited option group
      if top-level option
        check syntax
        append appropriate option to option string
        set appropriate global variable or append printFormat to print options
      else
        for each sub-option
          check syntax
          append appropriate option to option string
          set appropriate global variable or append printFormat to print options
*/
void qh_initflags(qhT *qh, char *command) {
  int k, i, lastproject;
  char *s= command, *t, *prev_s, *start, key, *lastwarning= NULL;
  boolT isgeom= False, wasproject;
  realT r;

  if(qh->NOerrexit){
    qh_fprintf(qh, qh->ferr, 6245, "qhull internal error (qh_initflags): qh.NOerrexit was not cleared before calling qh_initflags().  It should be cleared after setjmp().  Exit qhull.\n");
    qh_exit(qh_ERRqhull);
  }
#ifdef qh_RANDOMdist
  qh->RANDOMfactor= qh_RANDOMdist;
  qh_option(qh, "Random-qh_RANDOMdist", NULL, &qh->RANDOMfactor);
  qh->RANDOMdist= True;
#endif
  if (command <= &qh->qhull_command[0] || command > &qh->qhull_command[0] + sizeof(qh->qhull_command)) {
    if (command != &qh->qhull_command[0]) {
      *qh->qhull_command= '\0';
      strncat(qh->qhull_command, command, sizeof(qh->qhull_command)-strlen(qh->qhull_command)-1);
    }
    while (*s && !isspace(*s))  /* skip program name */
      s++;
  }
  while (*s) {
    while (*s && isspace(*s))
      s++;
    if (*s == '-')
      s++;
    if (!*s)
      break;
    prev_s= s;
    switch (*s++) {
    case 'd':
      qh_option(qh, "delaunay", NULL, NULL);
      qh->DELAUNAY= True;
      break;
    case 'f':
      qh_option(qh, "facets", NULL, NULL);
      qh_appendprint(qh, qh_PRINTfacets);
      break;
    case 'i':
      qh_option(qh, "incidence", NULL, NULL);
      qh_appendprint(qh, qh_PRINTincidences);
      break;
    case 'm':
      qh_option(qh, "mathematica", NULL, NULL);
      qh_appendprint(qh, qh_PRINTmathematica);
      break;
    case 'n':
      qh_option(qh, "normals", NULL, NULL);
      qh_appendprint(qh, qh_PRINTnormals);
      break;
    case 'o':
      qh_option(qh, "offFile", NULL, NULL);
      qh_appendprint(qh, qh_PRINToff);
      break;
    case 'p':
      qh_option(qh, "points", NULL, NULL);
      qh_appendprint(qh, qh_PRINTpoints);
      break;
    case 's':
      qh_option(qh, "summary", NULL, NULL);
      qh->PRINTsummary= True;
      break;
    case 'v':
      qh_option(qh, "voronoi", NULL, NULL);
      qh->VORONOI= True;
      qh->DELAUNAY= True;
      break;
    case 'A':
      if (!isdigit(*s) && *s != '.' && *s != '-') {
        qh_fprintf(qh, qh->ferr, 7002, "qhull input warning: no maximum cosine angle given for option 'An'.  A1.0 is coplanar\n");
        lastwarning= s-1;
      }else {
        if (*s == '-') {
          qh->premerge_cos= -qh_strtod(s, &s);
          qh_option(qh, "Angle-premerge-", NULL, &qh->premerge_cos);
          qh->PREmerge= True;
        }else {
          qh->postmerge_cos= qh_strtod(s, &s);
          qh_option(qh, "Angle-postmerge", NULL, &qh->postmerge_cos);
          qh->POSTmerge= True;
        }
        qh->MERGING= True;
      }
      break;
    case 'C':
      if (!isdigit(*s) && *s != '.' && *s != '-') {
        qh_fprintf(qh, qh->ferr, 7003, "qhull input warning: no centrum radius given for option 'Cn'\n");
        lastwarning= s-1;
      }else {
        if (*s == '-') {
          qh->premerge_centrum= -qh_strtod(s, &s);
          qh_option(qh, "Centrum-premerge-", NULL, &qh->premerge_centrum);
          qh->PREmerge= True;
        }else {
          qh->postmerge_centrum= qh_strtod(s, &s);
          qh_option(qh, "Centrum-postmerge", NULL, &qh->postmerge_centrum);
          qh->POSTmerge= True;
        }
        qh->MERGING= True;
      }
      break;
    case 'E':
      if (*s == '-') {
        qh_fprintf(qh, qh->ferr, 6363, "qhull option error: expecting a positive number for maximum roundoff 'En'.  Got '%s'\n", s-1);
        qh_errexit(qh, qh_ERRinput, NULL, NULL);
      }else if (!isdigit(*s)) {
        qh_fprintf(qh, qh->ferr, 7005, "qhull option warning: no maximum roundoff given for option 'En'\n");
        lastwarning= s-1;
      }else {
        qh->DISTround= qh_strtod(s, &s);
        qh_option(qh, "Distance-roundoff", NULL, &qh->DISTround);
        qh->SETroundoff= True;
      }
      break;
    case 'H':
      start= s;
      qh->HALFspace= True;
      qh_strtod(s, &t);
      while (t > s)  {
        if (*t && !isspace(*t)) {
          if (*t == ',')
            t++;
          else {
            qh_fprintf(qh, qh->ferr, 6364, "qhull option error: expecting 'Hn,n,n,...' for feasible point of halfspace intersection. Got '%s'\n", start-1);
            qh_errexit(qh, qh_ERRinput, NULL, NULL);
          }
        }
        s= t;
        qh_strtod(s, &t);
      }
      if (start < t) {
        if (!(qh->feasible_string= (char *)calloc((size_t)(t-start+1), (size_t)1))) {
          qh_fprintf(qh, qh->ferr, 6034, "qhull error: insufficient memory for 'Hn,n,n'\n");
          qh_errexit(qh, qh_ERRmem, NULL, NULL);
        }
        strncpy(qh->feasible_string, start, (size_t)(t-start));
        qh_option(qh, "Halfspace-about", NULL, NULL);
        qh_option(qh, qh->feasible_string, NULL, NULL);
      }else
        qh_option(qh, "Halfspace", NULL, NULL);
      break;
    case 'R':
      if (!isdigit(*s)) {
        qh_fprintf(qh, qh->ferr, 7007, "qhull option warning: missing random perturbation for option 'Rn'\n");
        lastwarning= s-1;
      }else {
        qh->RANDOMfactor= qh_strtod(s, &s);
        qh_option(qh, "Random-perturb", NULL, &qh->RANDOMfactor);
        qh->RANDOMdist= True;
      }
      break;
    case 'V':
      if (!isdigit(*s) && *s != '-') {
        qh_fprintf(qh, qh->ferr, 7008, "qhull option warning: missing visible distance for option 'Vn'\n");
        lastwarning= s-1;
      }else {
        qh->MINvisible= qh_strtod(s, &s);
        qh_option(qh, "Visible", NULL, &qh->MINvisible);
      }
      break;
    case 'U':
      if (!isdigit(*s) && *s != '-') {
        qh_fprintf(qh, qh->ferr, 7009, "qhull option warning: missing coplanar distance for option 'Un'\n");
        lastwarning= s-1;
      }else {
        qh->MAXcoplanar= qh_strtod(s, &s);
        qh_option(qh, "U-coplanar", NULL, &qh->MAXcoplanar);
      }
      break;
    case 'W':
      if (*s == '-') {
        qh_fprintf(qh, qh->ferr, 6365, "qhull option error: expecting a positive number for outside width 'Wn'.  Got '%s'\n", s-1);
        qh_errexit(qh, qh_ERRinput, NULL, NULL);
      }else if (!isdigit(*s)) {
        qh_fprintf(qh, qh->ferr, 7011, "qhull option warning: missing outside width for option 'Wn'\n");
        lastwarning= s-1;
      }else {
        qh->MINoutside= qh_strtod(s, &s);
        qh_option(qh, "W-outside", NULL, &qh->MINoutside);
        qh->APPROXhull= True;
      }
      break;
    /************  sub menus ***************/
    case 'F':
      while (*s && !isspace(*s)) {
        switch (*s++) {
        case 'a':
          qh_option(qh, "Farea", NULL, NULL);
          qh_appendprint(qh, qh_PRINTarea);
          qh->GETarea= True;
          break;
        case 'A':
          qh_option(qh, "FArea-total", NULL, NULL);
          qh->GETarea= True;
          break;
        case 'c':
          qh_option(qh, "Fcoplanars", NULL, NULL);
          qh_appendprint(qh, qh_PRINTcoplanars);
          break;
        case 'C':
          qh_option(qh, "FCentrums", NULL, NULL);
          qh_appendprint(qh, qh_PRINTcentrums);
          break;
        case 'd':
          qh_option(qh, "Fd-cdd-in", NULL, NULL);
          qh->CDDinput= True;
          break;
        case 'D':
          qh_option(qh, "FD-cdd-out", NULL, NULL);
          qh->CDDoutput= True;
          break;
        case 'F':
          qh_option(qh, "FFacets-xridge", NULL, NULL);
          qh_appendprint(qh, qh_PRINTfacets_xridge);
          break;
        case 'i':
          qh_option(qh, "Finner", NULL, NULL);
          qh_appendprint(qh, qh_PRINTinner);
          break;
        case 'I':
          qh_option(qh, "FIDs", NULL, NULL);
          qh_appendprint(qh, qh_PRINTids);
          break;
        case 'm':
          qh_option(qh, "Fmerges", NULL, NULL);
          qh_appendprint(qh, qh_PRINTmerges);
          break;
        case 'M':
          qh_option(qh, "FMaple", NULL, NULL);
          qh_appendprint(qh, qh_PRINTmaple);
          break;
        case 'n':
          qh_option(qh, "Fneighbors", NULL, NULL);
          qh_appendprint(qh, qh_PRINTneighbors);
          break;
        case 'N':
          qh_option(qh, "FNeighbors-vertex", NULL, NULL);
          qh_appendprint(qh, qh_PRINTvneighbors);
          break;
        case 'o':
          qh_option(qh, "Fouter", NULL, NULL);
          qh_appendprint(qh, qh_PRINTouter);
          break;
        case 'O':
          if (qh->PRINToptions1st) {
            qh_option(qh, "FOptions", NULL, NULL);
            qh_appendprint(qh, qh_PRINToptions);
          }else
            qh->PRINToptions1st= True;
          break;
        case 'p':
          qh_option(qh, "Fpoint-intersect", NULL, NULL);
          qh_appendprint(qh, qh_PRINTpointintersect);
          break;
        case 'P':
          qh_option(qh, "FPoint-nearest", NULL, NULL);
          qh_appendprint(qh, qh_PRINTpointnearest);
          break;
        case 'Q':
          qh_option(qh, "FQhull", NULL, NULL);
          qh_appendprint(qh, qh_PRINTqhull);
          break;
        case 's':
          qh_option(qh, "Fsummary", NULL, NULL);
          qh_appendprint(qh, qh_PRINTsummary);
          break;
        case 'S':
          qh_option(qh, "FSize", NULL, NULL);
          qh_appendprint(qh, qh_PRINTsize);
          qh->GETarea= True;
          break;
        case 't':
          qh_option(qh, "Ftriangles", NULL, NULL);
          qh_appendprint(qh, qh_PRINTtriangles);
          break;
        case 'v':
          /* option set in qh_initqhull_globals */
          qh_appendprint(qh, qh_PRINTvertices);
          break;
        case 'V':
          qh_option(qh, "FVertex-average", NULL, NULL);
          qh_appendprint(qh, qh_PRINTaverage);
          break;
        case 'x':
          qh_option(qh, "Fxtremes", NULL, NULL);
          qh_appendprint(qh, qh_PRINTextremes);
          break;
        default:
          s--;
          qh_fprintf(qh, qh->ferr, 7012, "qhull option warning: unknown 'F' output option 'F%c', skip to next space\n", (int)s[0]);
          lastwarning= s-1;
          while (*++s && !isspace(*s));
          break;
        }
      }
      break;
    case 'G':
      isgeom= True;
      qh_appendprint(qh, qh_PRINTgeom);
      while (*s && !isspace(*s)) {
        switch (*s++) {
        case 'a':
          qh_option(qh, "Gall-points", NULL, NULL);
          qh->PRINTdots= True;
          break;
        case 'c':
          qh_option(qh, "Gcentrums", NULL, NULL);
          qh->PRINTcentrums= True;
          break;
        case 'h':
          qh_option(qh, "Gintersections", NULL, NULL);
          qh->DOintersections= True;
          break;
        case 'i':
          qh_option(qh, "Ginner", NULL, NULL);
          qh->PRINTinner= True;
          break;
        case 'n':
          qh_option(qh, "Gno-planes", NULL, NULL);
          qh->PRINTnoplanes= True;
          break;
        case 'o':
          qh_option(qh, "Gouter", NULL, NULL);
          qh->PRINTouter= True;
          break;
        case 'p':
          qh_option(qh, "Gpoints", NULL, NULL);
          qh->PRINTcoplanar= True;
          break;
        case 'r':
          qh_option(qh, "Gridges", NULL, NULL);
          qh->PRINTridges= True;
          break;
        case 't':
          qh_option(qh, "Gtransparent", NULL, NULL);
          qh->PRINTtransparent= True;
          break;
        case 'v':
          qh_option(qh, "Gvertices", NULL, NULL);
          qh->PRINTspheres= True;
          break;
        case 'D':
          if (!isdigit(*s)) {
            qh_fprintf(qh, qh->ferr, 7004, "qhull option warning: missing dimension for option 'GDn'\n");
            lastwarning= s-2;
          }else {
            if (qh->DROPdim >= 0) {
              qh_fprintf(qh, qh->ferr, 7013, "qhull option warning: can only drop one dimension.  Previous 'GD%d' ignored\n",
                   qh->DROPdim);
              lastwarning= s-2;
            }
            qh->DROPdim= qh_strtol(s, &s);
            qh_option(qh, "GDrop-dim", &qh->DROPdim, NULL);
          }
          break;
        default:
          s--;
          qh_fprintf(qh, qh->ferr, 7014, "qhull option warning: unknown 'G' geomview option 'G%c', skip to next space\n", (int)s[0]);
          lastwarning= s-1;
          while (*++s && !isspace(*s));
          break;
        }
      }
      break;
    case 'P':
      while (*s && !isspace(*s)) {
        switch (*s++) {
        case 'd': case 'D':  /* see qh_initthresholds() */
          key= s[-1];
          i= qh_strtol(s, &s);
          r= 0;
          if (*s == ':') {
            s++;
            r= qh_strtod(s, &s);
          }
          if (key == 'd')
            qh_option(qh, "Pdrop-facets-dim-less", &i, &r);
          else
            qh_option(qh, "PDrop-facets-dim-more", &i, &r);
          break;
        case 'g':
          qh_option(qh, "Pgood-facets", NULL, NULL);
          qh->PRINTgood= True;
          break;
        case 'G':
          qh_option(qh, "PGood-facet-neighbors", NULL, NULL);
          qh->PRINTneighbors= True;
          break;
        case 'o':
          qh_option(qh, "Poutput-forced", NULL, NULL);
          qh->FORCEoutput= True;
          break;
        case 'p':
          qh_option(qh, "Pprecision-ignore", NULL, NULL);
          qh->PRINTprecision= False;
          break;
        case 'A':
          if (!isdigit(*s)) {
            qh_fprintf(qh, qh->ferr, 7006, "qhull option warning: missing facet count for keep area option 'PAn'\n");
            lastwarning= s-2;
          }else {
            qh->KEEParea= qh_strtol(s, &s);
            qh_option(qh, "PArea-keep", &qh->KEEParea, NULL);
            qh->GETarea= True;
          }
          break;
        case 'F':
          if (!isdigit(*s)) {
            qh_fprintf(qh, qh->ferr, 7010, "qhull option warning: missing facet area for option 'PFn'\n");
            lastwarning= s-2;
          }else {
            qh->KEEPminArea= qh_strtod(s, &s);
            qh_option(qh, "PFacet-area-keep", NULL, &qh->KEEPminArea);
            qh->GETarea= True;
          }
          break;
        case 'M':
          if (!isdigit(*s)) {
            qh_fprintf(qh, qh->ferr, 7090, "qhull option warning: missing merge count for option 'PMn'\n");
            lastwarning= s-2;
          }else {
            qh->KEEPmerge= qh_strtol(s, &s);
            qh_option(qh, "PMerge-keep", &qh->KEEPmerge, NULL);
          }
          break;
        default:
          s--;
          qh_fprintf(qh, qh->ferr, 7015, "qhull option warning: unknown 'P' print option 'P%c', skip to next space\n", (int)s[0]);
          lastwarning= s-1;
          while (*++s && !isspace(*s));
          break;
        }
      }
      break;
    case 'Q':
      lastproject= -1;
      while (*s && !isspace(*s)) {
        switch (*s++) {
        case 'a':
          qh_option(qh, "Qallow-short", NULL, NULL);
          qh->ALLOWshort= True;
          break;
        case 'b': case 'B':  /* handled by qh_initthresholds */
          key= s[-1];
          if (key == 'b' && *s == 'B') {
            s++;
            r= qh_DEFAULTbox;
            qh->SCALEinput= True;
            qh_option(qh, "QbBound-unit-box", NULL, &r);
            break;
          }
          if (key == 'b' && *s == 'b') {
            s++;
            qh->SCALElast= True;
            qh_option(qh, "Qbbound-last", NULL, NULL);
            break;
          }
          k= qh_strtol(s, &s);
          r= 0.0;
          wasproject= False;
          if (*s == ':') {
            s++;
            if ((r= qh_strtod(s, &s)) == 0.0) {
              t= s;            /* need true dimension for memory allocation */
              while (*t && !isspace(*t)) {
                if (toupper(*t++) == 'B'
                 && k == qh_strtol(t, &t)
                 && *t++ == ':'
                 && qh_strtod(t, &t) == 0.0) {
                  qh->PROJECTinput++;
                  trace2((qh, qh->ferr, 2004, "qh_initflags: project dimension %d\n", k));
                  qh_option(qh, "Qb-project-dim", &k, NULL);
                  wasproject= True;
                  lastproject= k;
                  break;
                }
              }
            }
          }
          if (!wasproject) {
            if (lastproject == k && r == 0.0)
              lastproject= -1;  /* doesn't catch all possible sequences */
            else if (key == 'b') {
              qh->SCALEinput= True;
              if (r == 0.0)
                r= -qh_DEFAULTbox;
              qh_option(qh, "Qbound-dim-low", &k, &r);
            }else {
              qh->SCALEinput= True;
              if (r == 0.0)
                r= qh_DEFAULTbox;
              qh_option(qh, "QBound-dim-high", &k, &r);
            }
          }
          break;
        case 'c':
          qh_option(qh, "Qcoplanar-keep", NULL, NULL);
          qh->KEEPcoplanar= True;
          break;
        case 'f':
          qh_option(qh, "Qfurthest-outside", NULL, NULL);
          qh->BESToutside= True;
          break;
        case 'g':
          qh_option(qh, "Qgood-facets-only", NULL, NULL);
          qh->ONLYgood= True;
          break;
        case 'i':
          qh_option(qh, "Qinterior-keep", NULL, NULL);
          qh->KEEPinside= True;
          break;
        case 'm':
          qh_option(qh, "Qmax-outside-only", NULL, NULL);
          qh->ONLYmax= True;
          break;
        case 'r':
          qh_option(qh, "Qrandom-outside", NULL, NULL);
          qh->RANDOMoutside= True;
          break;
        case 's':
          qh_option(qh, "Qsearch-initial-simplex", NULL, NULL);
          qh->ALLpoints= True;
          break;
        case 't':
          qh_option(qh, "Qtriangulate", NULL, NULL);
          qh->TRIangulate= True;
          break;
        case 'T':
          qh_option(qh, "QTestPoints", NULL, NULL);
          if (!isdigit(*s)) {
            qh_fprintf(qh, qh->ferr, 7091, "qhull option warning: missing number of test points for option 'QTn'\n");
            lastwarning= s-2;
          }else {
            qh->TESTpoints= qh_strtol(s, &s);
            qh_option(qh, "QTestPoints", &qh->TESTpoints, NULL);
          }
          break;
        case 'u':
          qh_option(qh, "QupperDelaunay", NULL, NULL);
          qh->UPPERdelaunay= True;
          break;
        case 'v':
          qh_option(qh, "Qvertex-neighbors-convex", NULL, NULL);
          qh->TESTvneighbors= True;
          break;
        case 'x':
          qh_option(qh, "Qxact-merge", NULL, NULL);
          qh->MERGEexact= True;
          break;
        case 'z':
          qh_option(qh, "Qz-infinity-point", NULL, NULL);
          qh->ATinfinity= True;
          break;
        case '0':
          qh_option(qh, "Q0-no-premerge", NULL, NULL);
          qh->NOpremerge= True;
          break;
        case '1':
          if (!isdigit(*s)) {
            qh_option(qh, "Q1-angle-merge", NULL, NULL);
            qh->ANGLEmerge= True;
            break;
          }
          switch (*s++) {
          case '0':
            qh_option(qh, "Q10-no-narrow", NULL, NULL);
            qh->NOnarrow= True;
            break;
          case '1':
            qh_option(qh, "Q11-trinormals Qtriangulate", NULL, NULL);
            qh->TRInormals= True;
            qh->TRIangulate= True;
            break;
          case '2':
            qh_option(qh, "Q12-allow-wide", NULL, NULL);
            qh->ALLOWwide= True;
            break;
          case '4':
#ifndef qh_NOmerge
            qh_option(qh, "Q14-merge-pinched-vertices", NULL, NULL);
            qh->MERGEpinched= True;
#else
            /* ignore 'Q14' for q_benchmark testing of difficult cases for Qhull */
            qh_fprintf(qh, qh->ferr, 7099, "qhull option warning: option 'Q14-merge-pinched' disabled due to qh_NOmerge\n");
#endif
            break;
          case '7':
            qh_option(qh, "Q15-check-duplicates", NULL, NULL);
            qh->CHECKduplicates= True;
            break;
          default:
            s--;
            qh_fprintf(qh, qh->ferr, 7016, "qhull option warning: unknown 'Q' qhull option 'Q1%c', skip to next space\n", (int)s[0]);
            lastwarning= s-1;
            while (*++s && !isspace(*s));
            break;
          }
          break;
        case '2':
          qh_option(qh, "Q2-no-merge-independent", NULL, NULL);
          qh->MERGEindependent= False;
          goto LABELcheckdigit;
          break; /* no gcc warnings */
        case '3':
          qh_option(qh, "Q3-no-merge-vertices", NULL, NULL);
          qh->MERGEvertices= False;
        LABELcheckdigit:
          if (isdigit(*s)) {
            qh_fprintf(qh, qh->ferr, 7017, "qhull option warning: can not follow '1', '2', or '3' with a digit.  'Q%c%c' skipped\n", *(s-1), *s);
            lastwarning= s-2;
            s++;
          }
          break;
        case '4':
          qh_option(qh, "Q4-avoid-old-into-new", NULL, NULL);
          qh->AVOIDold= True;
          break;
        case '5':
          qh_option(qh, "Q5-no-check-outer", NULL, NULL);
          qh->SKIPcheckmax= True;
          break;
        case '6':
          qh_option(qh, "Q6-no-concave-merge", NULL, NULL);
          qh->SKIPconvex= True;
          break;
        case '7':
          qh_option(qh, "Q7-no-breadth-first", NULL, NULL);
          qh->VIRTUALmemory= True;
          break;
        case '8':
          qh_option(qh, "Q8-no-near-inside", NULL, NULL);
          qh->NOnearinside= True;
          break;
        case '9':
          qh_option(qh, "Q9-pick-furthest", NULL, NULL);
          qh->PICKfurthest= True;
          break;
        case 'G':
          i= qh_strtol(s, &t);
          if (qh->GOODpoint) {
            qh_fprintf(qh, qh->ferr, 7018, "qhull option warning: good point already defined for option 'QGn'.  Ignored\n");
            lastwarning= s-2;
          }else if (s == t) {
            qh_fprintf(qh, qh->ferr, 7019, "qhull option warning: missing good point id for option 'QGn'.  Ignored\n");
            lastwarning= s-2;
          }else if (i < 0 || *s == '-') {
            qh->GOODpoint= i-1;
            qh_option(qh, "QGood-if-dont-see-point", &i, NULL);
          }else {
            qh->GOODpoint= i+1;
            qh_option(qh, "QGood-if-see-point", &i, NULL);
          }
          s= t;
          break;
        case 'J':
          if (!isdigit(*s) && *s != '-')
            qh->JOGGLEmax= 0.0;
          else {
            qh->JOGGLEmax= (realT) qh_strtod(s, &s);
            qh_option(qh, "QJoggle", NULL, &qh->JOGGLEmax);
          }
          break;
        case 'R':
          if (!isdigit(*s) && *s != '-') {
            qh_fprintf(qh, qh->ferr, 7020, "qhull option warning: missing random seed for option 'QRn'\n");
            lastwarning= s-2;
          }else {
            qh->ROTATErandom= i= qh_strtol(s, &s);
            if (i > 0)
              qh_option(qh, "QRotate-id", &i, NULL );
            else if (i < -1)
              qh_option(qh, "QRandom-seed", &i, NULL );
          }
          break;
        case 'V':
          i= qh_strtol(s, &t);
          if (qh->GOODvertex) {
            qh_fprintf(qh, qh->ferr, 7021, "qhull option warning: good vertex already defined for option 'QVn'.  Ignored\n");
            lastwarning= s-2;
          }else if (s == t) {
            qh_fprintf(qh, qh->ferr, 7022, "qhull option warning: no good point id given for option 'QVn'.  Ignored\n");
            lastwarning= s-2;
          }else if (i < 0) {
            qh->GOODvertex= i - 1;
            qh_option(qh, "QV-good-facets-not-point", &i, NULL);
          }else {
            qh_option(qh, "QV-good-facets-point", &i, NULL);
            qh->GOODvertex= i + 1;
          }
          s= t;
          break;
        case 'w':
          qh_option(qh, "Qwarn-allow", NULL, NULL);
          qh->ALLOWwarning= True;
          break;
        default:
          s--;
          qh_fprintf(qh, qh->ferr, 7023, "qhull option warning: unknown 'Q' qhull option 'Q%c', skip to next space\n", (int)s[0]);
          lastwarning= s-1;
          while (*++s && !isspace(*s));
          break;
        }
      }
      break;
    case 'T':
      while (*s && !isspace(*s)) {
        if (isdigit(*s) || *s == '-')
          qh->IStracing= qh_strtol(s, &s);
        else switch (*s++) {
        case 'a':
          qh_option(qh, "Tannotate-output", NULL, NULL);
          qh->ANNOTATEoutput= True;
          break;
        case 'c':
          qh_option(qh, "Tcheck-frequently", NULL, NULL);
          qh->CHECKfrequently= True;
          break;
        case 'f':
          qh_option(qh, "Tflush", NULL, NULL);
          qh->FLUSHprint= True;
          break;
        case 's':
          qh_option(qh, "Tstatistics", NULL, NULL);
          qh->PRINTstatistics= True;
          break;
        case 'v':
          qh_option(qh, "Tverify", NULL, NULL);
          qh->VERIFYoutput= True;
          break;
        case 'z':
          if (qh->ferr == qh_FILEstderr) {
            /* The C++ interface captures the output in qh_fprint_qhull() */
            qh_option(qh, "Tz-stdout", NULL, NULL);
            qh->USEstdout= True;
          }else if (!qh->fout) {
            qh_fprintf(qh, qh->ferr, 7024, "qhull option warning: output file undefined(stdout).  Option 'Tz' ignored.\n");
            lastwarning= s-2;
          }else {
            qh_option(qh, "Tz-stdout", NULL, NULL);
            qh->USEstdout= True;
            qh->ferr= qh->fout;
            qh->qhmem.ferr= qh->fout;
          }
          break;
        case 'C':
          if (!isdigit(*s)) {
            qh_fprintf(qh, qh->ferr, 7025, "qhull option warning: missing point id for cone for trace option 'TCn'\n");
            lastwarning= s-2;
          }else {
            i= qh_strtol(s, &s);
            qh_option(qh, "TCone-stop", &i, NULL);
            qh->STOPcone= i + 1;
          }
          break;
        case 'F':
          if (!isdigit(*s)) {
            qh_fprintf(qh, qh->ferr, 7026, "qhull option warning: missing frequency count for trace option 'TFn'\n");
            lastwarning= s-2;
          }else {
            qh->REPORTfreq= qh_strtol(s, &s);
            qh_option(qh, "TFacet-log", &qh->REPORTfreq, NULL);
            qh->REPORTfreq2= qh->REPORTfreq/2;  /* for tracemerging() */
          }
          break;
        case 'I':
          while (isspace(*s))
            s++;
          t= qh_skipfilename(qh, s);
          {
            char filename[qh_FILENAMElen];

            qh_copyfilename(qh, filename, (int)sizeof(filename), s, (int)(t-s));   /* WARN64 */
            s= t;
            if (!freopen(filename, "r", stdin)) {
              qh_fprintf(qh, qh->ferr, 6041, "qhull option error: cannot open 'TI' file \"%s\"\n", filename);
              qh_errexit(qh, qh_ERRinput, NULL, NULL);
            }else {
              qh_option(qh, "TInput-file", NULL, NULL);
              qh_option(qh, filename, NULL, NULL);
            }
          }
          break;
        case 'O':
          while (isspace(*s))
            s++;
          t= qh_skipfilename(qh, s);
          {
            char filename[qh_FILENAMElen];

            qh_copyfilename(qh, filename, (int)sizeof(filename), s, (int)(t-s));  /* WARN64 */
            if (!qh->fout) {
              qh_fprintf(qh, qh->ferr, 7092, "qhull option warning: qh.fout was not set by caller of qh_initflags.  Cannot use option 'TO' to redirect output.  Ignoring option 'TO'\n");
              lastwarning= s-2;
            }else if (!freopen(filename, "w", qh->fout)) {
              qh_fprintf(qh, qh->ferr, 6044, "qhull option error: cannot open file \"%s\" for writing as option 'TO'.  It is already in use or read-only\n", filename);
              qh_errexit(qh, qh_ERRinput, NULL, NULL);
            }else {
              qh_option(qh, "TOutput-file", NULL, NULL);
              qh_option(qh, filename, NULL, NULL);
            }
            s= t;
          }
          break;
        case 'A':
          if (!isdigit(*s)) {
            qh_fprintf(qh, qh->ferr, 7093, "qhull option warning: missing count of added points for trace option 'TAn'\n");
            lastwarning= s-2;
          }else {
            i= qh_strtol(s, &t);
            qh->STOPadd= i + 1;
            qh_option(qh, "TA-stop-add", &i, NULL);
          }
          s= t;
          break;
        case 'P':
          if (*s == '-') {
            if (s[1] == '1' && !isdigit(s[2])) {
              s += 2;
              qh->TRACEpoint= qh_IDunknown; /* qh_buildhull done */
              qh_option(qh, "Trace-point", &qh->TRACEpoint, NULL);
            }else {
              qh_fprintf(qh, qh->ferr, 7100, "qhull option warning: negative point id for trace option 'TPn'.  Expecting 'TP-1' for tracing after qh_buildhull and qh_postmerge\n");
              lastwarning= s-2;
              while (isdigit(*(++s)))
                ; /* skip digits */
            }
          }else if (!isdigit(*s)) {
            qh_fprintf(qh, qh->ferr, 7029, "qhull option warning: missing point id or -1 for trace option 'TPn'\n");
            lastwarning= s-2;
          }else {
            qh->TRACEpoint= qh_strtol(s, &s);
            qh_option(qh, "Trace-point", &qh->TRACEpoint, NULL);
          }
          break;
        case 'M':
          if (!isdigit(*s)) {
            qh_fprintf(qh, qh->ferr, 7030, "qhull option warning: missing merge id for trace option 'TMn'\n");
            lastwarning= s-2;
          }else {
            qh->TRACEmerge= qh_strtol(s, &s);
            qh_option(qh, "Trace-merge", &qh->TRACEmerge, NULL);
          }
          break;
        case 'R':
          if (!isdigit(*s)) {
            qh_fprintf(qh, qh->ferr, 7031, "qhull option warning: missing rerun count for trace option 'TRn'\n");
            lastwarning= s-2;
          }else {
            qh->RERUN= qh_strtol(s, &s);
            qh_option(qh, "TRerun", &qh->RERUN, NULL);
          }
          break;
        case 'V':
          i= qh_strtol(s, &t);
          if (s == t) {
            qh_fprintf(qh, qh->ferr, 7032, "qhull option warning: missing furthest point id for trace option 'TVn'\n");
            lastwarning= s-2;
          }else if (i < 0) {
            qh->STOPpoint= i - 1;
            qh_option(qh, "TV-stop-before-point", &i, NULL);
          }else {
            qh->STOPpoint= i + 1;
            qh_option(qh, "TV-stop-after-point", &i, NULL);
          }
          s= t;
          break;
        case 'W':
          if (!isdigit(*s)) {
            qh_fprintf(qh, qh->ferr, 7033, "qhull option warning: missing max width for trace option 'TWn'\n");
            lastwarning= s-2;
          }else {
            qh->TRACEdist= (realT) qh_strtod(s, &s);
            qh_option(qh, "TWide-trace", NULL, &qh->TRACEdist);
          }
          break;
        default:
          s--;
          qh_fprintf(qh, qh->ferr, 7034, "qhull option warning: unknown 'T' trace option 'T%c', skip to next space\n", (int)s[0]);
          lastwarning= s-2;
          while (*++s && !isspace(*s));
          break;
        }
      }
      break;
    default:
      qh_fprintf(qh, qh->ferr, 7094, "qhull option warning: unknown option '%c'(%x)\n",
        (int)s[-1], (int)s[-1]);
      lastwarning= s-2;
      break;
    }
    if (s-1 == prev_s && *s && !isspace(*s)) {
      qh_fprintf(qh, qh->ferr, 7036, "qhull option warning: missing space after option '%c'(%x), reserved for sub-options, ignoring '%c' options to next space\n",
               (int)*prev_s, (int)*prev_s, (int)*prev_s);
      lastwarning= s-1;
      while (*s && !isspace(*s))
        s++;
    }
  }
  if (qh->STOPcone && qh->JOGGLEmax < REALmax/2) {
    qh_fprintf(qh, qh->ferr, 7078, "qhull option warning: 'TCn' (stopCone) ignored when used with 'QJn' (joggle)\n");
    lastwarning= command;
  }
  if (isgeom && !qh->FORCEoutput && qh->PRINTout[1]) {
    qh_fprintf(qh, qh->ferr, 7037, "qhull option warning: additional output formats ('Fc',etc.) are not compatible with Geomview ('G').  Use option 'Po' to override\n");
    lastwarning= command;
  }
  if (lastwarning && !qh->ALLOWwarning) {
    qh_fprintf(qh, qh->ferr, 6035, "qhull option error: see previous warnings, use 'Qw' to override: '%s' (last offset %d)\n",
          command, (int)(lastwarning-command));
    qh_errexit(qh, qh_ERRinput, NULL, NULL);
  }
  trace4((qh, qh->ferr, 4093, "qh_initflags: option flags initialized\n"));
  /* set derived values in qh_initqhull_globals */
} /* initflags */


/*---------------------------------

  qh_initqhull_buffers(qh)
    initialize global memory buffers

  notes:
    must match qh_freebuffers()
*/
void qh_initqhull_buffers(qhT *qh) {
  int k;

  qh->TEMPsize= (qh->qhmem.LASTsize - (int)sizeof(setT))/SETelemsize;
  if (qh->TEMPsize <= 0 || qh->TEMPsize > qh->qhmem.LASTsize)
    qh->TEMPsize= 8;  /* e.g., if qh_NOmem */
  qh->other_points= qh_setnew(qh, qh->TEMPsize);
  qh->del_vertices= qh_setnew(qh, qh->TEMPsize);
  qh->coplanarfacetset= qh_setnew(qh, qh->TEMPsize);
  qh->NEARzero= (realT *)qh_memalloc(qh, qh->hull_dim * (int)sizeof(realT));
  qh->lower_threshold= (realT *)qh_memalloc(qh, (qh->input_dim+1) * (int)sizeof(realT));
  qh->upper_threshold= (realT *)qh_memalloc(qh, (qh->input_dim+1) * (int)sizeof(realT));
  qh->lower_bound= (realT *)qh_memalloc(qh, (qh->input_dim+1) * (int)sizeof(realT));
  qh->upper_bound= (realT *)qh_memalloc(qh, (qh->input_dim+1) * (int)sizeof(realT));
  for (k=qh->input_dim+1; k--; ) {  /* duplicated in qh_initqhull_buffers and qh_clear_outputflags */
    qh->lower_threshold[k]= -REALmax;
    qh->upper_threshold[k]= REALmax;
    qh->lower_bound[k]= -REALmax;
    qh->upper_bound[k]= REALmax;
  }
  qh->gm_matrix= (coordT *)qh_memalloc(qh, (qh->hull_dim+1) * qh->hull_dim * (int)sizeof(coordT));
  qh->gm_row= (coordT **)qh_memalloc(qh, (qh->hull_dim+1) * (int)sizeof(coordT *));
} /* initqhull_buffers */

/*---------------------------------

  qh_initqhull_globals(qh, points, numpoints, dim, ismalloc )
    initialize globals
    if ismalloc
      points were malloc'd and qhull should free at end

  returns:
    sets qh.first_point, num_points, input_dim, hull_dim and others
    seeds random number generator (seed=1 if tracing)
    modifies qh.hull_dim if ((qh.DELAUNAY and qh.PROJECTdelaunay) or qh.PROJECTinput)
    adjust user flags as needed
    also checks DIM3 dependencies and constants

  notes:
    do not use qh_point() since an input transformation may move them elsewhere
    qh_initqhull_start() sets default values for non-zero globals
    consider duplicate error checks in qh_readpoints.  It is called before qh_initqhull_globals

  design:
    initialize points array from input arguments
    test for qh.ZEROcentrum
      (i.e., use opposite vertex instead of cetrum for convexity testing)
    initialize qh.CENTERtype, qh.normal_size,
      qh.center_size, qh.TRACEpoint/level,
    initialize and test random numbers
    qh_initqhull_outputflags() -- adjust and test output flags
*/
void qh_initqhull_globals(qhT *qh, coordT *points, int numpoints, int dim, boolT ismalloc) {
  int seed, pointsneeded, extra= 0, i, randi, k;
  realT randr;
  realT factorial;

  time_t timedata;

  trace0((qh, qh->ferr, 13, "qh_initqhull_globals: for %s | %s\n", qh->rbox_command,
      qh->qhull_command));
  if (numpoints < 1 || numpoints > qh_POINTSmax) {
    qh_fprintf(qh, qh->ferr, 6412, "qhull input error (qh_initqhull_globals): expecting between 1 and %d points.  Got %d %d-d points\n",
      qh_POINTSmax, numpoints, dim);
    qh_errexit(qh, qh_ERRinput, NULL, NULL);
    /* same error message in qh_readpoints */
  }
  qh->POINTSmalloc= ismalloc;
  qh->first_point= points;
  qh->num_points= numpoints;
  qh->hull_dim= qh->input_dim= dim;
  if (!qh->NOpremerge && !qh->MERGEexact && !qh->PREmerge && qh->JOGGLEmax > REALmax/2) {
    qh->MERGING= True;
    if (qh->hull_dim <= 4) {
      qh->PREmerge= True;
      qh_option(qh, "_pre-merge", NULL, NULL);
    }else {
      qh->MERGEexact= True;
      qh_option(qh, "Qxact-merge", NULL, NULL);
    }
  }else if (qh->MERGEexact)
    qh->MERGING= True;
  if (qh->NOpremerge && (qh->MERGEexact || qh->PREmerge))
    qh_fprintf(qh, qh->ferr, 7095, "qhull option warning: 'Q0-no-premerge' ignored due to exact merge ('Qx') or pre-merge ('C-n' or 'A-n')\n");
  if (!qh->NOpremerge && qh->JOGGLEmax > REALmax/2) {
#ifdef qh_NOmerge
    qh->JOGGLEmax= 0.0;
#endif
  }
  if (qh->TRIangulate && qh->JOGGLEmax < REALmax/2 && !qh->PREmerge && !qh->POSTmerge && qh->PRINTprecision)
    qh_fprintf(qh, qh->ferr, 7038, "qhull option warning: joggle ('QJ') produces simplicial output (i.e., triangles in 2-D).  Unless merging is requested, option 'Qt' has no effect\n");
  if (qh->JOGGLEmax < REALmax/2 && qh->DELAUNAY && !qh->SCALEinput && !qh->SCALElast) {
    qh->SCALElast= True;
    qh_option(qh, "Qbbound-last-qj", NULL, NULL);
  }
  if (qh->MERGING && !qh->POSTmerge && qh->premerge_cos > REALmax/2
  && qh->premerge_centrum == 0.0) {
    qh->ZEROcentrum= True;
    qh->ZEROall_ok= True;
    qh_option(qh, "_zero-centrum", NULL, NULL);
  }
  if (qh->JOGGLEmax < REALmax/2 && REALepsilon > 2e-8 && qh->PRINTprecision)
    qh_fprintf(qh, qh->ferr, 7039, "qhull warning: real epsilon, %2.2g, is probably too large for joggle('QJn')\nRecompile with double precision reals(see user_r.h).\n",
          REALepsilon);
#ifdef qh_NOmerge
  if (qh->MERGING) {
    qh_fprintf(qh, qh->ferr, 6045, "qhull option error: merging not installed (qh_NOmerge) for 'Qx', 'Cn' or 'An')\n");
    qh_errexit(qh, qh_ERRinput, NULL, NULL);
  }
#endif
  if (qh->DELAUNAY && qh->KEEPcoplanar && !qh->KEEPinside) {
    qh->KEEPinside= True;
    qh_option(qh, "Qinterior-keep", NULL, NULL);
  }
  if (qh->VORONOI && !qh->DELAUNAY) {
    qh_fprintf(qh, qh->ferr, 6038, "qhull internal error (qh_initqhull_globals): if qh.VORONOI is set, qh.DELAUNAY must be set.  Qhull constructs the Delaunay triangulation in order to compute the Voronoi diagram\n");
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  if (qh->DELAUNAY && qh->HALFspace) {
    qh_fprintf(qh, qh->ferr, 6046, "qhull option error: can not use Delaunay('d') or Voronoi('v') with halfspace intersection('H')\n");
    qh_errexit(qh, qh_ERRinput, NULL, NULL);
    /* same error message in qh_readpoints */
  }
  if (!qh->DELAUNAY && (qh->UPPERdelaunay || qh->ATinfinity)) {
    qh_fprintf(qh, qh->ferr, 6047, "qhull option error: use upper-Delaunay('Qu') or infinity-point('Qz') with Delaunay('d') or Voronoi('v')\n");
    qh_errexit(qh, qh_ERRinput, NULL, NULL);
  }
  if (qh->UPPERdelaunay && qh->ATinfinity) {
    qh_fprintf(qh, qh->ferr, 6048, "qhull option error: can not use infinity-point('Qz') with upper-Delaunay('Qu')\n");
    qh_errexit(qh, qh_ERRinput, NULL, NULL);
  }
  if (qh->MERGEpinched && qh->ONLYgood) {
    qh_fprintf(qh, qh->ferr, 6362, "qhull option error: can not use merge-pinched-vertices ('Q14') with good-facets-only ('Qg')\n");
    qh_errexit(qh, qh_ERRinput, NULL, NULL);
  }
  if (qh->MERGEpinched && qh->hull_dim == 2) {
    trace2((qh, qh->ferr, 2108, "qh_initqhull_globals: disable qh.MERGEpinched for 2-d.  It has no effect"))
    qh->MERGEpinched= False;
  }
  if (qh->SCALElast && !qh->DELAUNAY && qh->PRINTprecision)
    qh_fprintf(qh, qh->ferr, 7040, "qhull option warning: option 'Qbb' (scale-last-coordinate) is normally used with 'd' or 'v'\n");
  qh->DOcheckmax= (!qh->SKIPcheckmax && (qh->MERGING || qh->APPROXhull));
  qh->KEEPnearinside= (qh->DOcheckmax && !(qh->KEEPinside && qh->KEEPcoplanar)
                          && !qh->NOnearinside);
  if (qh->MERGING)
    qh->CENTERtype= qh_AScentrum;
  else if (qh->VORONOI)
    qh->CENTERtype= qh_ASvoronoi;
  if (qh->TESTvneighbors && !qh->MERGING) {
    qh_fprintf(qh, qh->ferr, 6049, "qhull option error: test vertex neighbors('Qv') needs a merge option\n");
    qh_errexit(qh, qh_ERRinput, NULL ,NULL);
  }
  if (qh->PROJECTinput || (qh->DELAUNAY && qh->PROJECTdelaunay)) {
    qh->hull_dim -= qh->PROJECTinput;
    if (qh->DELAUNAY) {
      qh->hull_dim++;
      if (qh->ATinfinity)
        extra= 1;
    }
  }
  if (qh->hull_dim <= 1) {
    qh_fprintf(qh, qh->ferr, 6050, "qhull error: dimension %d must be > 1\n", qh->hull_dim);
    qh_errexit(qh, qh_ERRinput, NULL, NULL);
  }
  for (k=2, factorial=1.0; k < qh->hull_dim; k++)
    factorial *= k;
  qh->AREAfactor= 1.0 / factorial;
  trace2((qh, qh->ferr, 2005, "qh_initqhull_globals: initialize globals.  input_dim %d, numpoints %d, malloc? %d, projected %d to hull_dim %d\n",
        qh->input_dim, numpoints, ismalloc, qh->PROJECTinput, qh->hull_dim));
  qh->normal_size= qh->hull_dim * (int)sizeof(coordT);
  qh->center_size= qh->normal_size - (int)sizeof(coordT);
  pointsneeded= qh->hull_dim+1;
  if (qh->hull_dim > qh_DIMmergeVertex) {
    qh->MERGEvertices= False;
    qh_option(qh, "Q3-no-merge-vertices-dim-high", NULL, NULL);
  }
  if (qh->GOODpoint)
    pointsneeded++;
#ifdef qh_NOtrace
  if (qh->IStracing || qh->TRACEmerge || qh->TRACEpoint != qh_IDnone || qh->TRACEdist < REALmax/2) {
      qh_fprintf(qh, qh->ferr, 6051, "qhull option error: tracing is not installed (qh_NOtrace in user_r.h).  Trace options 'Tn', 'TMn', 'TPn' and 'TWn' mostly removed.  Continue with 'Qw' (allow warning)\n");
      if (!qh->ALLOWwarning)
        qh_errexit(qh, qh_ERRinput, NULL, NULL);
  }
#endif
  if (qh->RERUN > 1) {
    qh->TRACElastrun= qh->IStracing; /* qh_build_withrestart duplicates next conditional */
    if (qh->IStracing && qh->IStracing != -1) {
      qh_fprintf(qh, qh->ferr, 8162, "qh_initqhull_globals: trace last of TR%d runs at level %d\n", qh->RERUN, qh->IStracing);
      qh->IStracing= 0;
    }
  }else if (qh->TRACEpoint != qh_IDnone || qh->TRACEdist < REALmax/2 || qh->TRACEmerge) {
    qh->TRACElevel= (qh->IStracing ? qh->IStracing : 3);
    qh->IStracing= 0;
  }
  if (qh->ROTATErandom == 0 || qh->ROTATErandom == -1) {
    seed= (int)time(&timedata);
    if (qh->ROTATErandom  == -1) {
      seed= -seed;
      qh_option(qh, "QRandom-seed", &seed, NULL );
    }else
      qh_option(qh, "QRotate-random", &seed, NULL);
    qh->ROTATErandom= seed;
  }
  seed= qh->ROTATErandom;
  if (seed == INT_MIN)    /* default value */
    seed= 1;
  else if (seed < 0)
    seed= -seed;
  qh_RANDOMseed_(qh, seed);
  randr= 0.0;
  for (i=1000; i--; ) {
    randi= qh_RANDOMint;
    randr += randi;
    if (randi > qh_RANDOMmax) {
      qh_fprintf(qh, qh->ferr, 8036, "\
qhull configuration error (qh_RANDOMmax in user_r.h): random integer %d > qh_RANDOMmax (%.8g)\n",
               randi, qh_RANDOMmax);
      qh_errexit(qh, qh_ERRinput, NULL, NULL);
    }
  }
  qh_RANDOMseed_(qh, seed);
  randr= randr/1000;
  if (randr < qh_RANDOMmax * 0.1
  || randr > qh_RANDOMmax * 0.9)
    qh_fprintf(qh, qh->ferr, 8037, "\
qhull configuration warning (qh_RANDOMmax in user_r.h): average of 1000 random integers (%.2g) is much different than expected (%.2g).  Is qh_RANDOMmax (%.2g) wrong?\n",
             randr, qh_RANDOMmax * 0.5, qh_RANDOMmax);
  qh->RANDOMa= 2.0 * qh->RANDOMfactor/qh_RANDOMmax;
  qh->RANDOMb= 1.0 - qh->RANDOMfactor;
  if (qh_HASHfactor < 1.1) {
    qh_fprintf(qh, qh->ferr, 6052, "qhull internal error (qh_initqhull_globals): qh_HASHfactor %d must be at least 1.1.  Qhull uses linear hash probing\n",
      qh_HASHfactor);
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  if (numpoints+extra < pointsneeded) {
    qh_fprintf(qh, qh->ferr, 6214, "qhull input error: not enough points(%d) to construct initial simplex (need %d)\n",
            numpoints, pointsneeded);
    qh_errexit(qh, qh_ERRinput, NULL, NULL);
  }
  qh_initqhull_outputflags(qh);
} /* initqhull_globals */

/*---------------------------------

  qh_initqhull_mem(qh )
    initialize mem_r.c for qhull
    qh.hull_dim and qh.normal_size determine some of the allocation sizes
    if qh.MERGING,
      includes ridgeT
    calls qh_user_memsizes (user_r.c) to add up to 10 additional sizes for quick allocation
      (see numsizes below)

  returns:
    mem_r.c already for qh_memalloc/qh_memfree (errors if called beforehand)

  notes:
    qh_produceoutput() prints memsizes

*/
void qh_initqhull_mem(qhT *qh) {
  int numsizes;
  int i;

  numsizes= 8+10;
  qh_meminitbuffers(qh, qh->IStracing, qh_MEMalign, numsizes,
                     qh_MEMbufsize, qh_MEMinitbuf);
  qh_memsize(qh, (int)sizeof(vertexT));
  if (qh->MERGING) {
    qh_memsize(qh, (int)sizeof(ridgeT));
    qh_memsize(qh, (int)sizeof(mergeT));
  }
  qh_memsize(qh, (int)sizeof(facetT));
  i= (int)sizeof(setT) + (qh->hull_dim - 1) * SETelemsize;  /* ridge.vertices */
  qh_memsize(qh, i);
  qh_memsize(qh, qh->normal_size);        /* normal */
  i += SETelemsize;                 /* facet.vertices, .ridges, .neighbors */
  qh_memsize(qh, i);
  qh_user_memsizes(qh);
  qh_memsetup(qh);
} /* initqhull_mem */

/*---------------------------------

  qh_initqhull_outputflags
    initialize flags concerned with output

  returns:
    adjust user flags as needed

  see:
    qh_clear_outputflags() resets the flags

  design:
    test for qh.PRINTgood (i.e., only print 'good' facets)
    check for conflicting print output options
*/
void qh_initqhull_outputflags(qhT *qh) {
  boolT printgeom= False, printmath= False, printcoplanar= False;
  int i;

  trace3((qh, qh->ferr, 3024, "qh_initqhull_outputflags: %s\n", qh->qhull_command));
  if (!(qh->PRINTgood || qh->PRINTneighbors)) {
    if (qh->DELAUNAY || qh->KEEParea || qh->KEEPminArea < REALmax/2 || qh->KEEPmerge
        || (!qh->ONLYgood && (qh->GOODvertex || qh->GOODpoint))) {
      qh->PRINTgood= True;
      qh_option(qh, "Pgood", NULL, NULL);
    }
  }
  if (qh->PRINTtransparent) {
    if (qh->hull_dim != 4 || !qh->DELAUNAY || qh->VORONOI || qh->DROPdim >= 0) {
      qh_fprintf(qh, qh->ferr, 6215, "qhull option error: transparent Delaunay('Gt') needs 3-d Delaunay('d') w/o 'GDn'\n");
      qh_errexit(qh, qh_ERRinput, NULL, NULL);
    }
    qh->DROPdim= 3;
    qh->PRINTridges= True;
  }
  for (i=qh_PRINTEND; i--; ) {
    if (qh->PRINTout[i] == qh_PRINTgeom)
      printgeom= True;
    else if (qh->PRINTout[i] == qh_PRINTmathematica || qh->PRINTout[i] == qh_PRINTmaple)
      printmath= True;
    else if (qh->PRINTout[i] == qh_PRINTcoplanars)
      printcoplanar= True;
    else if (qh->PRINTout[i] == qh_PRINTpointnearest)
      printcoplanar= True;
    else if (qh->PRINTout[i] == qh_PRINTpointintersect && !qh->HALFspace) {
      qh_fprintf(qh, qh->ferr, 6053, "qhull option error: option 'Fp' is only used for \nhalfspace intersection('Hn,n,n').\n");
      qh_errexit(qh, qh_ERRinput, NULL, NULL);
    }else if (qh->PRINTout[i] == qh_PRINTtriangles && (qh->HALFspace || qh->VORONOI)) {
      qh_fprintf(qh, qh->ferr, 6054, "qhull option error: option 'Ft' is not available for Voronoi vertices ('v') or halfspace intersection ('H')\n");
      qh_errexit(qh, qh_ERRinput, NULL, NULL);
    }else if (qh->PRINTout[i] == qh_PRINTcentrums && qh->VORONOI) {
      qh_fprintf(qh, qh->ferr, 6055, "qhull option error: option 'FC' is not available for Voronoi vertices('v')\n");
      qh_errexit(qh, qh_ERRinput, NULL, NULL);
    }else if (qh->PRINTout[i] == qh_PRINTvertices) {
      if (qh->VORONOI)
        qh_option(qh, "Fvoronoi", NULL, NULL);
      else
        qh_option(qh, "Fvertices", NULL, NULL);
    }
  }
  if (printcoplanar && qh->DELAUNAY && qh->JOGGLEmax < REALmax/2) {
    if (qh->PRINTprecision)
      qh_fprintf(qh, qh->ferr, 7041, "qhull option warning: 'QJ' (joggle) will usually prevent coincident input sites for options 'Fc' and 'FP'\n");
  }
  if (printmath && (qh->hull_dim > 3 || qh->VORONOI)) {
    qh_fprintf(qh, qh->ferr, 6056, "qhull option error: Mathematica and Maple output is only available for 2-d and 3-d convex hulls and 2-d Delaunay triangulations\n");
    qh_errexit(qh, qh_ERRinput, NULL, NULL);
  }
  if (printgeom) {
    if (qh->hull_dim > 4) {
      qh_fprintf(qh, qh->ferr, 6057, "qhull option error: Geomview output is only available for 2-d, 3-d and 4-d\n");
      qh_errexit(qh, qh_ERRinput, NULL, NULL);
    }
    if (qh->PRINTnoplanes && !(qh->PRINTcoplanar + qh->PRINTcentrums
     + qh->PRINTdots + qh->PRINTspheres + qh->DOintersections + qh->PRINTridges)) {
      qh_fprintf(qh, qh->ferr, 6058, "qhull option error: no output specified for Geomview\n");
      qh_errexit(qh, qh_ERRinput, NULL, NULL);
    }
    if (qh->VORONOI && (qh->hull_dim > 3 || qh->DROPdim >= 0)) {
      qh_fprintf(qh, qh->ferr, 6059, "qhull option error: Geomview output for Voronoi diagrams only for 2-d\n");
      qh_errexit(qh, qh_ERRinput, NULL, NULL);
    }
    /* can not warn about furthest-site Geomview output: no lower_threshold */
    if (qh->hull_dim == 4 && qh->DROPdim == -1 &&
        (qh->PRINTcoplanar || qh->PRINTspheres || qh->PRINTcentrums)) {
      qh_fprintf(qh, qh->ferr, 7042, "qhull option warning: coplanars, vertices, and centrums output not available for 4-d output(ignored).  Could use 'GDn' instead.\n");
      qh->PRINTcoplanar= qh->PRINTspheres= qh->PRINTcentrums= False;
    }
  }
  if (!qh->KEEPcoplanar && !qh->KEEPinside && !qh->ONLYgood) {
    if ((qh->PRINTcoplanar && qh->PRINTspheres) || printcoplanar) {
      if (qh->QHULLfinished) {
        qh_fprintf(qh, qh->ferr, 7072, "qhull output warning: ignoring coplanar points, option 'Qc' was not set for the first run of qhull.\n");
      }else {
        qh->KEEPcoplanar= True;
        qh_option(qh, "Qcoplanar", NULL, NULL);
      }
    }
  }
  qh->PRINTdim= qh->hull_dim;
  if (qh->DROPdim >=0) {    /* after Geomview checks */
    if (qh->DROPdim < qh->hull_dim) {
      qh->PRINTdim--;
      if (!printgeom || qh->hull_dim < 3)
        qh_fprintf(qh, qh->ferr, 7043, "qhull option warning: drop dimension 'GD%d' is only available for 3-d/4-d Geomview\n", qh->DROPdim);
    }else
      qh->DROPdim= -1;
  }else if (qh->VORONOI) {
    qh->DROPdim= qh->hull_dim-1;
    qh->PRINTdim= qh->hull_dim-1;
  }
} /* qh_initqhull_outputflags */

/*---------------------------------

  qh_initqhull_start(qh, infile, outfile, errfile )
    allocate memory if needed and call qh_initqhull_start2()
*/
void qh_initqhull_start(qhT *qh, FILE *infile, FILE *outfile, FILE *errfile) {

  qh_initstatistics(qh);
  qh_initqhull_start2(qh, infile, outfile, errfile);
} /* initqhull_start */

/*---------------------------------

  qh_initqhull_start2(qh, infile, outfile, errfile )
    start initialization of qhull
    initialize statistics, stdio, default values for global variables
    assumes qh is allocated
  notes:
    report errors elsewhere, error handling and g_qhull_output [Qhull.cpp, QhullQh()] not in initialized
  see:
    qh_maxmin() determines the precision constants
    qh_freeqhull()
*/
void qh_initqhull_start2(qhT *qh, FILE *infile, FILE *outfile, FILE *errfile) {
  time_t timedata;
  int seed;

  qh_CPUclock; /* start the clock(for qh_clock).  One-shot. */
  /* memset is the same in qh_freeqhull() and qh_initqhull_start2() */
  memset((char *)qh, 0, sizeof(qhT)-sizeof(qhmemT)-sizeof(qhstatT));   /* every field is 0, FALSE, NULL */
  qh->NOerrexit= True;
  qh->DROPdim= -1;
  qh->ferr= errfile;
  qh->fin= infile;
  qh->fout= outfile;
  qh->furthest_id= qh_IDunknown;
#ifndef qh_NOmerge
  qh->JOGGLEmax= REALmax;
#else
  qh->JOGGLEmax= 0.0;  /* Joggle ('QJ') if qh_NOmerge */
#endif
  qh->KEEPminArea= REALmax;
  qh->last_low= REALmax;
  qh->last_high= REALmax;
  qh->last_newhigh= REALmax;
  qh->last_random= 1; /* reentrant only */
  qh->lastcpu= 0.0;
  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= qh_IDnone;    /* recompile to trace a point, or use 'TPn' */
  qh->tracefacet_id= UINT_MAX;  /* recompile to trace a facet, set to UINT_MAX when done, see userprintf_r.c/qh_fprintf */
  qh->traceridge_id= UINT_MAX;  /* recompile to trace a ridge, set to UINT_MAX when done, see userprintf_r.c/qh_fprintf */
  qh->tracevertex_id= UINT_MAX; /* recompile to trace a vertex, set to UINT_MAX when done, see userprintf_r.c/qh_fprintf */
  seed= (int)time(&timedata);
  qh_RANDOMseed_(qh, seed);
  qh->run_id= qh_RANDOMint;
  if(!qh->run_id)
      qh->run_id++;  /* guarantee non-zero */
  qh_option(qh, "run-id", &qh->run_id, NULL);
  strcat(qh->qhull, "qhull");
} /* initqhull_start2 */

/*---------------------------------

  qh_initthresholds(qh, commandString )
    set thresholds for printing and scaling from commandString

  returns:
    sets qh.GOODthreshold or qh.SPLITthreshold if 'Pd0D1' used

  see:
    qh_initflags(), 'Qbk' 'QBk' 'Pdk' and 'PDk'
    qh_inthresholds()

  design:
    for each 'Pdn' or 'PDn' option
      check syntax
      set qh.lower_threshold or qh.upper_threshold
    set qh.GOODthreshold if an unbounded threshold is used
    set qh.SPLITthreshold if a bounded threshold is used
*/
void qh_initthresholds(qhT *qh, char *command) {
  realT value;
  int idx, maxdim, k;
  char *s= command; /* non-const due to strtol */
  char *lastoption, *lastwarning= NULL;
  char key;

  maxdim= qh->input_dim;
  if (qh->DELAUNAY && (qh->PROJECTdelaunay || qh->PROJECTinput))
    maxdim++;
  while (*s) {
    if (*s == '-')
      s++;
    if (*s == 'P') {
      lastoption= s++;
      while (*s && !isspace(key= *s++)) {
        if (key == 'd' || key == 'D') {
          if (!isdigit(*s)) {
            qh_fprintf(qh, qh->ferr, 7044, "qhull option warning: no dimension given for Print option 'P%c' at: %s.  Ignored\n",
                    key, s-1);
            lastwarning= lastoption;
            continue;
          }
          idx= qh_strtol(s, &s);
          if (idx >= qh->hull_dim) {
            qh_fprintf(qh, qh->ferr, 7045, "qhull option warning: dimension %d for Print option 'P%c' is >= %d.  Ignored\n",
                idx, key, qh->hull_dim);
            lastwarning= lastoption;
            continue;
          }
          if (*s == ':') {
            s++;
            value= qh_strtod(s, &s);
            if (fabs((double)value) > 1.0) {
              qh_fprintf(qh, qh->ferr, 7046, "qhull option warning: value %2.4g for Print option 'P%c' is > +1 or < -1.  Ignored\n",
                      value, key);
              lastwarning= lastoption;
              continue;
            }
          }else
            value= 0.0;
          if (key == 'd')
            qh->lower_threshold[idx]= value;
          else
            qh->upper_threshold[idx]= value;
        }
      }
    }else if (*s == 'Q') {
      lastoption= s++;
      while (*s && !isspace(key= *s++)) {
        if (key == 'b' && *s == 'B') {
          s++;
          for (k=maxdim; k--; ) {
            qh->lower_bound[k]= -qh_DEFAULTbox;
            qh->upper_bound[k]= qh_DEFAULTbox;
          }
        }else if (key == 'b' && *s == 'b')
          s++;
        else if (key == 'b' || key == 'B') {
          if (!isdigit(*s)) {
            qh_fprintf(qh, qh->ferr, 7047, "qhull option warning: no dimension given for Qhull option 'Q%c'\n",
                    key);
            lastwarning= lastoption;
            continue;
          }
          idx= qh_strtol(s, &s);
          if (idx >= maxdim) {
            qh_fprintf(qh, qh->ferr, 7048, "qhull option warning: dimension %d for Qhull option 'Q%c' is >= %d.  Ignored\n",
                idx, key, maxdim);
            lastwarning= lastoption;
            continue;
          }
          if (*s == ':') {
            s++;
            value= qh_strtod(s, &s);
          }else if (key == 'b')
            value= -qh_DEFAULTbox;
          else
            value= qh_DEFAULTbox;
          if (key == 'b')
            qh->lower_bound[idx]= value;
          else
            qh->upper_bound[idx]= value;
        }
      }
    }else {
      while (*s && !isspace(*s))
        s++;
    }
    while (isspace(*s))
      s++;
  }
  for (k=qh->hull_dim; k--; ) {
    if (qh->lower_threshold[k] > -REALmax/2) {
      qh->GOODthreshold= True;
      if (qh->upper_threshold[k] < REALmax/2) {
        qh->SPLITthresholds= True;
        qh->GOODthreshold= False;
        break;
      }
    }else if (qh->upper_threshold[k] < REALmax/2)
      qh->GOODthreshold= True;
  }
  if (lastwarning && !qh->ALLOWwarning) {
    qh_fprintf(qh, qh->ferr, 6036, "qhull option error: see previous warnings, use 'Qw' to override: '%s' (last offset %d)\n",
      command, (int)(lastwarning-command));
    qh_errexit(qh, qh_ERRinput, NULL, NULL);
  }
} /* initthresholds */

/*---------------------------------

  qh_lib_check( qhullLibraryType, qhTsize, vertexTsize, ridgeTsize, facetTsize, setTsize, qhmemTsize )
    Report error if library does not agree with caller

  notes:
    NOerrors -- qh_lib_check can not call qh_errexit()
*/
void qh_lib_check(int qhullLibraryType, int qhTsize, int vertexTsize, int ridgeTsize, int facetTsize, int setTsize, int qhmemTsize) {
    int last_errcode= qh_ERRnone;

#if defined(_MSC_VER) && defined(_DEBUG) && defined(QHULL_CRTDBG)  /* user_r.h */
    /*_CrtSetBreakAlloc(744);*/  /* Break at memalloc {744}, or 'watch' _crtBreakAlloc */
    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_DELAY_FREE_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) );
    _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG );
    _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR );
    _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG );
    _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
    _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG );
    _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );
#endif

    if (qhullLibraryType==QHULL_NON_REENTRANT) { /* 0 */
      qh_fprintf_stderr(6257, "qh_lib_check: Incorrect qhull library called.  Caller uses non-reentrant Qhull with a static qhT.  Qhull library is reentrant.\n");
      last_errcode= 6257;
    }else if (qhullLibraryType==QHULL_QH_POINTER) { /* 1 */
      qh_fprintf_stderr(6258, "qh_lib_check: Incorrect qhull library called.  Caller uses non-reentrant Qhull with a dynamic qhT via qh_QHpointer.  Qhull library is reentrant.\n");
      last_errcode= 6258;
    }else if (qhullLibraryType != QHULL_REENTRANT) { /* 2 */
      qh_fprintf_stderr(6262, "qh_lib_check: Expecting qhullLibraryType QHULL_NON_REENTRANT(0), QHULL_QH_POINTER(1), or QHULL_REENTRANT(2).  Got %d\n", qhullLibraryType);
      last_errcode= 6262;
    }
    if (qhTsize != (int)sizeof(qhT)) {
      qh_fprintf_stderr(6249, "qh_lib_check: Incorrect qhull library called.  Size of qhT for caller is %d, but for qhull library is %d.\n", qhTsize, (int)sizeof(qhT));
      last_errcode= 6249;
    }
    if (vertexTsize != (int)sizeof(vertexT)) {
      qh_fprintf_stderr(6250, "qh_lib_check: Incorrect qhull library called.  Size of vertexT for caller is %d, but for qhull library is %d.\n", vertexTsize, (int)sizeof(vertexT));
      last_errcode= 6250;
    }
    if (ridgeTsize != (int)sizeof(ridgeT)) {
      qh_fprintf_stderr(6251, "qh_lib_check: Incorrect qhull library called.  Size of ridgeT for caller is %d, but for qhull library is %d.\n", ridgeTsize, (int)sizeof(ridgeT));
      last_errcode= 6251;
    }
    if (facetTsize != (int)sizeof(facetT)) {
      qh_fprintf_stderr(6252, "qh_lib_check: Incorrect qhull library called.  Size of facetT for caller is %d, but for qhull library is %d.\n", facetTsize, (int)sizeof(facetT));
      last_errcode= 6252;
    }
    if (setTsize && setTsize != (int)sizeof(setT)) {
      qh_fprintf_stderr(6253, "qh_lib_check: Incorrect qhull library called.  Size of setT for caller is %d, but for qhull library is %d.\n", setTsize, (int)sizeof(setT));
      last_errcode= 6253;
    }
    if (qhmemTsize && qhmemTsize != sizeof(qhmemT)) {
      qh_fprintf_stderr(6254, "qh_lib_check: Incorrect qhull library called.  Size of qhmemT for caller is %d, but for qhull library is %d.\n", qhmemTsize, sizeof(qhmemT));
      last_errcode= 6254;
    }
    if (last_errcode) {
      qh_fprintf_stderr(6259, "qhull internal error (qh_lib_check): Cannot continue due to QH%d.  '%s' is not reentrant (e.g., qhull.so) or out-of-date.  Exit with %d\n",
            last_errcode, qh_version2, last_errcode - 6200);
      qh_exit(last_errcode - 6200);  /* can not use qh_errexit(), must be less than 255 */
    }
} /* lib_check */

/*---------------------------------

  qh_option(qh, option, intVal, realVal )
    add an option description to qh.qhull_options

  notes:
    NOerrors -- qh_option can not call qh_errexit() [qh_initqhull_start2]
    will be printed with statistics ('Ts') and errors
    strlen(option) < 40
*/
void qh_option(qhT *qh, const char *option, int *i, realT *r) {
  char buf[200];
  int buflen, remainder;

  if (strlen(option) > sizeof(buf)-30-30) {
    qh_fprintf(qh, qh->ferr, 6408, "qhull internal error (qh_option): option (%d chars) has more than %d chars.  May overflow temporary buffer.  Option '%s'\n",
        (int)strlen(option), (int)sizeof(buf)-30-30, option);
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  sprintf(buf, "  %s", option);
  if (i)
    sprintf(buf+strlen(buf), " %d", *i);
  if (r)
    sprintf(buf+strlen(buf), " %2.2g", *r);
  buflen= (int)strlen(buf);   /* WARN64 */
  qh->qhull_optionlen += buflen;
  remainder= (int)(sizeof(qh->qhull_options) - strlen(qh->qhull_options)) - 1;    /* WARN64 */
  maximize_(remainder, 0);
  if (qh->qhull_optionlen >= qh_OPTIONline && remainder > 0) {
    strncat(qh->qhull_options, "\n", (unsigned int)remainder);
    --remainder;
    qh->qhull_optionlen= buflen;
  }
  if (buflen > remainder) {
    trace1((qh, qh->ferr, 1058, "qh_option: option would overflow qh.qhull_options. Truncated '%s'\n", buf));
  }
  strncat(qh->qhull_options, buf, (unsigned int)remainder);
} /* option */

/*---------------------------------

  qh_zero( qh, errfile )
    Initialize and zero Qhull's memory for qh_new_qhull()

  notes:
    Not needed in global_r.c because static variables are initialized to zero
*/
void qh_zero(qhT *qh, FILE *errfile) {
    memset((char *)qh, 0, sizeof(qhT));   /* every field is 0, FALSE, NULL */
    qh->NOerrexit= True;
    qh_meminit(qh, errfile);
} /* zero */

qhull-2020.2/src/libqhull_r/index.htm0000644060175106010010000002702113716274264015751 0ustar  bbarber



Reentrant Qhull functions, macros, and data structures




Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: Qhull files
To: GeomGlobalIoMemMergePolyQhullSetStatUser


Reentrant Qhull functions, macros, and data structures

The following sections provide an overview and index to reentrant Qhull's functions, macros, and data structures. Each section starts with an introduction. See also Calling Qhull from C programs and Calling Qhull from C++ programs.

Qhull uses the following conventions:

  • in code, global variables start with "qh "
  • in documentation, global variables start with 'qh.'
  • constants start with an upper case word
  • important globals include an '_'
  • functions, macros, and constants start with "qh_"
  • data types end in "T"
  • macros with arguments end in "_"
  • iterators are macros that use local variables
  • iterators for sets start with "FOREACH"
  • iterators for lists start with "FORALL"
  • qhull options are in single quotes (e.g., 'Pdn')
  • lists are sorted alphabetically
  • preprocessor directives on left margin for older compilers

Reentrant Qhull is nearly the same as non-reentrant Qhull. In reentrant Qhull, the qhT data structure is the first parameter to most functions. Qhull accesses this data structure with 'qh->...'. In non-reentrant Qhull, the global data structure is either a struct (qh_QHpointer==0) or a pointer (qh_QHpointer==1). The non-reentrant code looks different because this data structure is accessed via the 'qh' macro. This macro expands to 'qh_qh.' or 'qh_qh->' (resp.).

When reading code with an editor, a search for '"function' will locate the header of qh_function. A search for '* function' will locate the tail of qh_function.

A useful starting point is libqhull_r.h. It defines most of Qhull data structures and top-level functions. Search for 'PFn' to determine the corresponding constant in Qhull. Search for 'Fp' to determine the corresponding qh_PRINT... constant. Search io_r.c to learn how the print function is implemented.

If your web browser is configured for .c and .h files, the function, macro, and data type links go to the corresponding source location.

  • Internet Explorer -- OK for web access but not for file access
  • Chrome -- OK for web access but not for file access
  • Firefox -- OK for web access but not for file access
    # .htaccess on web server with NL line endings
    AddType text/html .c .h
    
  • Opera 12.10
    1. In Tools > Preferences > Advanced > Downloads
    2. Uncheck 'Hide file types opened with Opera'
    3. Quick find 'html'
    4. Select 'text/html' > Edit
    5. Add File extensions 'c,h,'
    6. Click 'OK'

Please report documentation and link errors to qhull-bug@qhull.org.

Copyright © 1997-2020 C.B. Barber


»Qhull files

This sections lists the .c and .h files for Qhull. Please refer to these files for detailed information.

Makefile, CMakeLists.txt
Makefile is preconfigured for gcc. CMakeLists.txt supports multiple platforms with CMake. Qhull includes project files for Visual Studio and Qt.
 
libqhull_r.h
Include file for the Qhull library (libqhull.so, qhull.dll, libqhullstatic.a). Data structures are documented under Poly. Global variables are documented under Global. Other data structures and variables are documented under Qhull or Geom.
 
Geom, geom_r.h, geom_r.c, geom2_r.c, random_r.c, random_r.h
Geometric routines. These routines implement mathematical functions such as Gaussian elimination and geometric routines needed for Qhull. Frequently used routines are in geom_r.c while infrequent ones are in geom2_r.c.
 
Global, global_r.c, libqhull_r.h
Global routines. Qhull uses a global data structure, qh, to store globally defined constants, lists, sets, and variables. global_r.c initializes and frees these structures.
 
Io, io_r.h, io_r.c
Input and output routines. Qhull provides a wide range of input and output options.
 
Mem, mem_r.h, mem_r.c
Memory routines. Qhull provides memory allocation and deallocation. It uses quick-fit allocation.
 
Merge, merge_r.h, merge_r.c
Merge routines. Qhull handles precision problems by merged facets or joggled input. These routines merge simplicial facets, merge non-simplicial facets, merge cycles of facets, and rename redundant vertices.
 
Poly, poly_r.h, poly_r.c, poly2_r.c, libqhull_r.h
Polyhedral routines. Qhull produces a polyhedron as a list of facets with vertices, neighbors, ridges, and geometric information. libqhull_r.h defines the main data structures. Frequently used routines are in poly_r.c while infrequent ones are in poly2_r.c.
 
Qhull, libqhull_r.c, libqhull_r.h, qhull_ra.h, unix_r.c , qconvex_r.c , qdelaun_r.c , qhalf_r.c , qvoronoi_r.c
Top-level routines. The Quickhull algorithm is implemented by libqhull_r.c. qhull_ra.h includes all header files.
 
Set, qset_r.h, qset_r.c
Set routines. Qhull implements its data structures as sets. A set is an array of pointers that is expanded as needed. This is a separate package that may be used in other applications.
 
Stat, stat_r.h, stat_r.c
Statistical routines. Qhull maintains statistics about its implementation.
 
User, user_r.h, user_r.c, user_eg_r.c, user_eg2_r.c, user_eg3_r.cpp,
User-defined routines. Qhull allows the user to configure the code with defined constants and specialized routines.


Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: Qhull files
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

qhull-2020.2/src/libqhull_r/io_r.c0000644060175106010010000042545013666241740015231 0ustar bbarber/*
  ---------------------------------

   io_r.c
   Input/Output routines of qhull application

   see qh-io_r.htm and io_r.h

   see user_r.c for qh_errprint and qh_printfacetlist

   unix_r.c calls qh_readpoints and qh_produce_output

   unix_r.c and user_r.c are the only callers of io_r.c functions
   This allows the user to avoid loading io_r.o from qhull.a

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull_r/io_r.c#12 $$Change: 2965 $
   $DateTime: 2020/06/04 15:37:41 $$Author: bbarber $
*/

#include "qhull_ra.h"

/*========= -functions in alphabetical order after qh_produce_output(qh)  =====*/

/*---------------------------------

  qh_produce_output(qh )
  qh_produce_output2(qh )
    prints out the result of qhull in desired format
    qh_produce_output2 does not call qh_prepare_output
      qh_checkpolygon is valid for qh_prepare_output
    if qh.GETarea
      computes and prints area and volume
    qh.PRINTout[] is an array of output formats

  notes:
    prints output in qh.PRINTout order
*/
void qh_produce_output(qhT *qh) {
    int tempsize= qh_setsize(qh, qh->qhmem.tempstack);

    qh_prepare_output(qh);
    qh_produce_output2(qh);
    if (qh_setsize(qh, qh->qhmem.tempstack) != tempsize) {
        qh_fprintf(qh, qh->ferr, 6206, "qhull internal error (qh_produce_output): temporary sets not empty(%d)\n",
            qh_setsize(qh, qh->qhmem.tempstack));
        qh_errexit(qh, qh_ERRqhull, NULL, NULL);
    }
} /* produce_output */


void qh_produce_output2(qhT *qh) {
  int i, tempsize= qh_setsize(qh, qh->qhmem.tempstack), d_1;

  fflush(NULL);
  if (qh->PRINTsummary)
    qh_printsummary(qh, qh->ferr);
  else if (qh->PRINTout[0] == qh_PRINTnone)
    qh_printsummary(qh, qh->fout);
  for (i=0; i < qh_PRINTEND; i++)
    qh_printfacets(qh, qh->fout, qh->PRINTout[i], qh->facet_list, NULL, !qh_ALL);
  fflush(NULL);

  qh_allstatistics(qh);
  if (qh->PRINTprecision && !qh->MERGING && (qh->JOGGLEmax > REALmax/2 || qh->RERUN))
    qh_printstats(qh, qh->ferr, qh->qhstat.precision, NULL);
  if (qh->VERIFYoutput && (zzval_(Zridge) > 0 || zzval_(Zridgemid) > 0))
    qh_printstats(qh, qh->ferr, qh->qhstat.vridges, NULL);
  if (qh->PRINTstatistics) {
    qh_printstatistics(qh, qh->ferr, "");
    qh_memstatistics(qh, qh->ferr);
    d_1= (int)sizeof(setT) + (qh->hull_dim - 1) * SETelemsize;
    qh_fprintf(qh, qh->ferr, 8040, "\
    size in bytes: merge %d ridge %d vertex %d facet %d\n\
         normal %d ridge vertices %d facet vertices or neighbors %d\n",
            (int)sizeof(mergeT), (int)sizeof(ridgeT),
            (int)sizeof(vertexT), (int)sizeof(facetT),
            qh->normal_size, d_1, d_1 + SETelemsize);
  }
  if (qh_setsize(qh, qh->qhmem.tempstack) != tempsize) {
    qh_fprintf(qh, qh->ferr, 6065, "qhull internal error (qh_produce_output2): temporary sets not empty(%d)\n",
             qh_setsize(qh, qh->qhmem.tempstack));
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
} /* produce_output2 */

/*---------------------------------

  qh_dfacet(qh, id )
    print facet by id, for debugging

*/
void qh_dfacet(qhT *qh, unsigned int id) {
  facetT *facet;

  FORALLfacets {
    if (facet->id == id) {
      qh_printfacet(qh, qh->fout, facet);
      break;
    }
  }
} /* dfacet */


/*---------------------------------

  qh_dvertex(qh, id )
    print vertex by id, for debugging
*/
void qh_dvertex(qhT *qh, unsigned int id) {
  vertexT *vertex;

  FORALLvertices {
    if (vertex->id == id) {
      qh_printvertex(qh, qh->fout, vertex);
      break;
    }
  }
} /* dvertex */


/*---------------------------------

  qh_compare_facetarea( p1, p2 )
    used by qsort() to order facets by area
*/
int qh_compare_facetarea(const void *p1, const void *p2) {
  const facetT *a= *((facetT *const*)p1), *b= *((facetT *const*)p2);

  if (!a->isarea)
    return -1;
  if (!b->isarea)
    return 1;
  if (a->f.area > b->f.area)
    return 1;
  else if (a->f.area == b->f.area)
    return 0;
  return -1;
} /* compare_facetarea */

/*---------------------------------

  qh_compare_facetvisit( p1, p2 )
    used by qsort() to order facets by visit id or id
*/
int qh_compare_facetvisit(const void *p1, const void *p2) {
  const facetT *a= *((facetT *const*)p1), *b= *((facetT *const*)p2);
  int i,j;

  if (!(i= (int)a->visitid))
    i= (int)(0 - a->id); /* sign distinguishes id from visitid */
  if (!(j= (int)b->visitid))
    j= (int)(0 - b->id);
  return(i - j);
} /* compare_facetvisit */

/*---------------------------------

  qh_compare_nummerge( p1, p2 )
    used by qsort() to order facets by number of merges

notes:
    called by qh_markkeep ('PMerge-keep')
*/
int qh_compare_nummerge(const void *p1, const void *p2) {
  const facetT *a= *((facetT *const*)p1), *b= *((facetT *const*)p2);

  return(a->nummerge - b->nummerge);
} /* compare_nummerge */

/*---------------------------------

  qh_copyfilename(qh, dest, size, source, length )
    copy filename identified by qh_skipfilename()

  notes:
    see qh_skipfilename() for syntax
*/
void qh_copyfilename(qhT *qh, char *filename, int size, const char* source, int length) {
  char c= *source;

  if (length > size + 1) {
      qh_fprintf(qh, qh->ferr, 6040, "qhull error: filename is more than %d characters, %s\n",  size-1, source);
      qh_errexit(qh, qh_ERRinput, NULL, NULL);
  }
  strncpy(filename, source, (size_t)length);
  filename[length]= '\0';
  if (c == '\'' || c == '"') {
    char *s= filename + 1;
    char *t= filename;
    while (*s) {
      if (*s == c) {
          if (s[-1] == '\\')
              t[-1]= c;
      }else
          *t++= *s;
      s++;
    }
    *t= '\0';
  }
} /* copyfilename */

/*---------------------------------

  qh_countfacets(qh, facetlist, facets, printall,
          numfacets, numsimplicial, totneighbors, numridges, numcoplanar, numtricoplanars  )
    count good facets for printing and set visitid
    if allfacets, ignores qh_skipfacet()

  notes:
    qh_printsummary and qh_countfacets must match counts

  returns:
    numfacets, numsimplicial, total neighbors, numridges, coplanars
    each facet with ->visitid indicating 1-relative position
      ->visitid==0 indicates not good

  notes
    numfacets >= numsimplicial
    if qh.NEWfacets,
      does not count visible facets (matches qh_printafacet)

  design:
    for all facets on facetlist and in facets set
      unless facet is skipped or visible (i.e., will be deleted)
        mark facet->visitid
        update counts
*/
void qh_countfacets(qhT *qh, facetT *facetlist, setT *facets, boolT printall,
    int *numfacetsp, int *numsimplicialp, int *totneighborsp, int *numridgesp, int *numcoplanarsp, int *numtricoplanarsp) {
  facetT *facet, **facetp;
  int numfacets= 0, numsimplicial= 0, numridges= 0, totneighbors= 0, numcoplanars= 0, numtricoplanars= 0;

  FORALLfacet_(facetlist) {
    if ((facet->visible && qh->NEWfacets)
    || (!printall && qh_skipfacet(qh, facet)))
      facet->visitid= 0;
    else {
      facet->visitid= (unsigned int)(++numfacets);
      totneighbors += qh_setsize(qh, facet->neighbors);
      if (facet->simplicial) {
        numsimplicial++;
        if (facet->keepcentrum && facet->tricoplanar)
          numtricoplanars++;
      }else
        numridges += qh_setsize(qh, facet->ridges);
      if (facet->coplanarset)
        numcoplanars += qh_setsize(qh, facet->coplanarset);
    }
  }

  FOREACHfacet_(facets) {
    if ((facet->visible && qh->NEWfacets)
    || (!printall && qh_skipfacet(qh, facet)))
      facet->visitid= 0;
    else {
      facet->visitid= (unsigned int)(++numfacets);
      totneighbors += qh_setsize(qh, facet->neighbors);
      if (facet->simplicial){
        numsimplicial++;
        if (facet->keepcentrum && facet->tricoplanar)
          numtricoplanars++;
      }else
        numridges += qh_setsize(qh, facet->ridges);
      if (facet->coplanarset)
        numcoplanars += qh_setsize(qh, facet->coplanarset);
    }
  }
  qh->visit_id += (unsigned int)numfacets + 1;
  *numfacetsp= numfacets;
  *numsimplicialp= numsimplicial;
  *totneighborsp= totneighbors;
  *numridgesp= numridges;
  *numcoplanarsp= numcoplanars;
  *numtricoplanarsp= numtricoplanars;
} /* countfacets */

/*---------------------------------

  qh_detvnorm(qh, vertex, vertexA, centers, offset )
    compute separating plane of the Voronoi diagram for a pair of input sites
    centers= set of facets (i.e., Voronoi vertices)
      facet->visitid= 0 iff vertex-at-infinity (i.e., unbounded)

  assumes:
    qh_ASvoronoi and qh_vertexneighbors() already set

  returns:
    norm
      a pointer into qh.gm_matrix to qh.hull_dim-1 reals
      copy the data before reusing qh.gm_matrix
    offset
      if 'QVn'
        sign adjusted so that qh.GOODvertexp is inside
      else
        sign adjusted so that vertex is inside

    qh.gm_matrix= simplex of points from centers relative to first center

  notes:
    in io_r.c so that code for 'v Tv' can be removed by removing io_r.c
    returns pointer into qh.gm_matrix to avoid tracking of temporary memory

  design:
    determine midpoint of input sites
    build points as the set of Voronoi vertices
    select a simplex from points (if necessary)
      include midpoint if the Voronoi region is unbounded
    relocate the first vertex of the simplex to the origin
    compute the normalized hyperplane through the simplex
    orient the hyperplane toward 'QVn' or 'vertex'
    if 'Tv' or 'Ts'
      if bounded
        test that hyperplane is the perpendicular bisector of the input sites
      test that Voronoi vertices not in the simplex are still on the hyperplane
    free up temporary memory
*/
pointT *qh_detvnorm(qhT *qh, vertexT *vertex, vertexT *vertexA, setT *centers, realT *offsetp) {
  facetT *facet, **facetp;
  int  i, k, pointid, pointidA, point_i, point_n;
  setT *simplex= NULL;
  pointT *point, **pointp, *point0, *midpoint, *normal, *inpoint;
  coordT *coord, *gmcoord, *normalp;
  setT *points= qh_settemp(qh, qh->TEMPsize);
  boolT nearzero= False;
  boolT unbounded= False;
  int numcenters= 0;
  int dim= qh->hull_dim - 1;
  realT dist, offset, angle, zero= 0.0;

  midpoint= qh->gm_matrix + qh->hull_dim * qh->hull_dim;  /* last row */
  for (k=0; k < dim; k++)
    midpoint[k]= (vertex->point[k] + vertexA->point[k])/2;
  FOREACHfacet_(centers) {
    numcenters++;
    if (!facet->visitid)
      unbounded= True;
    else {
      if (!facet->center)
        facet->center= qh_facetcenter(qh, facet->vertices);
      qh_setappend(qh, &points, facet->center);
    }
  }
  if (numcenters > dim) {
    simplex= qh_settemp(qh, qh->TEMPsize);
    qh_setappend(qh, &simplex, vertex->point);
    if (unbounded)
      qh_setappend(qh, &simplex, midpoint);
    qh_maxsimplex(qh, dim, points, NULL, 0, &simplex);
    qh_setdelnth(qh, simplex, 0);
  }else if (numcenters == dim) {
    if (unbounded)
      qh_setappend(qh, &points, midpoint);
    simplex= points;
  }else {
    qh_fprintf(qh, qh->ferr, 6216, "qhull internal error (qh_detvnorm): too few points(%d) to compute separating plane\n", numcenters);
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  i= 0;
  gmcoord= qh->gm_matrix;
  point0= SETfirstt_(simplex, pointT);
  FOREACHpoint_(simplex) {
    if (qh->IStracing >= 4)
      qh_printmatrix(qh, qh->ferr, "qh_detvnorm: Voronoi vertex or midpoint",
                              &point, 1, dim);
    if (point != point0) {
      qh->gm_row[i++]= gmcoord;
      coord= point0;
      for (k=dim; k--; )
        *(gmcoord++)= *point++ - *coord++;
    }
  }
  qh->gm_row[i]= gmcoord;  /* does not overlap midpoint, may be used later for qh_areasimplex */
  normal= gmcoord;
  qh_sethyperplane_gauss(qh, dim, qh->gm_row, point0, True,
                normal, &offset, &nearzero);
  /* nearzero is true for axis-parallel hyperplanes (e.g., a bounding box).  Should detect degenerate hyperplanes.  See 'Tv' check following */
  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(qh, vertex->point);
    pointidA= qh_pointid(qh, 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, qh->ferr, 4014, "qh_detvnorm: points %d %d midpoint dist %2.2g\n",
                 pointid, pointidA, dist));
      for (k=0; k < dim; k++)
        midpoint[k]= vertexA->point[k] - vertex->point[k];  /* overwrites midpoint! */
      qh_normalize(qh, midpoint, dim, False);
      angle= qh_distnorm(dim, midpoint, normal, &zero); /* qh_detangle uses dim+1 */
      if (angle < 0.0)
        angle= angle + 1.0;
      else
        angle= angle - 1.0;
      if (angle < 0.0)
        angle= -angle;
      trace4((qh, qh->ferr, 4015, "qh_detvnorm: points %d %d angle %2.2g nearzero %d\n",
                 pointid, pointidA, angle, nearzero));
      if (nearzero) {
        zzinc_(Zridge0);
        wwmax_(Wridge0max, angle);
        wwadd_(Wridge0, angle);
      }else {
        zzinc_(Zridgeok)
        wwmax_(Wridgeokmax, angle);
        wwadd_(Wridgeok, angle);
      }
    }
    if (simplex != points) {
      FOREACHpoint_i_(qh, points) {
        if (!qh_setin(simplex, point)) {
          facet= SETelemt_(centers, point_i, facetT);
          zinc_(Zdiststat);
          dist= qh_distnorm(dim, point, normal, &offset);
          if (dist < 0)
            dist= -dist;
          zzinc_(Zridge);
          wwmax_(Wridgemax, dist);
          wwadd_(Wridge, dist);
          trace4((qh, qh->ferr, 4016, "qh_detvnorm: points %d %d Voronoi vertex %d dist %2.2g\n",
                             pointid, pointidA, facet->visitid, dist));
        }
      }
    }
  }
  *offsetp= offset;
  if (simplex != points)
    qh_settempfree(qh, &simplex);
  qh_settempfree(qh, &points);
  return normal;
} /* detvnorm */

/*---------------------------------

  qh_detvridge(qh, vertexA )
    determine Voronoi ridge from 'seen' neighbors of vertexA
    include one vertex-at-infinite if an !neighbor->visitid

  returns:
    temporary set of centers (facets, i.e., Voronoi vertices)
    sorted by center id
*/
setT *qh_detvridge(qhT *qh, vertexT *vertex) {
  setT *centers= qh_settemp(qh, qh->TEMPsize);
  setT *tricenters= qh_settemp(qh, qh->TEMPsize);
  facetT *neighbor, **neighborp;
  boolT firstinf= True;

  FOREACHneighbor_(vertex) {
    if (neighbor->seen) {
      if (neighbor->visitid) {
        if (!neighbor->tricoplanar || qh_setunique(qh, &tricenters, neighbor->center))
          qh_setappend(qh, ¢ers, neighbor);
      }else if (firstinf) {
        firstinf= False;
        qh_setappend(qh, ¢ers, neighbor);
      }
    }
  }
  qsort(SETaddr_(centers, facetT), (size_t)qh_setsize(qh, centers),
             sizeof(facetT *), qh_compare_facetvisit);
  qh_settempfree(qh, &tricenters);
  return centers;
} /* detvridge */

/*---------------------------------

  qh_detvridge3(qh, atvertex, vertex )
    determine 3-d Voronoi ridge from 'seen' neighbors of atvertex and vertex
    include one vertex-at-infinite for !neighbor->visitid
    assumes all facet->seen2= True

  returns:
    temporary set of centers (facets, i.e., Voronoi vertices)
    listed in adjacency order (!oriented)
    all facet->seen2= True

  design:
    mark all neighbors of atvertex
    for each adjacent neighbor of both atvertex and vertex
      if neighbor selected
        add neighbor to set of Voronoi vertices
*/
setT *qh_detvridge3(qhT *qh, vertexT *atvertex, vertexT *vertex) {
  setT *centers= qh_settemp(qh, qh->TEMPsize);
  setT *tricenters= qh_settemp(qh, qh->TEMPsize);
  facetT *neighbor, **neighborp, *facet= NULL;
  boolT firstinf= True;

  FOREACHneighbor_(atvertex)
    neighbor->seen2= False;
  FOREACHneighbor_(vertex) {
    if (!neighbor->seen2) {
      facet= neighbor;
      break;
    }
  }
  while (facet) {
    facet->seen2= True;
    if (neighbor->seen) {
      if (facet->visitid) {
        if (!facet->tricoplanar || qh_setunique(qh, &tricenters, facet->center))
          qh_setappend(qh, ¢ers, facet);
      }else if (firstinf) {
        firstinf= False;
        qh_setappend(qh, ¢ers, facet);
      }
    }
    FOREACHneighbor_(facet) {
      if (!neighbor->seen2) {
        if (qh_setin(vertex->neighbors, neighbor))
          break;
        else
          neighbor->seen2= True;
      }
    }
    facet= neighbor;
  }
  if (qh->CHECKfrequently) {
    FOREACHneighbor_(vertex) {
      if (!neighbor->seen2) {
          qh_fprintf(qh, qh->ferr, 6217, "qhull internal error (qh_detvridge3): neighbors of vertex p%d are not connected at facet %d\n",
                 qh_pointid(qh, vertex->point), neighbor->id);
        qh_errexit(qh, qh_ERRqhull, neighbor, NULL);
      }
    }
  }
  FOREACHneighbor_(atvertex)
    neighbor->seen2= True;
  qh_settempfree(qh, &tricenters);
  return centers;
} /* detvridge3 */

/*---------------------------------

  qh_eachvoronoi(qh, fp, printvridge, vertex, visitall, innerouter, inorder )
    if visitall,
      visit all Voronoi ridges for vertex (i.e., an input site)
    else
      visit all unvisited Voronoi ridges for vertex
      all vertex->seen= False if unvisited
    assumes
      all facet->seen= False
      all facet->seen2= True (for qh_detvridge3)
      all facet->visitid == 0 if vertex_at_infinity
                         == index of Voronoi vertex
                         >= qh.num_facets if ignored
    innerouter:
      qh_RIDGEall--  both inner (bounded) and outer(unbounded) ridges
      qh_RIDGEinner- only inner
      qh_RIDGEouter- only outer

    if inorder
      orders vertices for 3-d Voronoi diagrams

  returns:
    number of visited ridges (does not include previously visited ridges)

    if printvridge,
      calls printvridge( fp, vertex, vertexA, centers)
        fp== any pointer (assumes FILE*)
             fp may be NULL for QhullQh::qh_fprintf which calls appendQhullMessage
        vertex,vertexA= pair of input sites that define a Voronoi ridge
        centers= set of facets (i.e., Voronoi vertices)
                 ->visitid == index or 0 if vertex_at_infinity
                 ordered for 3-d Voronoi diagram
  notes:
    uses qh.vertex_visit

  see:
    qh_eachvoronoi_all()

  design:
    mark selected neighbors of atvertex
    for each selected neighbor (either Voronoi vertex or vertex-at-infinity)
      for each unvisited vertex
        if atvertex and vertex share more than d-1 neighbors
          bump totalcount
          if printvridge defined
            build the set of shared neighbors (i.e., Voronoi vertices)
            call printvridge
*/
int qh_eachvoronoi(qhT *qh, FILE *fp, printvridgeT printvridge, vertexT *atvertex, boolT visitall, qh_RIDGE innerouter, boolT inorder) {
  boolT unbounded;
  int count;
  facetT *neighbor, **neighborp, *neighborA, **neighborAp;
  setT *centers;
  setT *tricenters= qh_settemp(qh, qh->TEMPsize);

  vertexT *vertex, **vertexp;
  boolT firstinf;
  unsigned int numfacets= (unsigned int)qh->num_facets;
  int totridges= 0;

  qh->vertex_visit++;
  atvertex->seen= True;
  if (visitall) {
    FORALLvertices
      vertex->seen= False;
  }
  FOREACHneighbor_(atvertex) {
    if (neighbor->visitid < numfacets)
      neighbor->seen= True;
  }
  FOREACHneighbor_(atvertex) {
    if (neighbor->seen) {
      FOREACHvertex_(neighbor->vertices) {
        if (vertex->visitid != qh->vertex_visit && !vertex->seen) {
          vertex->visitid= qh->vertex_visit;
          count= 0;
          firstinf= True;
          qh_settruncate(qh, tricenters, 0);
          FOREACHneighborA_(vertex) {
            if (neighborA->seen) {
              if (neighborA->visitid) {
                if (!neighborA->tricoplanar || qh_setunique(qh, &tricenters, neighborA->center))
                  count++;
              }else if (firstinf) {
                count++;
                firstinf= False;
              }
            }
          }
          if (count >= qh->hull_dim - 1) {  /* e.g., 3 for 3-d Voronoi */
            if (firstinf) {
              if (innerouter == qh_RIDGEouter)
                continue;
              unbounded= False;
            }else {
              if (innerouter == qh_RIDGEinner)
                continue;
              unbounded= True;
            }
            totridges++;
            trace4((qh, qh->ferr, 4017, "qh_eachvoronoi: Voronoi ridge of %d vertices between sites %d and %d\n",
                  count, qh_pointid(qh, atvertex->point), qh_pointid(qh, vertex->point)));
            if (printvridge) {
              if (inorder && qh->hull_dim == 3+1) /* 3-d Voronoi diagram */
                centers= qh_detvridge3(qh, atvertex, vertex);
              else
                centers= qh_detvridge(qh, vertex);
              (*printvridge)(qh, fp, atvertex, vertex, centers, unbounded);
              qh_settempfree(qh, ¢ers);
            }
          }
        }
      }
    }
  }
  FOREACHneighbor_(atvertex)
    neighbor->seen= False;
  qh_settempfree(qh, &tricenters);
  return totridges;
} /* eachvoronoi */


/*---------------------------------

  qh_eachvoronoi_all(qh, fp, printvridge, isUpper, innerouter, inorder )
    visit all Voronoi ridges

    innerouter:
      see qh_eachvoronoi()

    if inorder
      orders vertices for 3-d Voronoi diagrams

  returns
    total number of ridges

    if isUpper == facet->upperdelaunay  (i.e., a Vornoi vertex)
      facet->visitid= Voronoi vertex index(same as 'o' format)
    else
      facet->visitid= 0

    if printvridge,
      calls printvridge( fp, vertex, vertexA, centers)
      [see qh_eachvoronoi]

  notes:
    Not used for qhull.exe
    same effect as qh_printvdiagram but ridges not sorted by point id
*/
int qh_eachvoronoi_all(qhT *qh, FILE *fp, printvridgeT printvridge, boolT isUpper, qh_RIDGE innerouter, boolT inorder) {
  facetT *facet;
  vertexT *vertex;
  int numcenters= 1;  /* vertex 0 is vertex-at-infinity */
  int totridges= 0;

  qh_clearcenters(qh, qh_ASvoronoi);
  qh_vertexneighbors(qh);
  maximize_(qh->visit_id, (unsigned int)qh->num_facets);
  FORALLfacets {
    facet->visitid= 0;
    facet->seen= False;
    facet->seen2= True;
  }
  FORALLfacets {
    if (facet->upperdelaunay == isUpper)
      facet->visitid= (unsigned int)(numcenters++);
  }
  FORALLvertices
    vertex->seen= False;
  FORALLvertices {
    if (qh->GOODvertex > 0 && qh_pointid(qh, vertex->point)+1 != qh->GOODvertex)
      continue;
    totridges += qh_eachvoronoi(qh, fp, printvridge, vertex,
                   !qh_ALL, innerouter, inorder);
  }
  return totridges;
} /* eachvoronoi_all */

/*---------------------------------

  qh_facet2point(qh, facet, point0, point1, mindist )
    return two projected temporary vertices for a 2-d facet
    may be non-simplicial

  returns:
    point0 and point1 oriented and projected to the facet
    returns mindist (maximum distance below plane)
*/
void qh_facet2point(qhT *qh, facetT *facet, pointT **point0, pointT **point1, realT *mindist) {
  vertexT *vertex0, *vertex1;
  realT dist;

  if (facet->toporient ^ qh_ORIENTclock) {
    vertex0= SETfirstt_(facet->vertices, vertexT);
    vertex1= SETsecondt_(facet->vertices, vertexT);
  }else {
    vertex1= SETfirstt_(facet->vertices, vertexT);
    vertex0= SETsecondt_(facet->vertices, vertexT);
  }
  zadd_(Zdistio, 2);
  qh_distplane(qh, vertex0->point, facet, &dist);
  *mindist= dist;
  *point0= qh_projectpoint(qh, vertex0->point, facet, dist);
  qh_distplane(qh, vertex1->point, facet, &dist);
  minimize_(*mindist, dist);
  *point1= qh_projectpoint(qh, vertex1->point, facet, dist);
} /* facet2point */


/*---------------------------------

  qh_facetvertices(qh, facetlist, facets, allfacets )
    returns temporary set of vertices in a set and/or list of facets
    if allfacets, ignores qh_skipfacet()

  returns:
    vertices with qh.vertex_visit

  notes:
    optimized for allfacets of facet_list

  design:
    if allfacets of facet_list
      create vertex set from vertex_list
    else
      for each selected facet in facets or facetlist
        append unvisited vertices to vertex set
*/
setT *qh_facetvertices(qhT *qh, facetT *facetlist, setT *facets, boolT allfacets) {
  setT *vertices;
  facetT *facet, **facetp;
  vertexT *vertex, **vertexp;

  qh->vertex_visit++;
  if (facetlist == qh->facet_list && allfacets && !facets) {
    vertices= qh_settemp(qh, qh->num_vertices);
    FORALLvertices {
      vertex->visitid= qh->vertex_visit;
      qh_setappend(qh, &vertices, vertex);
    }
  }else {
    vertices= qh_settemp(qh, qh->TEMPsize);
    FORALLfacet_(facetlist) {
      if (!allfacets && qh_skipfacet(qh, facet))
        continue;
      FOREACHvertex_(facet->vertices) {
        if (vertex->visitid != qh->vertex_visit) {
          vertex->visitid= qh->vertex_visit;
          qh_setappend(qh, &vertices, vertex);
        }
      }
    }
  }
  FOREACHfacet_(facets) {
    if (!allfacets && qh_skipfacet(qh, facet))
      continue;
    FOREACHvertex_(facet->vertices) {
      if (vertex->visitid != qh->vertex_visit) {
        vertex->visitid= qh->vertex_visit;
        qh_setappend(qh, &vertices, vertex);
      }
    }
  }
  return vertices;
} /* facetvertices */

/*---------------------------------

  qh_geomplanes(qh, facet, outerplane, innerplane )
    return outer and inner planes for Geomview
    qh.PRINTradius is size of vertices and points (includes qh.JOGGLEmax)

  notes:
    assume precise calculations in io_r.c with roundoff covered by qh_GEOMepsilon
*/
void qh_geomplanes(qhT *qh, facetT *facet, realT *outerplane, realT *innerplane) {
  realT radius;

  if (qh->MERGING || qh->JOGGLEmax < REALmax/2) {
    qh_outerinner(qh, facet, outerplane, innerplane);
    radius= qh->PRINTradius;
    if (qh->JOGGLEmax < REALmax/2)
      radius -= qh->JOGGLEmax * sqrt((realT)qh->hull_dim);  /* already accounted for in qh_outerinner() */
    *outerplane += radius;
    *innerplane -= radius;
    if (qh->PRINTcoplanar || qh->PRINTspheres) {
      *outerplane += qh->MAXabs_coord * qh_GEOMepsilon;
      *innerplane -= qh->MAXabs_coord * qh_GEOMepsilon;
    }
  }else
    *innerplane= *outerplane= 0;
} /* geomplanes */


/*---------------------------------

  qh_markkeep(qh, facetlist )
    restrict good facets for qh.KEEParea, qh.KEEPmerge, and qh.KEEPminArea
    ignores visible facets (!part of convex hull)

  returns:
    may clear facet->good
    recomputes qh.num_good

  notes:
    only called by qh_prepare_output after qh_findgood_all
    does not throw errors except memory/corruption of qset_r.c

  design:
    get set of good facets
    if qh.KEEParea
      sort facets by area
      clear facet->good for all but n largest facets
    if qh.KEEPmerge
      sort facets by merge count
      clear facet->good for all but n most merged facets
    if qh.KEEPminarea
      clear facet->good if area too small
    update qh.num_good
*/
void qh_markkeep(qhT *qh, facetT *facetlist) {
  facetT *facet, **facetp;
  setT *facets= qh_settemp(qh, qh->num_facets);
  int size, count;

  trace2((qh, qh->ferr, 2006, "qh_markkeep: only keep %d largest and/or %d most merged facets and/or min area %.2g\n",
          qh->KEEParea, qh->KEEPmerge, qh->KEEPminArea));
  FORALLfacet_(facetlist) {
    if (!facet->visible && facet->good)
      qh_setappend(qh, &facets, facet);
  }
  size= qh_setsize(qh, facets);
  if (qh->KEEParea) {
    qsort(SETaddr_(facets, facetT), (size_t)size,
             sizeof(facetT *), qh_compare_facetarea);
    if ((count= size - qh->KEEParea) > 0) {
      FOREACHfacet_(facets) {
        facet->good= False;
        if (--count == 0)
          break;
      }
    }
  }
  if (qh->KEEPmerge) {
    qsort(SETaddr_(facets, facetT), (size_t)size,
             sizeof(facetT *), qh_compare_nummerge);
    if ((count= size - qh->KEEPmerge) > 0) {
      FOREACHfacet_(facets) {
        facet->good= False;
        if (--count == 0)
          break;
      }
    }
  }
  if (qh->KEEPminArea < REALmax/2) {
    FOREACHfacet_(facets) {
      if (!facet->isarea || facet->f.area < qh->KEEPminArea)
        facet->good= False;
    }
  }
  qh_settempfree(qh, &facets);
  count= 0;
  FORALLfacet_(facetlist) {
    if (facet->good)
      count++;
  }
  qh->num_good= count;
} /* markkeep */


/*---------------------------------

  qh_markvoronoi(qh, facetlist, facets, printall, isLower, numcenters )
    mark voronoi vertices for printing by site pairs

  returns:
    temporary set of vertices indexed by pointid
    isLower set if printing lower hull (i.e., at least one facet is lower hull)
    numcenters= total number of Voronoi vertices
    bumps qh.printoutnum for vertex-at-infinity
    clears all facet->seen and sets facet->seen2

    if selected
      facet->visitid= Voronoi vertex id
    else if upper hull (or 'Qu' and lower hull)
      facet->visitid= 0
    else
      facet->visitid >= qh->num_facets

  notes:
    ignores qh.ATinfinity, if defined
*/
setT *qh_markvoronoi(qhT *qh, facetT *facetlist, setT *facets, boolT printall, boolT *isLowerp, int *numcentersp) {
  int numcenters=0;
  facetT *facet, **facetp;
  setT *vertices;
  boolT isLower= False;

  qh->printoutnum++;
  qh_clearcenters(qh, qh_ASvoronoi);  /* in case, qh_printvdiagram2 called by user */
  qh_vertexneighbors(qh);
  vertices= qh_pointvertex(qh);
  if (qh->ATinfinity)
    SETelem_(vertices, qh->num_points-1)= NULL;
  qh->visit_id++;
  maximize_(qh->visit_id, (unsigned int)qh->num_facets);
  FORALLfacet_(facetlist) {
    if (printall || !qh_skipfacet(qh, facet)) {
      if (!facet->upperdelaunay) {
        isLower= True;
        break;
      }
    }
  }
  FOREACHfacet_(facets) {
    if (printall || !qh_skipfacet(qh, facet)) {
      if (!facet->upperdelaunay) {
        isLower= True;
        break;
      }
    }
  }
  FORALLfacets {
    if (facet->normal && (facet->upperdelaunay == isLower))
      facet->visitid= 0;  /* facetlist or facets may overwrite */
    else
      facet->visitid= qh->visit_id;
    facet->seen= False;
    facet->seen2= True;
  }
  numcenters++;  /* qh_INFINITE */
  FORALLfacet_(facetlist) {
    if (printall || !qh_skipfacet(qh, facet))
      facet->visitid= (unsigned int)(numcenters++);
  }
  FOREACHfacet_(facets) {
    if (printall || !qh_skipfacet(qh, facet))
      facet->visitid= (unsigned int)(numcenters++);
  }
  *isLowerp= isLower;
  *numcentersp= numcenters;
  trace2((qh, qh->ferr, 2007, "qh_markvoronoi: isLower %d numcenters %d\n", isLower, numcenters));
  return vertices;
} /* markvoronoi */

/*---------------------------------

  qh_order_vertexneighbors(qh, vertex )
    order facet neighbors of vertex by 2-d (orientation), 3-d (adjacency), or n-d (f.visitid,id)

  notes:
    error if qh_vertexneighbors not called beforehand
    only 2-d orients the neighbors
    for 4-d and higher
      set or clear f.visitid for qh_compare_facetvisit
      for example, use qh_markvoronoi (e.g., qh_printvornoi) or qh_countfacets (e.g., qh_printvneighbors)

  design (2-d):
    see qh_printextremes_2d
  design (3-d):
    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
  design (n-d):
    qsort by f.visitid, or f.facetid (qh_compare_facetvisit)
    facet_id is negated (sorted before visit_id facets)
*/
void qh_order_vertexneighbors(qhT *qh, vertexT *vertex) {
  setT *newset;
  facetT *facet, *facetA, *facetB, *neighbor, **neighborp;
  vertexT *vertexA;
  int numneighbors;

  trace4((qh, qh->ferr, 4018, "qh_order_vertexneighbors: order facet neighbors of v%d by 2-d (orientation), 3-d (adjacency), or n-d (f.visitid,id)\n", vertex->id));
  if (!qh->VERTEXneighbors) {
    qh_fprintf(qh, qh->ferr, 6428, "qhull internal error (qh_order_vertexneighbors): call qh_vertexneighbors before calling qh_order_vertexneighbors\n");
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  if (qh->hull_dim == 2) {
    facetA= SETfirstt_(vertex->neighbors, facetT);
    if (facetA->toporient ^ qh_ORIENTclock)
      vertexA= SETfirstt_(facetA->vertices, vertexT);
    else
      vertexA= SETsecondt_(facetA->vertices, vertexT);
    if (vertexA!=vertex) {
      facetB= SETsecondt_(vertex->neighbors, facetT);
      SETfirst_(vertex->neighbors)= facetB;
      SETsecond_(vertex->neighbors)= facetA;
    }
  }else if (qh->hull_dim == 3) {
    newset= qh_settemp(qh, qh_setsize(qh, vertex->neighbors));
    facet= (facetT *)qh_setdellast(vertex->neighbors);
    qh_setappend(qh, &newset, facet);
    while (qh_setsize(qh, vertex->neighbors)) {
      FOREACHneighbor_(vertex) {
        if (qh_setin(facet->neighbors, neighbor)) {
          qh_setdel(vertex->neighbors, neighbor);
          qh_setappend(qh, &newset, neighbor);
          facet= neighbor;
          break;
        }
      }
      if (!neighbor) {
        qh_fprintf(qh, qh->ferr, 6066, "qhull internal error (qh_order_vertexneighbors): no neighbor of v%d for f%d\n",
          vertex->id, facet->id);
        qh_errexit(qh, qh_ERRqhull, facet, NULL);
      }
    }
    qh_setfree(qh, &vertex->neighbors);
    qh_settemppop(qh);
    vertex->neighbors= newset;
  }else { /* qh.hull_dim >= 4 */
    numneighbors= qh_setsize(qh, vertex->neighbors);
    qsort(SETaddr_(vertex->neighbors, facetT), (size_t)numneighbors,
        sizeof(facetT *), qh_compare_facetvisit);
  }
} /* order_vertexneighbors */

/*---------------------------------

  qh_prepare_output(qh )
    prepare for qh_produce_output2(qh) according to
      qh.KEEPminArea, KEEParea, KEEPmerge, GOODvertex, GOODthreshold, GOODpoint, ONLYgood, SPLITthresholds
    does not reset facet->good

  notes
    called by qh_produce_output, qh_new_qhull, Qhull.outputQhull
    except for PRINTstatistics, no-op if previously called with same options
*/
void qh_prepare_output(qhT *qh) {
  if (qh->VORONOI) {
    qh_clearcenters(qh, qh_ASvoronoi);  /* must be before qh_triangulate */
    qh_vertexneighbors(qh);
  }
  if (qh->TRIangulate && !qh->hasTriangulation) {
    qh_triangulate(qh);
    if (qh->VERIFYoutput && !qh->CHECKfrequently)
      qh_checkpolygon(qh, qh->facet_list);
  }
  qh_findgood_all(qh, qh->facet_list);
  if (qh->GETarea)
    qh_getarea(qh, qh->facet_list);
  if (qh->KEEParea || qh->KEEPmerge || qh->KEEPminArea < REALmax/2)
    qh_markkeep(qh, qh->facet_list);
  if (qh->PRINTstatistics)
    qh_collectstatistics(qh);
}

/*---------------------------------

  qh_printafacet(qh, fp, format, facet, printall )
    print facet to fp in given output format (see qh.PRINTout)

  returns:
    nop if !printall and qh_skipfacet()
    nop if visible facet and NEWfacets and format != PRINTfacets
    must match qh_countfacets

  notes
    preserves qh.visit_id
    facet->normal may be null if PREmerge/MERGEexact and STOPcone before merge

  see
    qh_printbegin() and qh_printend()

  design:
    test for printing facet
    call appropriate routine for format
    or output results directly
*/
void qh_printafacet(qhT *qh, FILE *fp, qh_PRINT format, facetT *facet, boolT printall) {
  realT color[4], offset, dist, outerplane, innerplane;
  boolT zerodiv;
  coordT *point, *normp, *coordp, **pointp, *feasiblep;
  int k;
  vertexT *vertex, **vertexp;
  facetT *neighbor, **neighborp;

  if (!printall && qh_skipfacet(qh, facet))
    return;
  if (facet->visible && qh->NEWfacets && format != qh_PRINTfacets)
    return;
  qh->printoutnum++;
  switch (format) {
  case qh_PRINTarea:
    if (facet->isarea) {
      qh_fprintf(qh, fp, 9009, qh_REAL_1, facet->f.area);
      qh_fprintf(qh, fp, 9010, "\n");
    }else
      qh_fprintf(qh, fp, 9011, "0\n");
    break;
  case qh_PRINTcoplanars:
    qh_fprintf(qh, fp, 9012, "%d", qh_setsize(qh, facet->coplanarset));
    FOREACHpoint_(facet->coplanarset)
      qh_fprintf(qh, fp, 9013, " %d", qh_pointid(qh, point));
    qh_fprintf(qh, fp, 9014, "\n");
    break;
  case qh_PRINTcentrums:
    qh_printcenter(qh, fp, format, NULL, facet);
    break;
  case qh_PRINTfacets:
    qh_printfacet(qh, fp, facet);
    break;
  case qh_PRINTfacets_xridge:
    qh_printfacetheader(qh, fp, facet);
    break;
  case qh_PRINTgeom:  /* either 2 , 3, or 4-d by qh_printbegin */
    if (!facet->normal)
      break;
    for (k=qh->hull_dim; k--; ) {
      color[k]= (facet->normal[k]+1.0)/2.0;
      maximize_(color[k], -1.0);
      minimize_(color[k], +1.0);
    }
    qh_projectdim3(qh, color, color);
    if (qh->PRINTdim != qh->hull_dim)
      qh_normalize2(qh, color, 3, True, NULL, NULL);
    if (qh->hull_dim <= 2)
      qh_printfacet2geom(qh, fp, facet, color);
    else if (qh->hull_dim == 3) {
      if (facet->simplicial)
        qh_printfacet3geom_simplicial(qh, fp, facet, color);
      else
        qh_printfacet3geom_nonsimplicial(qh, fp, facet, color);
    }else {
      if (facet->simplicial)
        qh_printfacet4geom_simplicial(qh, fp, facet, color);
      else
        qh_printfacet4geom_nonsimplicial(qh, fp, facet, color);
    }
    break;
  case qh_PRINTids:
    qh_fprintf(qh, fp, 9015, "%d\n", facet->id);
    break;
  case qh_PRINTincidences:
  case qh_PRINToff:
  case qh_PRINTtriangles:
    if (qh->hull_dim == 3 && format != qh_PRINTtriangles)
      qh_printfacet3vertex(qh, fp, facet, format);
    else if (facet->simplicial || qh->hull_dim == 2 || format == qh_PRINToff)
      qh_printfacetNvertex_simplicial(qh, fp, facet, format);
    else
      qh_printfacetNvertex_nonsimplicial(qh, fp, facet, qh->printoutvar++, format);
    break;
  case qh_PRINTinner:
    qh_outerinner(qh, facet, NULL, &innerplane);
    offset= facet->offset - innerplane;
    goto LABELprintnorm;
    break; /* prevent warning */
  case qh_PRINTmerges:
    qh_fprintf(qh, fp, 9016, "%d\n", facet->nummerge);
    break;
  case qh_PRINTnormals:
    offset= facet->offset;
    goto LABELprintnorm;
    break; /* prevent warning */
  case qh_PRINTouter:
    qh_outerinner(qh, facet, &outerplane, NULL);
    offset= facet->offset - outerplane;
  LABELprintnorm:
    if (!facet->normal) {
      qh_fprintf(qh, fp, 9017, "no normal for facet f%d\n", facet->id);
      break;
    }
    if (qh->CDDoutput) {
      qh_fprintf(qh, fp, 9018, qh_REAL_1, -offset);
      for (k=0; k < qh->hull_dim; k++)
        qh_fprintf(qh, fp, 9019, qh_REAL_1, -facet->normal[k]);
    }else {
      for (k=0; k < qh->hull_dim; k++)
        qh_fprintf(qh, fp, 9020, qh_REAL_1, facet->normal[k]);
      qh_fprintf(qh, fp, 9021, qh_REAL_1, offset);
    }
    qh_fprintf(qh, fp, 9022, "\n");
    break;
  case qh_PRINTmathematica:  /* either 2 or 3-d by qh_printbegin */
  case qh_PRINTmaple:
    if (qh->hull_dim == 2)
      qh_printfacet2math(qh, fp, facet, format, qh->printoutvar++);
    else
      qh_printfacet3math(qh, fp, facet, format, qh->printoutvar++);
    break;
  case qh_PRINTneighbors:
    qh_fprintf(qh, fp, 9023, "%d", qh_setsize(qh, facet->neighbors));
    FOREACHneighbor_(facet)
      qh_fprintf(qh, fp, 9024, " %d",
               neighbor->visitid ? neighbor->visitid - 1: 0 - neighbor->id);
    qh_fprintf(qh, fp, 9025, "\n");
    break;
  case qh_PRINTpointintersect:
    if (!qh->feasible_point) {
      qh_fprintf(qh, qh->ferr, 6067, "qhull input error (qh_printafacet): option 'Fp' needs qh->feasible_point\n");
      qh_errexit(qh, qh_ERRinput, NULL, NULL);
    }
    if (facet->offset > 0)
      goto LABELprintinfinite;
    point= coordp= (coordT *)qh_memalloc(qh, qh->normal_size);
    normp= facet->normal;
    feasiblep= qh->feasible_point;
    if (facet->offset < -qh->MINdenom) {
      for (k=qh->hull_dim; k--; )
        *(coordp++)= (*(normp++) / - facet->offset) + *(feasiblep++);
    }else {
      for (k=qh->hull_dim; k--; ) {
        *(coordp++)= qh_divzero(*(normp++), facet->offset, qh->MINdenom_1,
                                 &zerodiv) + *(feasiblep++);
        if (zerodiv) {
          qh_memfree(qh, point, qh->normal_size);
          goto LABELprintinfinite;
        }
      }
    }
    qh_printpoint(qh, fp, NULL, point);
    qh_memfree(qh, point, qh->normal_size);
    break;
  LABELprintinfinite:
    for (k=qh->hull_dim; k--; )
      qh_fprintf(qh, fp, 9026, qh_REAL_1, qh_INFINITE);
    qh_fprintf(qh, fp, 9027, "\n");
    break;
  case qh_PRINTpointnearest:
    FOREACHpoint_(facet->coplanarset) {
      int id, id2;
      vertex= qh_nearvertex(qh, facet, point, &dist);
      id= qh_pointid(qh, vertex->point);
      id2= qh_pointid(qh, point);
      qh_fprintf(qh, fp, 9028, "%d %d %d " qh_REAL_1 "\n", id, id2, facet->id, dist);
    }
    break;
  case qh_PRINTpoints:  /* VORONOI only by qh_printbegin */
    if (qh->CDDoutput)
      qh_fprintf(qh, fp, 9029, "1 ");
    qh_printcenter(qh, fp, format, NULL, facet);
    break;
  case qh_PRINTvertices:
    qh_fprintf(qh, fp, 9030, "%d", qh_setsize(qh, facet->vertices));
    FOREACHvertex_(facet->vertices)
      qh_fprintf(qh, fp, 9031, " %d", qh_pointid(qh, vertex->point));
    qh_fprintf(qh, fp, 9032, "\n");
    break;
  default:
    break;
  }
} /* printafacet */

/*---------------------------------

  qh_printbegin(qh )
    prints header for all output formats

  returns:
    checks for valid format

  notes:
    uses qh.visit_id for 3/4off
    changes qh.interior_point if printing centrums
    qh_countfacets clears facet->visitid for non-good facets

  see
    qh_printend() and qh_printafacet()

  design:
    count facets and related statistics
    print header for format
*/
void qh_printbegin(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {
  int numfacets, numsimplicial, numridges, totneighbors, numcoplanars, numtricoplanars;
  int i, num;
  facetT *facet, **facetp;
  vertexT *vertex, **vertexp;
  setT *vertices;
  pointT *point, **pointp, *pointtemp;

  qh->printoutnum= 0;
  qh_countfacets(qh, facetlist, facets, printall, &numfacets, &numsimplicial,
      &totneighbors, &numridges, &numcoplanars, &numtricoplanars);
  switch (format) {
  case qh_PRINTnone:
    break;
  case qh_PRINTarea:
    qh_fprintf(qh, fp, 9033, "%d\n", numfacets);
    break;
  case qh_PRINTcoplanars:
    qh_fprintf(qh, fp, 9034, "%d\n", numfacets);
    break;
  case qh_PRINTcentrums:
    if (qh->CENTERtype == qh_ASnone)
      qh_clearcenters(qh, qh_AScentrum);
    qh_fprintf(qh, fp, 9035, "%d\n%d\n", qh->hull_dim, numfacets);
    break;
  case qh_PRINTfacets:
  case qh_PRINTfacets_xridge:
    if (facetlist)
      qh_printvertexlist(qh, fp, "Vertices and facets:\n", facetlist, facets, printall);
    break;
  case qh_PRINTgeom:
    if (qh->hull_dim > 4)  /* qh_initqhull_globals also checks */
      goto LABELnoformat;
    if (qh->VORONOI && qh->hull_dim > 3)  /* PRINTdim == DROPdim == hull_dim-1 */
      goto LABELnoformat;
    if (qh->hull_dim == 2 && (qh->PRINTridges || qh->DOintersections))
      qh_fprintf(qh, qh->ferr, 7049, "qhull warning: output for ridges and intersections not implemented in 2-d\n");
    if (qh->hull_dim == 4 && (qh->PRINTinner || qh->PRINTouter ||
                             (qh->PRINTdim == 4 && qh->PRINTcentrums)))
      qh_fprintf(qh, qh->ferr, 7050, "qhull warning: output for outer/inner planes and centrums not implemented in 4-d\n");
    if (qh->PRINTdim == 4 && (qh->PRINTspheres))
      qh_fprintf(qh, qh->ferr, 7051, "qhull warning: output for vertices not implemented in 4-d\n");
    if (qh->PRINTdim == 4 && qh->DOintersections && qh->PRINTnoplanes)
      qh_fprintf(qh, qh->ferr, 7052, "qhull warning: 'Gnh' generates no output in 4-d\n");
    if (qh->PRINTdim == 2) {
      qh_fprintf(qh, fp, 9036, "{appearance {linewidth 3} LIST # %s | %s\n",
              qh->rbox_command, qh->qhull_command);
    }else if (qh->PRINTdim == 3) {
      qh_fprintf(qh, fp, 9037, "{appearance {+edge -evert linewidth 2} LIST # %s | %s\n",
              qh->rbox_command, qh->qhull_command);
    }else if (qh->PRINTdim == 4) {
      qh->visit_id++;
      num= 0;
      FORALLfacet_(facetlist)    /* get number of ridges to be printed */
        qh_printend4geom(qh, NULL, facet, &num, printall);
      FOREACHfacet_(facets)
        qh_printend4geom(qh, NULL, facet, &num, printall);
      qh->ridgeoutnum= num;
      qh->printoutvar= 0;  /* counts number of ridges in output */
      qh_fprintf(qh, fp, 9038, "LIST # %s | %s\n", qh->rbox_command, qh->qhull_command);
    }

    if (qh->PRINTdots) {
      qh->printoutnum++;
      num= qh->num_points + qh_setsize(qh, qh->other_points);
      if (qh->DELAUNAY && qh->ATinfinity)
        num--;
      if (qh->PRINTdim == 4)
        qh_fprintf(qh, fp, 9039, "4VECT %d %d 1\n", num, num);
      else
        qh_fprintf(qh, fp, 9040, "VECT %d %d 1\n", num, num);

      for (i=num; i--; ) {
        if (i % 20 == 0)
          qh_fprintf(qh, fp, 9041, "\n");
        qh_fprintf(qh, fp, 9042, "1 ");
      }
      qh_fprintf(qh, fp, 9043, "# 1 point per line\n1 ");
      for (i=num-1; i--; ) { /* num at least 3 for D2 */
        if (i % 20 == 0)
          qh_fprintf(qh, fp, 9044, "\n");
        qh_fprintf(qh, fp, 9045, "0 ");
      }
      qh_fprintf(qh, fp, 9046, "# 1 color for all\n");
      FORALLpoints {
        if (!qh->DELAUNAY || !qh->ATinfinity || qh_pointid(qh, point) != qh->num_points-1) {
          if (qh->PRINTdim == 4)
            qh_printpoint(qh, fp, NULL, point);
            else
              qh_printpoint3(qh, fp, point);
        }
      }
      FOREACHpoint_(qh->other_points) {
        if (qh->PRINTdim == 4)
          qh_printpoint(qh, fp, NULL, point);
        else
          qh_printpoint3(qh, fp, point);
      }
      qh_fprintf(qh, fp, 9047, "0 1 1 1  # color of points\n");
    }

    if (qh->PRINTdim == 4  && !qh->PRINTnoplanes)
      /* 4dview loads up multiple 4OFF objects slowly */
      qh_fprintf(qh, fp, 9048, "4OFF %d %d 1\n", 3*qh->ridgeoutnum, qh->ridgeoutnum);
    qh->PRINTcradius= 2 * qh->DISTround;  /* include test DISTround */
    if (qh->PREmerge) {
      maximize_(qh->PRINTcradius, qh->premerge_centrum + qh->DISTround);
    }else if (qh->POSTmerge)
      maximize_(qh->PRINTcradius, qh->postmerge_centrum + qh->DISTround);
    qh->PRINTradius= qh->PRINTcradius;
    if (qh->PRINTspheres + qh->PRINTcoplanar)
      maximize_(qh->PRINTradius, qh->MAXabs_coord * qh_MINradius);
    if (qh->premerge_cos < REALmax/2) {
      maximize_(qh->PRINTradius, (1- qh->premerge_cos) * qh->MAXabs_coord);
    }else if (!qh->PREmerge && qh->POSTmerge && qh->postmerge_cos < REALmax/2) {
      maximize_(qh->PRINTradius, (1- qh->postmerge_cos) * qh->MAXabs_coord);
    }
    maximize_(qh->PRINTradius, qh->MINvisible);
    if (qh->JOGGLEmax < REALmax/2)
      qh->PRINTradius += qh->JOGGLEmax * sqrt((realT)qh->hull_dim);
    if (qh->PRINTdim != 4 &&
        (qh->PRINTcoplanar || qh->PRINTspheres || qh->PRINTcentrums)) {
      vertices= qh_facetvertices(qh, facetlist, facets, printall);
      if (qh->PRINTspheres && qh->PRINTdim <= 3)
        qh_printspheres(qh, fp, vertices, qh->PRINTradius);
      if (qh->PRINTcoplanar || qh->PRINTcentrums) {
        qh->firstcentrum= True;
        if (qh->PRINTcoplanar&& !qh->PRINTspheres) {
          FOREACHvertex_(vertices)
            qh_printpointvect2(qh, fp, vertex->point, NULL, qh->interior_point, qh->PRINTradius);
        }
        FORALLfacet_(facetlist) {
          if (!printall && qh_skipfacet(qh, facet))
            continue;
          if (!facet->normal)
            continue;
          if (qh->PRINTcentrums && qh->PRINTdim <= 3)
            qh_printcentrum(qh, fp, facet, qh->PRINTcradius);
          if (!qh->PRINTcoplanar)
            continue;
          FOREACHpoint_(facet->coplanarset)
            qh_printpointvect2(qh, fp, point, facet->normal, NULL, qh->PRINTradius);
          FOREACHpoint_(facet->outsideset)
            qh_printpointvect2(qh, fp, point, facet->normal, NULL, qh->PRINTradius);
        }
        FOREACHfacet_(facets) {
          if (!printall && qh_skipfacet(qh, facet))
            continue;
          if (!facet->normal)
            continue;
          if (qh->PRINTcentrums && qh->PRINTdim <= 3)
            qh_printcentrum(qh, fp, facet, qh->PRINTcradius);
          if (!qh->PRINTcoplanar)
            continue;
          FOREACHpoint_(facet->coplanarset)
            qh_printpointvect2(qh, fp, point, facet->normal, NULL, qh->PRINTradius);
          FOREACHpoint_(facet->outsideset)
            qh_printpointvect2(qh, fp, point, facet->normal, NULL, qh->PRINTradius);
        }
      }
      qh_settempfree(qh, &vertices);
    }
    qh->visit_id++; /* for printing hyperplane intersections */
    break;
  case qh_PRINTids:
    qh_fprintf(qh, fp, 9049, "%d\n", numfacets);
    break;
  case qh_PRINTincidences:
    if (qh->VORONOI && qh->PRINTprecision)
      qh_fprintf(qh, qh->ferr, 7053, "qhull warning: input sites of Delaunay regions (option 'i').  Use option 'p' or 'o' for Voronoi centers.  Disable warning with option 'Pp'\n");
    qh->printoutvar= (int)qh->vertex_id;  /* centrum id for 4-d+, non-simplicial facets */
    if (qh->hull_dim <= 3)
      qh_fprintf(qh, fp, 9050, "%d\n", numfacets);
    else
      qh_fprintf(qh, fp, 9051, "%d\n", numsimplicial+numridges);
    break;
  case qh_PRINTinner:
  case qh_PRINTnormals:
  case qh_PRINTouter:
    if (qh->CDDoutput)
      qh_fprintf(qh, fp, 9052, "%s | %s\nbegin\n    %d %d real\n", qh->rbox_command,
            qh->qhull_command, numfacets, qh->hull_dim+1);
    else
      qh_fprintf(qh, fp, 9053, "%d\n%d\n", qh->hull_dim+1, numfacets);
    break;
  case qh_PRINTmathematica:
  case qh_PRINTmaple:
    if (qh->hull_dim > 3)  /* qh_initbuffers also checks */
      goto LABELnoformat;
    if (qh->VORONOI)
      qh_fprintf(qh, qh->ferr, 7054, "qhull warning: output is the Delaunay triangulation\n");
    if (format == qh_PRINTmaple) {
      if (qh->hull_dim == 2)
        qh_fprintf(qh, fp, 9054, "PLOT(CURVES(\n");
      else
        qh_fprintf(qh, fp, 9055, "PLOT3D(POLYGONS(\n");
    }else
      qh_fprintf(qh, fp, 9056, "{\n");
    qh->printoutvar= 0;   /* counts number of facets for notfirst */
    break;
  case qh_PRINTmerges:
    qh_fprintf(qh, fp, 9057, "%d\n", numfacets);
    break;
  case qh_PRINTpointintersect:
    qh_fprintf(qh, fp, 9058, "%d\n%d\n", qh->hull_dim, numfacets);
    break;
  case qh_PRINTneighbors:
    qh_fprintf(qh, fp, 9059, "%d\n", numfacets);
    break;
  case qh_PRINToff:
  case qh_PRINTtriangles:
    if (qh->VORONOI)
      goto LABELnoformat;
    num= qh->hull_dim;
    if (format == qh_PRINToff || qh->hull_dim == 2)
      qh_fprintf(qh, fp, 9060, "%d\n%d %d %d\n", num,
        qh->num_points+qh_setsize(qh, qh->other_points), numfacets, totneighbors/2);
    else { /* qh_PRINTtriangles */
      qh->printoutvar= qh->num_points+qh_setsize(qh, qh->other_points); /* first centrum */
      if (qh->DELAUNAY)
        num--;  /* drop last dimension */
      qh_fprintf(qh, fp, 9061, "%d\n%d %d %d\n", num, qh->printoutvar
        + numfacets - numsimplicial, numsimplicial + numridges, totneighbors/2);
    }
    FORALLpoints
      qh_printpointid(qh, qh->fout, NULL, num, point, qh_IDunknown);
    FOREACHpoint_(qh->other_points)
      qh_printpointid(qh, qh->fout, NULL, num, point, qh_IDunknown);
    if (format == qh_PRINTtriangles && qh->hull_dim > 2) {
      FORALLfacets {
        if (!facet->simplicial && facet->visitid)
          qh_printcenter(qh, qh->fout, format, NULL, facet);
      }
    }
    break;
  case qh_PRINTpointnearest:
    qh_fprintf(qh, fp, 9062, "%d\n", numcoplanars);
    break;
  case qh_PRINTpoints:
    if (!qh->VORONOI)
      goto LABELnoformat;
    if (qh->CDDoutput)
      qh_fprintf(qh, fp, 9063, "%s | %s\nbegin\n%d %d real\n", qh->rbox_command,
           qh->qhull_command, numfacets, qh->hull_dim);
    else
      qh_fprintf(qh, fp, 9064, "%d\n%d\n", qh->hull_dim-1, numfacets);
    break;
  case qh_PRINTvertices:
    qh_fprintf(qh, fp, 9065, "%d\n", numfacets);
    break;
  case qh_PRINTsummary:
  default:
  LABELnoformat:
    qh_fprintf(qh, qh->ferr, 6068, "qhull internal error (qh_printbegin): can not use this format for dimension %d\n",
         qh->hull_dim);
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
} /* printbegin */

/*---------------------------------

  qh_printcenter(qh, fp, string, facet )
    print facet->center as centrum or Voronoi center
    string may be NULL.  Don't include '%' codes.
    nop if qh->CENTERtype neither CENTERvoronoi nor CENTERcentrum
    if upper envelope of Delaunay triangulation and point at-infinity
      prints qh_INFINITE instead;

  notes:
    defines facet->center if needed
    if format=PRINTgeom, adds a 0 if would otherwise be 2-d
    Same as QhullFacet::printCenter
*/
void qh_printcenter(qhT *qh, FILE *fp, qh_PRINT format, const char *string, facetT *facet) {
  int k, num;

  if (qh->CENTERtype != qh_ASvoronoi && qh->CENTERtype != qh_AScentrum)
    return;
  if (string)
    qh_fprintf(qh, fp, 9066, string);
  if (qh->CENTERtype == qh_ASvoronoi) {
    num= qh->hull_dim-1;
    if (!facet->normal || !facet->upperdelaunay || !qh->ATinfinity) {
      if (!facet->center)
        facet->center= qh_facetcenter(qh, facet->vertices);
      for (k=0; k < num; k++)
        qh_fprintf(qh, fp, 9067, qh_REAL_1, facet->center[k]);
    }else {
      for (k=0; k < num; k++)
        qh_fprintf(qh, fp, 9068, qh_REAL_1, qh_INFINITE);
    }
  }else /* qh.CENTERtype == qh_AScentrum */ {
    num= qh->hull_dim;
    if (format == qh_PRINTtriangles && qh->DELAUNAY)
      num--;
    if (!facet->center)
      facet->center= qh_getcentrum(qh, facet);
    for (k=0; k < num; k++)
      qh_fprintf(qh, fp, 9069, qh_REAL_1, facet->center[k]);
  }
  if (format == qh_PRINTgeom && num == 2)
    qh_fprintf(qh, fp, 9070, " 0\n");
  else
    qh_fprintf(qh, fp, 9071, "\n");
} /* printcenter */

/*---------------------------------

  qh_printcentrum(qh, fp, facet, radius )
    print centrum for a facet in OOGL format
    radius defines size of centrum
    2-d or 3-d only

  returns:
    defines facet->center if needed
*/
void qh_printcentrum(qhT *qh, FILE *fp, facetT *facet, realT radius) {
  pointT *centrum, *projpt;
  boolT tempcentrum= False;
  realT xaxis[4], yaxis[4], normal[4], dist;
  realT green[3]={0, 1, 0};
  vertexT *apex;
  int k;

  if (qh->CENTERtype == qh_AScentrum) {
    if (!facet->center)
      facet->center= qh_getcentrum(qh, facet);
    centrum= facet->center;
  }else {
    centrum= qh_getcentrum(qh, facet);
    tempcentrum= True;
  }
  qh_fprintf(qh, fp, 9072, "{appearance {-normal -edge normscale 0} ");
  if (qh->firstcentrum) {
    qh->firstcentrum= False;
    qh_fprintf(qh, fp, 9073, "{INST geom { define centrum CQUAD  # f%d\n\
-0.3 -0.3 0.0001     0 0 1 1\n\
 0.3 -0.3 0.0001     0 0 1 1\n\
 0.3  0.3 0.0001     0 0 1 1\n\
-0.3  0.3 0.0001     0 0 1 1 } transform { \n", facet->id);
  }else
    qh_fprintf(qh, fp, 9074, "{INST geom { : centrum } transform { # f%d\n", facet->id);
  apex= SETfirstt_(facet->vertices, vertexT);
  qh_distplane(qh, apex->point, facet, &dist);
  projpt= qh_projectpoint(qh, apex->point, facet, dist);
  for (k=qh->hull_dim; k--; ) {
    xaxis[k]= projpt[k] - centrum[k];
    normal[k]= facet->normal[k];
  }
  if (qh->hull_dim == 2) {
    xaxis[2]= 0;
    normal[2]= 0;
  }else if (qh->hull_dim == 4) {
    qh_projectdim3(qh, xaxis, xaxis);
    qh_projectdim3(qh, normal, normal);
    qh_normalize2(qh, normal, qh->PRINTdim, True, NULL, NULL);
  }
  qh_crossproduct(3, xaxis, normal, yaxis);
  qh_fprintf(qh, fp, 9075, "%8.4g %8.4g %8.4g 0\n", xaxis[0], xaxis[1], xaxis[2]);
  qh_fprintf(qh, fp, 9076, "%8.4g %8.4g %8.4g 0\n", yaxis[0], yaxis[1], yaxis[2]);
  qh_fprintf(qh, fp, 9077, "%8.4g %8.4g %8.4g 0\n", normal[0], normal[1], normal[2]);
  qh_printpoint3(qh, fp, centrum);
  qh_fprintf(qh, fp, 9078, "1 }}}\n");
  qh_memfree(qh, projpt, qh->normal_size);
  qh_printpointvect(qh, fp, centrum, facet->normal, NULL, radius, green);
  if (tempcentrum)
    qh_memfree(qh, centrum, qh->normal_size);
} /* printcentrum */

/*---------------------------------

  qh_printend(qh, fp, format )
    prints trailer for all output formats

  see:
    qh_printbegin() and qh_printafacet()

*/
void qh_printend(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {
  int num;
  facetT *facet, **facetp;

  if (!qh->printoutnum)
    qh_fprintf(qh, qh->ferr, 7055, "qhull warning: no facets printed\n");
  switch (format) {
  case qh_PRINTgeom:
    if (qh->hull_dim == 4 && qh->DROPdim < 0  && !qh->PRINTnoplanes) {
      qh->visit_id++;
      num= 0;
      FORALLfacet_(facetlist)
        qh_printend4geom(qh, fp, facet,&num, printall);
      FOREACHfacet_(facets)
        qh_printend4geom(qh, fp, facet, &num, printall);
      if (num != qh->ridgeoutnum || qh->printoutvar != qh->ridgeoutnum) {
        qh_fprintf(qh, qh->ferr, 6069, "qhull internal error (qh_printend): number of ridges %d != number printed %d and at end %d\n", qh->ridgeoutnum, qh->printoutvar, num);
        qh_errexit(qh, qh_ERRqhull, NULL, NULL);
      }
    }else
      qh_fprintf(qh, fp, 9079, "}\n");
    break;
  case qh_PRINTinner:
  case qh_PRINTnormals:
  case qh_PRINTouter:
    if (qh->CDDoutput)
      qh_fprintf(qh, fp, 9080, "end\n");
    break;
  case qh_PRINTmaple:
    qh_fprintf(qh, fp, 9081, "));\n");
    break;
  case qh_PRINTmathematica:
    qh_fprintf(qh, fp, 9082, "}\n");
    break;
  case qh_PRINTpoints:
    if (qh->CDDoutput)
      qh_fprintf(qh, fp, 9083, "end\n");
    break;
  default:
    break;
  }
} /* printend */

/*---------------------------------

  qh_printend4geom(qh, fp, facet, numridges, printall )
    helper function for qh_printbegin/printend

  returns:
    number of printed ridges

  notes:
    just counts printed ridges if fp=NULL
    uses facet->visitid
    must agree with qh_printfacet4geom...

  design:
    computes color for facet from its normal
    prints each ridge of facet
*/
void qh_printend4geom(qhT *qh, FILE *fp, facetT *facet, int *nump, boolT printall) {
  realT color[3];
  int i, num= *nump;
  facetT *neighbor, **neighborp;
  ridgeT *ridge, **ridgep;

  if (!printall && qh_skipfacet(qh, facet))
    return;
  if (qh->PRINTnoplanes || (facet->visible && qh->NEWfacets))
    return;
  if (!facet->normal)
    return;
  if (fp) {
    for (i=0; i < 3; i++) {
      color[i]= (facet->normal[i]+1.0)/2.0;
      maximize_(color[i], -1.0);
      minimize_(color[i], +1.0);
    }
  }
  facet->visitid= qh->visit_id;
  if (facet->simplicial) {
    FOREACHneighbor_(facet) {
      if (neighbor->visitid != qh->visit_id) {
        if (fp)
          qh_fprintf(qh, fp, 9084, "3 %d %d %d %8.4g %8.4g %8.4g 1 # f%d f%d\n",
                 3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],
                 facet->id, neighbor->id);
        num++;
      }
    }
  }else {
    FOREACHridge_(facet->ridges) {
      neighbor= otherfacet_(ridge, facet);
      if (neighbor->visitid != qh->visit_id) {
        if (fp)
          qh_fprintf(qh, fp, 9085, "3 %d %d %d %8.4g %8.4g %8.4g 1 #r%d f%d f%d\n",
                 3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],
                 ridge->id, facet->id, neighbor->id);
        num++;
      }
    }
  }
  *nump= num;
} /* printend4geom */

/*---------------------------------

  qh_printextremes(qh, fp, facetlist, facets, printall )
    print extreme points for convex hulls or halfspace intersections

  notes:
    #points, followed by ids, one per line

    sorted by id
    same order as qh_printpoints_out if no coplanar/interior points
*/
void qh_printextremes(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall) {
  setT *vertices, *points;
  pointT *point;
  vertexT *vertex, **vertexp;
  int id;
  int numpoints=0, point_i, point_n;
  int allpoints= qh->num_points + qh_setsize(qh, qh->other_points);

  points= qh_settemp(qh, allpoints);
  qh_setzero(qh, points, 0, allpoints);
  vertices= qh_facetvertices(qh, facetlist, facets, printall);
  FOREACHvertex_(vertices) {
    id= qh_pointid(qh, vertex->point);
    if (id >= 0) {
      SETelem_(points, id)= vertex->point;
      numpoints++;
    }
  }
  qh_settempfree(qh, &vertices);
  qh_fprintf(qh, fp, 9086, "%d\n", numpoints);
  FOREACHpoint_i_(qh, points) {
    if (point)
      qh_fprintf(qh, fp, 9087, "%d\n", point_i);
  }
  qh_settempfree(qh, &points);
} /* printextremes */

/*---------------------------------

  qh_printextremes_2d(qh, fp, facetlist, facets, printall )
    prints point ids for facets in qh_ORIENTclock order

  notes:
    #points, followed by ids, one per line
    if facetlist/facets are disjoint than the output includes skips
    errors if facets form a loop
    does not print coplanar points
*/
void qh_printextremes_2d(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall) {
  int numfacets, numridges, totneighbors, numcoplanars, numsimplicial, numtricoplanars;
  setT *vertices;
  facetT *facet, *startfacet, *nextfacet;
  vertexT *vertexA, *vertexB;

  qh_countfacets(qh, facetlist, facets, printall, &numfacets, &numsimplicial,
      &totneighbors, &numridges, &numcoplanars, &numtricoplanars); /* marks qh->visit_id */
  vertices= qh_facetvertices(qh, facetlist, facets, printall);
  qh_fprintf(qh, fp, 9088, "%d\n", qh_setsize(qh, vertices));
  qh_settempfree(qh, &vertices);
  if (!numfacets)
    return;
  facet= startfacet= facetlist ? facetlist : SETfirstt_(facets, facetT);
  qh->vertex_visit++;
  qh->visit_id++;
  do {
    if (facet->toporient ^ qh_ORIENTclock) {
      vertexA= SETfirstt_(facet->vertices, vertexT);
      vertexB= SETsecondt_(facet->vertices, vertexT);
      nextfacet= SETfirstt_(facet->neighbors, facetT);
    }else {
      vertexA= SETsecondt_(facet->vertices, vertexT);
      vertexB= SETfirstt_(facet->vertices, vertexT);
      nextfacet= SETsecondt_(facet->neighbors, facetT);
    }
    if (facet->visitid == qh->visit_id) {
      qh_fprintf(qh, qh->ferr, 6218, "qhull internal error (qh_printextremes_2d): loop in facet list.  facet %d nextfacet %d\n",
                 facet->id, nextfacet->id);
      qh_errexit2(qh, qh_ERRqhull, facet, nextfacet);
    }
    if (facet->visitid) {
      if (vertexA->visitid != qh->vertex_visit) {
        vertexA->visitid= qh->vertex_visit;
        qh_fprintf(qh, fp, 9089, "%d\n", qh_pointid(qh, vertexA->point));
      }
      if (vertexB->visitid != qh->vertex_visit) {
        vertexB->visitid= qh->vertex_visit;
        qh_fprintf(qh, fp, 9090, "%d\n", qh_pointid(qh, vertexB->point));
      }
    }
    facet->visitid= qh->visit_id;
    facet= nextfacet;
  }while (facet && facet != startfacet);
} /* printextremes_2d */

/*---------------------------------

  qh_printextremes_d(qh, fp, facetlist, facets, printall )
    print extreme points of input sites for Delaunay triangulations

  notes:
    #points, followed by ids, one per line

    unordered
*/
void qh_printextremes_d(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall) {
  setT *vertices;
  vertexT *vertex, **vertexp;
  boolT upperseen, lowerseen;
  facetT *neighbor, **neighborp;
  int numpoints=0;

  vertices= qh_facetvertices(qh, facetlist, facets, printall);
  qh_vertexneighbors(qh);
  FOREACHvertex_(vertices) {
    upperseen= lowerseen= False;
    FOREACHneighbor_(vertex) {
      if (neighbor->upperdelaunay)
        upperseen= True;
      else
        lowerseen= True;
    }
    if (upperseen && lowerseen) {
      vertex->seen= True;
      numpoints++;
    }else
      vertex->seen= False;
  }
  qh_fprintf(qh, fp, 9091, "%d\n", numpoints);
  FOREACHvertex_(vertices) {
    if (vertex->seen)
      qh_fprintf(qh, fp, 9092, "%d\n", qh_pointid(qh, vertex->point));
  }
  qh_settempfree(qh, &vertices);
} /* printextremes_d */

/*---------------------------------

  qh_printfacet(qh, fp, facet )
    prints all fields of a facet to fp

  notes:
    ridges printed in neighbor order
*/
void qh_printfacet(qhT *qh, FILE *fp, facetT *facet) {

  qh_printfacetheader(qh, fp, facet);
  if (facet->ridges)
    qh_printfacetridges(qh, fp, facet);
} /* printfacet */


/*---------------------------------

  qh_printfacet2geom(qh, fp, facet, color )
    print facet as part of a 2-d VECT for Geomview

    notes:
      assume precise calculations in io_r.c with roundoff covered by qh_GEOMepsilon
      mindist is calculated within io_r.c.  maxoutside is calculated elsewhere
      so a DISTround error may have occurred.
*/
void qh_printfacet2geom(qhT *qh, FILE *fp, facetT *facet, realT color[3]) {
  pointT *point0, *point1;
  realT mindist, innerplane, outerplane;
  int k;

  qh_facet2point(qh, facet, &point0, &point1, &mindist);
  qh_geomplanes(qh, facet, &outerplane, &innerplane);
  if (qh->PRINTouter || (!qh->PRINTnoplanes && !qh->PRINTinner))
    qh_printfacet2geom_points(qh, fp, point0, point1, facet, outerplane, color);
  if (qh->PRINTinner || (!qh->PRINTnoplanes && !qh->PRINTouter &&
                outerplane - innerplane > 2 * qh->MAXabs_coord * qh_GEOMepsilon)) {
    for (k=3; k--; )
      color[k]= 1.0 - color[k];
    qh_printfacet2geom_points(qh, fp, point0, point1, facet, innerplane, color);
  }
  qh_memfree(qh, point1, qh->normal_size);
  qh_memfree(qh, point0, qh->normal_size);
} /* printfacet2geom */

/*---------------------------------

  qh_printfacet2geom_points(qh, fp, point1, point2, facet, offset, color )
    prints a 2-d facet as a VECT with 2 points at some offset.
    The points are on the facet's plane.
*/
void qh_printfacet2geom_points(qhT *qh, FILE *fp, pointT *point1, pointT *point2,
                               facetT *facet, realT offset, realT color[3]) {
  pointT *p1= point1, *p2= point2;

  qh_fprintf(qh, fp, 9093, "VECT 1 2 1 2 1 # f%d\n", facet->id);
  if (offset != 0.0) {
    p1= qh_projectpoint(qh, p1, facet, -offset);
    p2= qh_projectpoint(qh, p2, facet, -offset);
  }
  qh_fprintf(qh, fp, 9094, "%8.4g %8.4g %8.4g\n%8.4g %8.4g %8.4g\n",
           p1[0], p1[1], 0.0, p2[0], p2[1], 0.0);
  if (offset != 0.0) {
    qh_memfree(qh, p1, qh->normal_size);
    qh_memfree(qh, p2, qh->normal_size);
  }
  qh_fprintf(qh, fp, 9095, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
} /* printfacet2geom_points */


/*---------------------------------

  qh_printfacet2math(qh, fp, facet, format, notfirst )
    print 2-d Maple or Mathematica output for a facet
    may be non-simplicial

  notes:
    use %16.8f since Mathematica 2.2 does not handle exponential format
    see qh_printfacet3math
*/
void qh_printfacet2math(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format, int notfirst) {
  pointT *point0, *point1;
  realT mindist;
  const char *pointfmt;

  qh_facet2point(qh, facet, &point0, &point1, &mindist);
  if (notfirst)
    qh_fprintf(qh, fp, 9096, ",");
  if (format == qh_PRINTmaple)
    pointfmt= "[[%16.8f, %16.8f], [%16.8f, %16.8f]]\n";
  else
    pointfmt= "Line[{{%16.8f, %16.8f}, {%16.8f, %16.8f}}]\n";
  qh_fprintf(qh, fp, 9097, pointfmt, point0[0], point0[1], point1[0], point1[1]);
  qh_memfree(qh, point1, qh->normal_size);
  qh_memfree(qh, point0, qh->normal_size);
} /* printfacet2math */


/*---------------------------------

  qh_printfacet3geom_nonsimplicial(qh, fp, facet, color )
    print Geomview OFF for a 3-d nonsimplicial facet.
    if DOintersections, prints ridges to unvisited neighbors(qh->visit_id)

  notes
    uses facet->visitid for intersections and ridges
*/
void qh_printfacet3geom_nonsimplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]) {
  ridgeT *ridge, **ridgep;
  setT *projectedpoints, *vertices;
  vertexT *vertex, **vertexp, *vertexA, *vertexB;
  pointT *projpt, *point, **pointp;
  facetT *neighbor;
  realT dist, outerplane, innerplane;
  int cntvertices, k;
  realT black[3]={0, 0, 0}, green[3]={0, 1, 0};

  qh_geomplanes(qh, facet, &outerplane, &innerplane);
  vertices= qh_facet3vertex(qh, facet); /* oriented */
  cntvertices= qh_setsize(qh, vertices);
  projectedpoints= qh_settemp(qh, cntvertices);
  FOREACHvertex_(vertices) {
    zinc_(Zdistio);
    qh_distplane(qh, vertex->point, facet, &dist);
    projpt= qh_projectpoint(qh, vertex->point, facet, dist);
    qh_setappend(qh, &projectedpoints, projpt);
  }
  if (qh->PRINTouter || (!qh->PRINTnoplanes && !qh->PRINTinner))
    qh_printfacet3geom_points(qh, fp, projectedpoints, facet, outerplane, color);
  if (qh->PRINTinner || (!qh->PRINTnoplanes && !qh->PRINTouter &&
                outerplane - innerplane > 2 * qh->MAXabs_coord * qh_GEOMepsilon)) {
    for (k=3; k--; )
      color[k]= 1.0 - color[k];
    qh_printfacet3geom_points(qh, fp, projectedpoints, facet, innerplane, color);
  }
  FOREACHpoint_(projectedpoints)
    qh_memfree(qh, point, qh->normal_size);
  qh_settempfree(qh, &projectedpoints);
  qh_settempfree(qh, &vertices);
  if ((qh->DOintersections || qh->PRINTridges)
  && (!facet->visible || !qh->NEWfacets)) {
    facet->visitid= qh->visit_id;
    FOREACHridge_(facet->ridges) {
      neighbor= otherfacet_(ridge, facet);
      if (neighbor->visitid != qh->visit_id) {
        if (qh->DOintersections)
          qh_printhyperplaneintersection(qh, fp, facet, neighbor, ridge->vertices, black);
        if (qh->PRINTridges) {
          vertexA= SETfirstt_(ridge->vertices, vertexT);
          vertexB= SETsecondt_(ridge->vertices, vertexT);
          qh_printline3geom(qh, fp, vertexA->point, vertexB->point, green);
        }
      }
    }
  }
} /* printfacet3geom_nonsimplicial */

/*---------------------------------

  qh_printfacet3geom_points(qh, fp, points, facet, offset )
    prints a 3-d facet as OFF Geomview object.
    offset is relative to the facet's hyperplane
    Facet is determined as a list of points
*/
void qh_printfacet3geom_points(qhT *qh, FILE *fp, setT *points, facetT *facet, realT offset, realT color[3]) {
  int k, n= qh_setsize(qh, points), i;
  pointT *point, **pointp;
  setT *printpoints;

  qh_fprintf(qh, fp, 9098, "{ OFF %d 1 1 # f%d\n", n, facet->id);
  if (offset != 0.0) {
    printpoints= qh_settemp(qh, n);
    FOREACHpoint_(points)
      qh_setappend(qh, &printpoints, qh_projectpoint(qh, point, facet, -offset));
  }else
    printpoints= points;
  FOREACHpoint_(printpoints) {
    for (k=0; k < qh->hull_dim; k++) {
      if (k == qh->DROPdim)
        qh_fprintf(qh, fp, 9099, "0 ");
      else
        qh_fprintf(qh, fp, 9100, "%8.4g ", point[k]);
    }
    if (printpoints != points)
      qh_memfree(qh, point, qh->normal_size);
    qh_fprintf(qh, fp, 9101, "\n");
  }
  if (printpoints != points)
    qh_settempfree(qh, &printpoints);
  qh_fprintf(qh, fp, 9102, "%d ", n);
  for (i=0; i < n; i++)
    qh_fprintf(qh, fp, 9103, "%d ", i);
  qh_fprintf(qh, fp, 9104, "%8.4g %8.4g %8.4g 1.0 }\n", color[0], color[1], color[2]);
} /* printfacet3geom_points */


/*---------------------------------

  qh_printfacet3geom_simplicial(qh )
    print Geomview OFF for a 3-d simplicial facet.

  notes:
    may flip color
    uses facet->visitid for intersections and ridges

    assume precise calculations in io_r.c with roundoff covered by qh_GEOMepsilon
    innerplane may be off by qh->DISTround.  Maxoutside is calculated elsewhere
    so a DISTround error may have occurred.
*/
void qh_printfacet3geom_simplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]) {
  setT *points, *vertices;
  vertexT *vertex, **vertexp, *vertexA, *vertexB;
  facetT *neighbor, **neighborp;
  realT outerplane, innerplane;
  realT black[3]={0, 0, 0}, green[3]={0, 1, 0};
  int k;

  qh_geomplanes(qh, facet, &outerplane, &innerplane);
  vertices= qh_facet3vertex(qh, facet);
  points= qh_settemp(qh, qh->TEMPsize);
  FOREACHvertex_(vertices)
    qh_setappend(qh, &points, vertex->point);
  if (qh->PRINTouter || (!qh->PRINTnoplanes && !qh->PRINTinner))
    qh_printfacet3geom_points(qh, fp, points, facet, outerplane, color);
  if (qh->PRINTinner || (!qh->PRINTnoplanes && !qh->PRINTouter &&
              outerplane - innerplane > 2 * qh->MAXabs_coord * qh_GEOMepsilon)) {
    for (k=3; k--; )
      color[k]= 1.0 - color[k];
    qh_printfacet3geom_points(qh, fp, points, facet, innerplane, color);
  }
  qh_settempfree(qh, &points);
  qh_settempfree(qh, &vertices);
  if ((qh->DOintersections || qh->PRINTridges)
  && (!facet->visible || !qh->NEWfacets)) {
    facet->visitid= qh->visit_id;
    FOREACHneighbor_(facet) {
      if (neighbor->visitid != qh->visit_id) {
        vertices= qh_setnew_delnthsorted(qh, facet->vertices, qh->hull_dim,
                          SETindex_(facet->neighbors, neighbor), 0);
        if (qh->DOintersections)
           qh_printhyperplaneintersection(qh, fp, facet, neighbor, vertices, black);
        if (qh->PRINTridges) {
          vertexA= SETfirstt_(vertices, vertexT);
          vertexB= SETsecondt_(vertices, vertexT);
          qh_printline3geom(qh, fp, vertexA->point, vertexB->point, green);
        }
        qh_setfree(qh, &vertices);
      }
    }
  }
} /* printfacet3geom_simplicial */

/*---------------------------------

  qh_printfacet3math(qh, fp, facet, notfirst )
    print 3-d Maple or Mathematica output for a facet

  notes:
    may be non-simplicial
    use %16.8f since Mathematica 2.2 does not handle exponential format
    see qh_printfacet2math
*/
void qh_printfacet3math(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format, int notfirst) {
  vertexT *vertex, **vertexp;
  setT *points, *vertices;
  pointT *point, **pointp;
  boolT firstpoint= True;
  realT dist;
  const char *pointfmt, *endfmt;

  if (notfirst)
    qh_fprintf(qh, fp, 9105, ",\n");
  vertices= qh_facet3vertex(qh, facet);
  points= qh_settemp(qh, qh_setsize(qh, vertices));
  FOREACHvertex_(vertices) {
    zinc_(Zdistio);
    qh_distplane(qh, vertex->point, facet, &dist);
    point= qh_projectpoint(qh, vertex->point, facet, dist);
    qh_setappend(qh, &points, point);
  }
  if (format == qh_PRINTmaple) {
    qh_fprintf(qh, fp, 9106, "[");
    pointfmt= "[%16.8f, %16.8f, %16.8f]";
    endfmt= "]";
  }else {
    qh_fprintf(qh, fp, 9107, "Polygon[{");
    pointfmt= "{%16.8f, %16.8f, %16.8f}";
    endfmt= "}]";
  }
  FOREACHpoint_(points) {
    if (firstpoint)
      firstpoint= False;
    else
      qh_fprintf(qh, fp, 9108, ",\n");
    qh_fprintf(qh, fp, 9109, pointfmt, point[0], point[1], point[2]);
  }
  FOREACHpoint_(points)
    qh_memfree(qh, point, qh->normal_size);
  qh_settempfree(qh, &points);
  qh_settempfree(qh, &vertices);
  qh_fprintf(qh, fp, 9110, "%s", endfmt);
} /* printfacet3math */


/*---------------------------------

  qh_printfacet3vertex(qh, fp, facet, format )
    print vertices in a 3-d facet as point ids

  notes:
    prints number of vertices first if format == qh_PRINToff
    the facet may be non-simplicial
*/
void qh_printfacet3vertex(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format) {
  vertexT *vertex, **vertexp;
  setT *vertices;

  vertices= qh_facet3vertex(qh, facet);
  if (format == qh_PRINToff)
    qh_fprintf(qh, fp, 9111, "%d ", qh_setsize(qh, vertices));
  FOREACHvertex_(vertices)
    qh_fprintf(qh, fp, 9112, "%d ", qh_pointid(qh, vertex->point));
  qh_fprintf(qh, fp, 9113, "\n");
  qh_settempfree(qh, &vertices);
} /* printfacet3vertex */


/*---------------------------------

  qh_printfacet4geom_nonsimplicial(qh )
    print Geomview 4OFF file for a 4d nonsimplicial facet
    prints all ridges to unvisited neighbors (qh.visit_id)
    if qh.DROPdim
      prints in OFF format

  notes:
    must agree with printend4geom()
*/
void qh_printfacet4geom_nonsimplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]) {
  facetT *neighbor;
  ridgeT *ridge, **ridgep;
  vertexT *vertex, **vertexp;
  pointT *point;
  int k;
  realT dist;

  facet->visitid= qh->visit_id;
  if (qh->PRINTnoplanes || (facet->visible && qh->NEWfacets))
    return;
  FOREACHridge_(facet->ridges) {
    neighbor= otherfacet_(ridge, facet);
    if (neighbor->visitid == qh->visit_id)
      continue;
    if (qh->PRINTtransparent && !neighbor->good)
      continue;
    if (qh->DOintersections)
      qh_printhyperplaneintersection(qh, fp, facet, neighbor, ridge->vertices, color);
    else {
      if (qh->DROPdim >= 0)
        qh_fprintf(qh, fp, 9114, "OFF 3 1 1 # f%d\n", facet->id);
      else {
        qh->printoutvar++;
        qh_fprintf(qh, fp, 9115, "# r%d between f%d f%d\n", ridge->id, facet->id, neighbor->id);
      }
      FOREACHvertex_(ridge->vertices) {
        zinc_(Zdistio);
        qh_distplane(qh, vertex->point,facet, &dist);
        point=qh_projectpoint(qh, vertex->point,facet, dist);
        for (k=0; k < qh->hull_dim; k++) {
          if (k != qh->DROPdim)
            qh_fprintf(qh, fp, 9116, "%8.4g ", point[k]);
        }
        qh_fprintf(qh, fp, 9117, "\n");
        qh_memfree(qh, point, qh->normal_size);
      }
      if (qh->DROPdim >= 0)
        qh_fprintf(qh, fp, 9118, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);
    }
  }
} /* printfacet4geom_nonsimplicial */


/*---------------------------------

  qh_printfacet4geom_simplicial(qh, fp, facet, color )
    print Geomview 4OFF file for a 4d simplicial facet
    prints triangles for unvisited neighbors (qh.visit_id)

  notes:
    must agree with printend4geom()
*/
void qh_printfacet4geom_simplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]) {
  setT *vertices;
  facetT *neighbor, **neighborp;
  vertexT *vertex, **vertexp;
  int k;

  facet->visitid= qh->visit_id;
  if (qh->PRINTnoplanes || (facet->visible && qh->NEWfacets))
    return;
  FOREACHneighbor_(facet) {
    if (neighbor->visitid == qh->visit_id)
      continue;
    if (qh->PRINTtransparent && !neighbor->good)
      continue;
    vertices= qh_setnew_delnthsorted(qh, facet->vertices, qh->hull_dim,
                          SETindex_(facet->neighbors, neighbor), 0);
    if (qh->DOintersections)
      qh_printhyperplaneintersection(qh, fp, facet, neighbor, vertices, color);
    else {
      if (qh->DROPdim >= 0)
        qh_fprintf(qh, fp, 9119, "OFF 3 1 1 # ridge between f%d f%d\n",
                facet->id, neighbor->id);
      else {
        qh->printoutvar++;
        qh_fprintf(qh, fp, 9120, "# ridge between f%d f%d\n", facet->id, neighbor->id);
      }
      FOREACHvertex_(vertices) {
        for (k=0; k < qh->hull_dim; k++) {
          if (k != qh->DROPdim)
            qh_fprintf(qh, fp, 9121, "%8.4g ", vertex->point[k]);
        }
        qh_fprintf(qh, fp, 9122, "\n");
      }
      if (qh->DROPdim >= 0)
        qh_fprintf(qh, fp, 9123, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);
    }
    qh_setfree(qh, &vertices);
  }
} /* printfacet4geom_simplicial */


/*---------------------------------

  qh_printfacetNvertex_nonsimplicial(qh, fp, facet, id, format )
    print vertices for an N-d non-simplicial facet
    triangulates each ridge to the id
*/
void qh_printfacetNvertex_nonsimplicial(qhT *qh, FILE *fp, facetT *facet, int id, qh_PRINT format) {
  vertexT *vertex, **vertexp;
  ridgeT *ridge, **ridgep;

  if (facet->visible && qh->NEWfacets)
    return;
  FOREACHridge_(facet->ridges) {
    if (format == qh_PRINTtriangles)
      qh_fprintf(qh, fp, 9124, "%d ", qh->hull_dim);
    qh_fprintf(qh, fp, 9125, "%d ", id);
    if ((ridge->top == facet) ^ qh_ORIENTclock) {
      FOREACHvertex_(ridge->vertices)
        qh_fprintf(qh, fp, 9126, "%d ", qh_pointid(qh, vertex->point));
    }else {
      FOREACHvertexreverse12_(ridge->vertices)
        qh_fprintf(qh, fp, 9127, "%d ", qh_pointid(qh, vertex->point));
    }
    qh_fprintf(qh, fp, 9128, "\n");
  }
} /* printfacetNvertex_nonsimplicial */


/*---------------------------------

  qh_printfacetNvertex_simplicial(qh, fp, facet, format )
    print vertices for an N-d simplicial facet
    prints vertices for non-simplicial facets
      2-d facets (orientation preserved by qh_mergefacet2d)
      PRINToff ('o') for 4-d and higher
*/
void qh_printfacetNvertex_simplicial(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format) {
  vertexT *vertex, **vertexp;

  if (format == qh_PRINToff || format == qh_PRINTtriangles)
    qh_fprintf(qh, fp, 9129, "%d ", qh_setsize(qh, facet->vertices));
  if ((facet->toporient ^ qh_ORIENTclock)
  || (qh->hull_dim > 2 && !facet->simplicial)) {
    FOREACHvertex_(facet->vertices)
      qh_fprintf(qh, fp, 9130, "%d ", qh_pointid(qh, vertex->point));
  }else {
    FOREACHvertexreverse12_(facet->vertices)
      qh_fprintf(qh, fp, 9131, "%d ", qh_pointid(qh, vertex->point));
  }
  qh_fprintf(qh, fp, 9132, "\n");
} /* printfacetNvertex_simplicial */


/*---------------------------------

  qh_printfacetheader(qh, fp, facet )
    prints header fields of a facet to fp

  notes:
    for 'f' output and debugging
    Same as QhullFacet::printHeader()
*/
void qh_printfacetheader(qhT *qh, FILE *fp, facetT *facet) {
  pointT *point, **pointp, *furthest;
  facetT *neighbor, **neighborp;
  realT dist;

  if (facet == qh_MERGEridge) {
    qh_fprintf(qh, fp, 9133, " MERGEridge\n");
    return;
  }else if (facet == qh_DUPLICATEridge) {
    qh_fprintf(qh, fp, 9134, " DUPLICATEridge\n");
    return;
  }else if (!facet) {
    qh_fprintf(qh, fp, 9135, " NULLfacet\n");
    return;
  }
  qh->old_randomdist= qh->RANDOMdist;
  qh->RANDOMdist= False;
  qh_fprintf(qh, fp, 9136, "- f%d\n", facet->id);
  qh_fprintf(qh, fp, 9137, "    - flags:");
  if (facet->toporient)
    qh_fprintf(qh, fp, 9138, " top");
  else
    qh_fprintf(qh, fp, 9139, " bottom");
  if (facet->simplicial)
    qh_fprintf(qh, fp, 9140, " simplicial");
  if (facet->tricoplanar)
    qh_fprintf(qh, fp, 9141, " tricoplanar");
  if (facet->upperdelaunay)
    qh_fprintf(qh, fp, 9142, " upperDelaunay");
  if (facet->visible)
    qh_fprintf(qh, fp, 9143, " visible");
  if (facet->newfacet)
    qh_fprintf(qh, fp, 9144, " newfacet");
  if (facet->tested)
    qh_fprintf(qh, fp, 9145, " tested");
  if (!facet->good)
    qh_fprintf(qh, fp, 9146, " notG");
  if (facet->seen && qh->IStracing)
    qh_fprintf(qh, fp, 9147, " seen");
  if (facet->seen2 && qh->IStracing)
    qh_fprintf(qh, fp, 9418, " seen2");
  if (facet->isarea)
    qh_fprintf(qh, fp, 9419, " isarea");
  if (facet->coplanarhorizon)
    qh_fprintf(qh, fp, 9148, " coplanarhorizon");
  if (facet->mergehorizon)
    qh_fprintf(qh, fp, 9149, " mergehorizon");
  if (facet->cycledone)
    qh_fprintf(qh, fp, 9420, " cycledone");
  if (facet->keepcentrum)
    qh_fprintf(qh, fp, 9150, " keepcentrum");
  if (facet->dupridge)
    qh_fprintf(qh, fp, 9151, " dupridge");
  if (facet->mergeridge && !facet->mergeridge2)
    qh_fprintf(qh, fp, 9152, " mergeridge1");
  if (facet->mergeridge2)
    qh_fprintf(qh, fp, 9153, " mergeridge2");
  if (facet->newmerge)
    qh_fprintf(qh, fp, 9154, " newmerge");
  if (facet->flipped)
    qh_fprintf(qh, fp, 9155, " flipped");
  if (facet->notfurthest)
    qh_fprintf(qh, fp, 9156, " notfurthest");
  if (facet->degenerate)
    qh_fprintf(qh, fp, 9157, " degenerate");
  if (facet->redundant)
    qh_fprintf(qh, fp, 9158, " redundant");
  qh_fprintf(qh, fp, 9159, "\n");
  if (facet->isarea)
    qh_fprintf(qh, fp, 9160, "    - area: %2.2g\n", facet->f.area);
  else if (qh->NEWfacets && facet->visible && facet->f.replace)
    qh_fprintf(qh, fp, 9161, "    - replacement: f%d\n", facet->f.replace->id);
  else if (facet->newfacet) {
    if (facet->f.samecycle && facet->f.samecycle != facet)
      qh_fprintf(qh, fp, 9162, "    - shares same visible/horizon as f%d\n", facet->f.samecycle->id);
  }else if (facet->tricoplanar /* !isarea */) {
    if (facet->f.triowner)
      qh_fprintf(qh, fp, 9163, "    - owner of normal & centrum is facet f%d\n", facet->f.triowner->id);
  }else if (facet->f.newcycle)
    qh_fprintf(qh, fp, 9164, "    - was horizon to f%d\n", facet->f.newcycle->id);
  if (facet->nummerge == qh_MAXnummerge)
    qh_fprintf(qh, fp, 9427, "    - merges: %dmax\n", qh_MAXnummerge);
  else if (facet->nummerge)
    qh_fprintf(qh, fp, 9165, "    - merges: %d\n", facet->nummerge);
  qh_printpointid(qh, fp, "    - normal: ", qh->hull_dim, facet->normal, qh_IDunknown);
  qh_fprintf(qh, fp, 9166, "    - offset: %10.7g\n", facet->offset);
  if (qh->CENTERtype == qh_ASvoronoi || facet->center)
    qh_printcenter(qh, fp, qh_PRINTfacets, "    - center: ", facet);
#if qh_MAXoutside
  if (facet->maxoutside > qh->DISTround) /* initial value */
    qh_fprintf(qh, fp, 9167, "    - maxoutside: %10.7g\n", facet->maxoutside);
#endif
  if (!SETempty_(facet->outsideset)) {
    furthest= (pointT *)qh_setlast(facet->outsideset);
    if (qh_setsize(qh, facet->outsideset) < 6) {
      qh_fprintf(qh, fp, 9168, "    - outside set(furthest p%d):\n", qh_pointid(qh, furthest));
      FOREACHpoint_(facet->outsideset)
        qh_printpoint(qh, fp, "     ", point);
    }else if (qh_setsize(qh, facet->outsideset) < 21) {
      qh_printpoints(qh, fp, "    - outside set:", facet->outsideset);
    }else {
      qh_fprintf(qh, fp, 9169, "    - outside set:  %d points.", qh_setsize(qh, facet->outsideset));
      qh_printpoint(qh, fp, "  Furthest", furthest);
    }
#if !qh_COMPUTEfurthest
    qh_fprintf(qh, fp, 9170, "    - furthest distance= %2.2g\n", facet->furthestdist);
#endif
  }
  if (!SETempty_(facet->coplanarset)) {
    furthest= (pointT *)qh_setlast(facet->coplanarset);
    if (qh_setsize(qh, facet->coplanarset) < 6) {
      qh_fprintf(qh, fp, 9171, "    - coplanar set(furthest p%d):\n", qh_pointid(qh, furthest));
      FOREACHpoint_(facet->coplanarset)
        qh_printpoint(qh, fp, "     ", point);
    }else if (qh_setsize(qh, facet->coplanarset) < 21) {
      qh_printpoints(qh, fp, "    - coplanar set:", facet->coplanarset);
    }else {
      qh_fprintf(qh, fp, 9172, "    - coplanar set:  %d points.", qh_setsize(qh, facet->coplanarset));
      qh_printpoint(qh, fp, "  Furthest", furthest);
    }
    zinc_(Zdistio);
    qh_distplane(qh, furthest, facet, &dist);
    qh_fprintf(qh, fp, 9173, "      furthest distance= %2.2g\n", dist);
  }
  qh_printvertices(qh, fp, "    - vertices:", facet->vertices);
  qh_fprintf(qh, fp, 9174, "    - neighboring facets:");
  FOREACHneighbor_(facet) {
    if (neighbor == qh_MERGEridge)
      qh_fprintf(qh, fp, 9175, " MERGEridge");
    else if (neighbor == qh_DUPLICATEridge)
      qh_fprintf(qh, fp, 9176, " DUPLICATEridge");
    else
      qh_fprintf(qh, fp, 9177, " f%d", neighbor->id);
  }
  qh_fprintf(qh, fp, 9178, "\n");
  qh->RANDOMdist= qh->old_randomdist;
} /* printfacetheader */


/*---------------------------------

  qh_printfacetridges(qh, fp, facet )
    prints ridges of a facet to fp

  notes:
    ridges printed in neighbor order
    assumes the ridges exist
    for 'f' output
    same as QhullFacet::printRidges
*/
void qh_printfacetridges(qhT *qh, FILE *fp, facetT *facet) {
  facetT *neighbor, **neighborp;
  ridgeT *ridge, **ridgep;
  int numridges= 0;
  int n;

  if (facet->visible && qh->NEWfacets) {
    qh_fprintf(qh, fp, 9179, "    - ridges (tentative ids):");
    FOREACHridge_(facet->ridges)
      qh_fprintf(qh, fp, 9180, " r%d", ridge->id);
    qh_fprintf(qh, fp, 9181, "\n");
  }else {
    qh_fprintf(qh, fp, 9182, "    - ridges:\n");
    FOREACHridge_(facet->ridges)
      ridge->seen= False;
    if (qh->hull_dim == 3) {
      ridge= SETfirstt_(facet->ridges, ridgeT);
      while (ridge && !ridge->seen) {
        ridge->seen= True;
        qh_printridge(qh, fp, ridge);
        numridges++;
        ridge= qh_nextridge3d(ridge, facet, NULL);
        }
    }else {
      FOREACHneighbor_(facet) {
        FOREACHridge_(facet->ridges) {
          if (otherfacet_(ridge, facet) == neighbor && !ridge->seen) {
            ridge->seen= True;
            qh_printridge(qh, fp, ridge);
            numridges++;
          }
        }
      }
    }
    n= qh_setsize(qh, facet->ridges);
    if (n == 1 && facet->newfacet && qh->NEWtentative) {
      qh_fprintf(qh, fp, 9411, "     - horizon ridge to visible facet\n");
    }
    if (numridges != n) {
      qh_fprintf(qh, fp, 9183, "     - all ridges:");
      FOREACHridge_(facet->ridges)
        qh_fprintf(qh, fp, 9184, " r%d", ridge->id);
      qh_fprintf(qh, fp, 9185, "\n");
    }
    /* non-3d ridges w/o non-simplicial neighbors */
    FOREACHridge_(facet->ridges) {
      if (!ridge->seen)
        qh_printridge(qh, fp, ridge);
    }
  }
} /* printfacetridges */

/*---------------------------------

  qh_printfacets(qh, fp, format, facetlist, facets, printall )
    prints facetlist and/or facet set in output format

  notes:
    also used for specialized formats ('FO' and summary)
    turns off 'Rn' option since want actual numbers
*/
void qh_printfacets(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {
  int numfacets, numsimplicial, numridges, totneighbors, numcoplanars, numtricoplanars;
  facetT *facet, **facetp;
  setT *vertices;
  coordT *center;
  realT outerplane, innerplane;

  qh->old_randomdist= qh->RANDOMdist;
  qh->RANDOMdist= False;
  if (qh->CDDoutput && (format == qh_PRINTcentrums || format == qh_PRINTpointintersect || format == qh_PRINToff))
    qh_fprintf(qh, qh->ferr, 7056, "qhull warning: CDD format is not available for centrums, halfspace\nintersections, and OFF file format.\n");
  if (format == qh_PRINTnone)
    ; /* print nothing */
  else if (format == qh_PRINTaverage) {
    vertices= qh_facetvertices(qh, facetlist, facets, printall);
    center= qh_getcenter(qh, vertices);
    qh_fprintf(qh, fp, 9186, "%d 1\n", qh->hull_dim);
    qh_printpointid(qh, fp, NULL, qh->hull_dim, center, qh_IDunknown);
    qh_memfree(qh, center, qh->normal_size);
    qh_settempfree(qh, &vertices);
  }else if (format == qh_PRINTextremes) {
    if (qh->DELAUNAY)
      qh_printextremes_d(qh, fp, facetlist, facets, printall);
    else if (qh->hull_dim == 2)
      qh_printextremes_2d(qh, fp, facetlist, facets, printall);
    else
      qh_printextremes(qh, fp, facetlist, facets, printall);
  }else if (format == qh_PRINToptions)
    qh_fprintf(qh, fp, 9187, "Options selected for Qhull %s:\n%s\n", qh_version, qh->qhull_options);
  else if (format == qh_PRINTpoints && !qh->VORONOI)
    qh_printpoints_out(qh, fp, facetlist, facets, printall);
  else if (format == qh_PRINTqhull)
    qh_fprintf(qh, fp, 9188, "%s | %s\n", qh->rbox_command, qh->qhull_command);
  else if (format == qh_PRINTsize) {
    qh_fprintf(qh, fp, 9189, "0\n2 ");
    qh_fprintf(qh, fp, 9190, qh_REAL_1, qh->totarea);
    qh_fprintf(qh, fp, 9191, qh_REAL_1, qh->totvol);
    qh_fprintf(qh, fp, 9192, "\n");
  }else if (format == qh_PRINTsummary) {
    qh_countfacets(qh, facetlist, facets, printall, &numfacets, &numsimplicial,
      &totneighbors, &numridges, &numcoplanars, &numtricoplanars);
    vertices= qh_facetvertices(qh, facetlist, facets, printall);
    qh_fprintf(qh, fp, 9193, "10 %d %d %d %d %d %d %d %d %d %d\n2 ", qh->hull_dim,
                qh->num_points + qh_setsize(qh, qh->other_points),
                qh->num_vertices, qh->num_facets - qh->num_visible,
                qh_setsize(qh, vertices), numfacets, numcoplanars,
                numfacets - numsimplicial, zzval_(Zdelvertextot),
                numtricoplanars);
    qh_settempfree(qh, &vertices);
    qh_outerinner(qh, NULL, &outerplane, &innerplane);
    qh_fprintf(qh, fp, 9194, qh_REAL_2n, outerplane, innerplane);
  }else if (format == qh_PRINTvneighbors)
    qh_printvneighbors(qh, fp, facetlist, facets, printall);
  else if (qh->VORONOI && format == qh_PRINToff)
    qh_printvoronoi(qh, fp, format, facetlist, facets, printall);
  else if (qh->VORONOI && format == qh_PRINTgeom) {
    qh_printbegin(qh, fp, format, facetlist, facets, printall);
    qh_printvoronoi(qh, fp, format, facetlist, facets, printall);
    qh_printend(qh, fp, format, facetlist, facets, printall);
  }else if (qh->VORONOI
  && (format == qh_PRINTvertices || format == qh_PRINTinner || format == qh_PRINTouter))
    qh_printvdiagram(qh, fp, format, facetlist, facets, printall);
  else {
    qh_printbegin(qh, fp, format, facetlist, facets, printall);
    FORALLfacet_(facetlist)
      qh_printafacet(qh, fp, format, facet, printall);
    FOREACHfacet_(facets)
      qh_printafacet(qh, fp, format, facet, printall);
    qh_printend(qh, fp, format, facetlist, facets, printall);
  }
  qh->RANDOMdist= qh->old_randomdist;
} /* printfacets */


/*---------------------------------

  qh_printhyperplaneintersection(qh, fp, facet1, facet2, vertices, color )
    print Geomview OFF or 4OFF for the intersection of two hyperplanes in 3-d or 4-d
*/
void qh_printhyperplaneintersection(qhT *qh, FILE *fp, facetT *facet1, facetT *facet2,
                   setT *vertices, realT color[3]) {
  realT costheta, denominator, dist1, dist2, s, t, mindenom, p[4];
  vertexT *vertex, **vertexp;
  int i, k;
  boolT nearzero1, nearzero2;

  costheta= qh_getangle(qh, facet1->normal, facet2->normal);
  denominator= 1 - costheta * costheta;
  i= qh_setsize(qh, vertices);
  if (qh->hull_dim == 3)
    qh_fprintf(qh, fp, 9195, "VECT 1 %d 1 %d 1 ", i, i);
  else if (qh->hull_dim == 4 && qh->DROPdim >= 0)
    qh_fprintf(qh, fp, 9196, "OFF 3 1 1 ");
  else
    qh->printoutvar++;
  qh_fprintf(qh, fp, 9197, "# intersect f%d f%d\n", facet1->id, facet2->id);
  mindenom= 1 / (10.0 * qh->MAXabs_coord);
  FOREACHvertex_(vertices) {
    zadd_(Zdistio, 2);
    qh_distplane(qh, vertex->point, facet1, &dist1);
    qh_distplane(qh, vertex->point, facet2, &dist2);
    s= qh_divzero(-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(qh, p, p);
      qh_fprintf(qh, fp, 9198, "%8.4g %8.4g %8.4g # ", p[0], p[1], p[2]);
    }else
      qh_fprintf(qh, fp, 9199, "%8.4g %8.4g %8.4g %8.4g # ", p[0], p[1], p[2], p[3]);
    if (nearzero1+nearzero2)
      qh_fprintf(qh, fp, 9200, "p%d(coplanar facets)\n", qh_pointid(qh, vertex->point));
    else
      qh_fprintf(qh, fp, 9201, "projected p%d\n", qh_pointid(qh, vertex->point));
  }
  if (qh->hull_dim == 3)
    qh_fprintf(qh, fp, 9202, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
  else if (qh->hull_dim == 4 && qh->DROPdim >= 0)
    qh_fprintf(qh, fp, 9203, "3 0 1 2 %8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
} /* printhyperplaneintersection */

/*---------------------------------

  qh_printline3geom(qh, fp, pointA, pointB, color )
    prints a line as a VECT
    prints 0's for qh.DROPdim

  notes:
    if pointA == pointB,
      it's a 1 point VECT
*/
void qh_printline3geom(qhT *qh, FILE *fp, pointT *pointA, pointT *pointB, realT color[3]) {
  int k;
  realT pA[4], pB[4];

  qh_projectdim3(qh, pointA, pA);
  qh_projectdim3(qh, pointB, pB);
  if ((fabs(pA[0] - pB[0]) > 1e-3) ||
      (fabs(pA[1] - pB[1]) > 1e-3) ||
      (fabs(pA[2] - pB[2]) > 1e-3)) {
    qh_fprintf(qh, fp, 9204, "VECT 1 2 1 2 1\n");
    for (k=0; k < 3; k++)
       qh_fprintf(qh, fp, 9205, "%8.4g ", pB[k]);
    qh_fprintf(qh, fp, 9206, " # p%d\n", qh_pointid(qh, pointB));
  }else
    qh_fprintf(qh, fp, 9207, "VECT 1 1 1 1 1\n");
  for (k=0; k < 3; k++)
    qh_fprintf(qh, fp, 9208, "%8.4g ", pA[k]);
  qh_fprintf(qh, fp, 9209, " # p%d\n", qh_pointid(qh, pointA));
  qh_fprintf(qh, fp, 9210, "%8.4g %8.4g %8.4g 1\n", color[0], color[1], color[2]);
}

/*---------------------------------

  qh_printneighborhood(qh, fp, format, facetA, facetB, printall )
    print neighborhood of one or two facets

  notes:
    calls qh_findgood_all()
    bumps qh.visit_id
*/
void qh_printneighborhood(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetA, facetT *facetB, boolT printall) {
  facetT *neighbor, **neighborp, *facet;
  setT *facets;

  if (format == qh_PRINTnone)
    return;
  qh_findgood_all(qh, qh->facet_list);
  if (facetA == facetB)
    facetB= NULL;
  facets= qh_settemp(qh, 2*(qh_setsize(qh, facetA->neighbors)+1));
  qh->visit_id++;
  for (facet=facetA; facet; facet= ((facet == facetA) ? facetB : NULL)) {
    if (facet->visitid != qh->visit_id) {
      facet->visitid= qh->visit_id;
      qh_setappend(qh, &facets, facet);
    }
    FOREACHneighbor_(facet) {
      if (neighbor->visitid == qh->visit_id)
        continue;
      neighbor->visitid= qh->visit_id;
      if (printall || !qh_skipfacet(qh, neighbor))
        qh_setappend(qh, &facets, neighbor);
    }
  }
  qh_printfacets(qh, fp, format, NULL, facets, printall);
  qh_settempfree(qh, &facets);
} /* printneighborhood */

/*---------------------------------

  qh_printpoint(qh, fp, string, point )
  qh_printpointid(qh, fp, string, dim, point, id )
    prints the coordinates of a point

  returns:
    if string is defined
      prints 'string p%d'.  Skips p%d if id=qh_IDunknown(-1) or qh_IDnone(-3)

  notes:
    nop if point is NULL
    Same as QhullPoint's printPoint
*/
void qh_printpoint(qhT *qh, FILE *fp, const char *string, pointT *point) {
  int id= qh_pointid(qh, point);

  qh_printpointid(qh, fp, string, qh->hull_dim, point, id);
} /* printpoint */

void qh_printpointid(qhT *qh, FILE *fp, const char *string, int dim, pointT *point, int id) {
  int k;
  realT r; /*bug fix*/

  if (!point)
    return;
  if (string) {
    qh_fprintf(qh, fp, 9211, "%s", string);
    if (id != qh_IDunknown && id != qh_IDnone)
      qh_fprintf(qh, fp, 9212, " p%d: ", id);
  }
  for (k=dim; k--; ) {
    r= *point++;
    if (string)
      qh_fprintf(qh, fp, 9213, " %8.4g", r);
    else
      qh_fprintf(qh, fp, 9214, qh_REAL_1, r);
  }
  qh_fprintf(qh, fp, 9215, "\n");
} /* printpointid */

/*---------------------------------

  qh_printpoint3(qh, fp, point )
    prints 2-d, 3-d, or 4-d point as Geomview 3-d coordinates
*/
void qh_printpoint3(qhT *qh, FILE *fp, pointT *point) {
  int k;
  realT p[4];

  qh_projectdim3(qh, point, p);
  for (k=0; k < 3; k++)
    qh_fprintf(qh, fp, 9216, "%8.4g ", p[k]);
  qh_fprintf(qh, fp, 9217, " # p%d\n", qh_pointid(qh, point));
} /* printpoint3 */

/*----------------------------------------
-printpoints- print pointids for a set of points starting at index
   see geom_r.c
*/

/*---------------------------------

  qh_printpoints_out(qh, fp, facetlist, facets, printall )
    prints vertices, coplanar/inside points, for facets by their point coordinates
    allows qh.CDDoutput

  notes:
    same format as qhull input
    if no coplanar/interior points,
      same order as qh_printextremes
*/
void qh_printpoints_out(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall) {
  int allpoints= qh->num_points + qh_setsize(qh, qh->other_points);
  int numpoints=0, point_i, point_n;
  setT *vertices, *points;
  facetT *facet, **facetp;
  pointT *point, **pointp;
  vertexT *vertex, **vertexp;
  int id;

  points= qh_settemp(qh, allpoints);
  qh_setzero(qh, points, 0, allpoints);
  vertices= qh_facetvertices(qh, facetlist, facets, printall);
  FOREACHvertex_(vertices) {
    id= qh_pointid(qh, vertex->point);
    if (id >= 0)
      SETelem_(points, id)= vertex->point;
  }
  if (qh->KEEPinside || qh->KEEPcoplanar || qh->KEEPnearinside) {
    FORALLfacet_(facetlist) {
      if (!printall && qh_skipfacet(qh, facet))
        continue;
      FOREACHpoint_(facet->coplanarset) {
        id= qh_pointid(qh, point);
        if (id >= 0)
          SETelem_(points, id)= point;
      }
    }
    FOREACHfacet_(facets) {
      if (!printall && qh_skipfacet(qh, facet))
        continue;
      FOREACHpoint_(facet->coplanarset) {
        id= qh_pointid(qh, point);
        if (id >= 0)
          SETelem_(points, id)= point;
      }
    }
  }
  qh_settempfree(qh, &vertices);
  FOREACHpoint_i_(qh, points) {
    if (point)
      numpoints++;
  }
  if (qh->CDDoutput)
    qh_fprintf(qh, fp, 9218, "%s | %s\nbegin\n%d %d real\n", qh->rbox_command,
             qh->qhull_command, numpoints, qh->hull_dim + 1);
  else
    qh_fprintf(qh, fp, 9219, "%d\n%d\n", qh->hull_dim, numpoints);
  FOREACHpoint_i_(qh, points) {
    if (point) {
      if (qh->CDDoutput)
        qh_fprintf(qh, fp, 9220, "1 ");
      qh_printpoint(qh, fp, NULL, point);
    }
  }
  if (qh->CDDoutput)
    qh_fprintf(qh, fp, 9221, "end\n");
  qh_settempfree(qh, &points);
} /* printpoints_out */


/*---------------------------------

  qh_printpointvect(qh, fp, point, normal, center, radius, color )
    prints a 2-d, 3-d, or 4-d point as 3-d VECT's relative to normal or to center point
*/
void qh_printpointvect(qhT *qh, FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius, realT color[3]) {
  realT diff[4], pointA[4];
  int k;

  for (k=qh->hull_dim; k--; ) {
    if (center)
      diff[k]= point[k]-center[k];
    else if (normal)
      diff[k]= normal[k];
    else
      diff[k]= 0;
  }
  if (center)
    qh_normalize2(qh, diff, qh->hull_dim, True, NULL, NULL);
  for (k=qh->hull_dim; k--; )
    pointA[k]= point[k]+diff[k] * radius;
  qh_printline3geom(qh, fp, point, pointA, color);
} /* printpointvect */

/*---------------------------------

  qh_printpointvect2(qh, fp, point, normal, center, radius )
    prints a 2-d, 3-d, or 4-d point as 2 3-d VECT's for an imprecise point
*/
void qh_printpointvect2(qhT *qh, FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius) {
  realT red[3]={1, 0, 0}, yellow[3]={1, 1, 0};

  qh_printpointvect(qh, fp, point, normal, center, radius, red);
  qh_printpointvect(qh, fp, point, normal, center, -radius, yellow);
} /* printpointvect2 */

/*---------------------------------

  qh_printridge(qh, fp, ridge )
    prints the information in a ridge

  notes:
    for qh_printfacetridges()
    same as operator<< [QhullRidge.cpp]
*/
void qh_printridge(qhT *qh, FILE *fp, ridgeT *ridge) {

  qh_fprintf(qh, fp, 9222, "     - r%d", ridge->id);
  if (ridge->tested)
    qh_fprintf(qh, fp, 9223, " tested");
  if (ridge->nonconvex)
    qh_fprintf(qh, fp, 9224, " nonconvex");
  if (ridge->mergevertex)
    qh_fprintf(qh, fp, 9421, " mergevertex");
  if (ridge->mergevertex2)
    qh_fprintf(qh, fp, 9422, " mergevertex2");
  if (ridge->simplicialtop)
    qh_fprintf(qh, fp, 9425, " simplicialtop");
  if (ridge->simplicialbot)
    qh_fprintf(qh, fp, 9423, " simplicialbot");
  qh_fprintf(qh, fp, 9225, "\n");
  qh_printvertices(qh, fp, "           vertices:", ridge->vertices);
  if (ridge->top && ridge->bottom)
    qh_fprintf(qh, fp, 9226, "           between f%d and f%d\n",
            ridge->top->id, ridge->bottom->id);
} /* printridge */

/*---------------------------------

  qh_printspheres(qh, fp, vertices, radius )
    prints 3-d vertices as OFF spheres

  notes:
    inflated octahedron from Stuart Levy earth/mksphere2
*/
void qh_printspheres(qhT *qh, FILE *fp, setT *vertices, realT radius) {
  vertexT *vertex, **vertexp;

  qh->printoutnum++;
  qh_fprintf(qh, fp, 9227, "{appearance {-edge -normal normscale 0} {\n\
INST geom {define vsphere OFF\n\
18 32 48\n\
\n\
0 0 1\n\
1 0 0\n\
0 1 0\n\
-1 0 0\n\
0 -1 0\n\
0 0 -1\n\
0.707107 0 0.707107\n\
0 -0.707107 0.707107\n\
0.707107 -0.707107 0\n\
-0.707107 0 0.707107\n\
-0.707107 -0.707107 0\n\
0 0.707107 0.707107\n\
-0.707107 0.707107 0\n\
0.707107 0.707107 0\n\
0.707107 0 -0.707107\n\
0 0.707107 -0.707107\n\
-0.707107 0 -0.707107\n\
0 -0.707107 -0.707107\n\
\n\
3 0 6 11\n\
3 0 7 6 \n\
3 0 9 7 \n\
3 0 11 9\n\
3 1 6 8 \n\
3 1 8 14\n\
3 1 13 6\n\
3 1 14 13\n\
3 2 11 13\n\
3 2 12 11\n\
3 2 13 15\n\
3 2 15 12\n\
3 3 9 12\n\
3 3 10 9\n\
3 3 12 16\n\
3 3 16 10\n\
3 4 7 10\n\
3 4 8 7\n\
3 4 10 17\n\
3 4 17 8\n\
3 5 14 17\n\
3 5 15 14\n\
3 5 16 15\n\
3 5 17 16\n\
3 6 13 11\n\
3 7 8 6\n\
3 9 10 7\n\
3 11 12 9\n\
3 14 8 17\n\
3 15 13 14\n\
3 16 12 15\n\
3 17 10 16\n} transforms { TLIST\n");
  FOREACHvertex_(vertices) {
    qh_fprintf(qh, fp, 9228, "%8.4g 0 0 0 # v%d\n 0 %8.4g 0 0\n0 0 %8.4g 0\n",
      radius, vertex->id, radius, radius);
    qh_printpoint3(qh, fp, vertex->point);
    qh_fprintf(qh, fp, 9229, "1\n");
  }
  qh_fprintf(qh, fp, 9230, "}}}\n");
} /* printspheres */


/*----------------------------------------------
-printsummary-
                see libqhull_r.c
*/

/*---------------------------------

  qh_printvdiagram(qh, fp, format, facetlist, facets, printall )
    print voronoi diagram
      # of pairs of input sites
      #indices site1 site2 vertex1 ...

    sites indexed by input point id
      point 0 is the first input point
    vertices indexed by 'o' and 'p' order
      vertex 0 is the 'vertex-at-infinity'
      vertex 1 is the first Voronoi vertex

  see:
    qh_printvoronoi()
    qh_eachvoronoi_all()

  notes:
    if all facets are upperdelaunay,
      prints upper hull (furthest-site Voronoi diagram)
*/
void qh_printvdiagram(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {
  setT *vertices;
  int totcount, numcenters;
  boolT isLower;
  qh_RIDGE innerouter= qh_RIDGEall;
  printvridgeT printvridge= NULL;

  if (format == qh_PRINTvertices) {
    innerouter= qh_RIDGEall;
    printvridge= qh_printvridge;
  }else if (format == qh_PRINTinner) {
    innerouter= qh_RIDGEinner;
    printvridge= qh_printvnorm;
  }else if (format == qh_PRINTouter) {
    innerouter= qh_RIDGEouter;
    printvridge= qh_printvnorm;
  }else {
    qh_fprintf(qh, qh->ferr, 6219, "qhull internal error (qh_printvdiagram): unknown print format %d.\n", format);
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  vertices= qh_markvoronoi(qh, facetlist, facets, printall, &isLower, &numcenters);
  totcount= qh_printvdiagram2(qh, NULL, NULL, vertices, innerouter, False);
  qh_fprintf(qh, fp, 9231, "%d\n", totcount);
  totcount= qh_printvdiagram2(qh, fp, printvridge, vertices, innerouter, True /* inorder*/);
  qh_settempfree(qh, &vertices);
#if 0  /* for testing qh_eachvoronoi_all */
  qh_fprintf(qh, fp, 9232, "\n");
  totcount= qh_eachvoronoi_all(qh, fp, printvridge, qh->UPPERdelaunay, innerouter, True /* inorder*/);
  qh_fprintf(qh, fp, 9233, "%d\n", totcount);
#endif
} /* printvdiagram */

/*---------------------------------

  qh_printvdiagram2(qh, fp, printvridge, vertices, innerouter, inorder )
    visit all pairs of input sites (vertices) for selected Voronoi vertices
    vertices may include NULLs

  innerouter:
    qh_RIDGEall   print inner ridges(bounded) and outer ridges(unbounded)
    qh_RIDGEinner print only inner ridges
    qh_RIDGEouter print only outer ridges

  inorder:
    print 3-d Voronoi vertices in order

  assumes:
    qh_markvoronoi marked facet->visitid for Voronoi vertices
    all facet->seen= False
    all facet->seen2= True

  returns:
    total number of Voronoi ridges
    if printvridge,
      calls printvridge( fp, vertex, vertexA, centers) for each ridge
      [see qh_eachvoronoi()]

  see:
    qh_eachvoronoi_all()
*/
int qh_printvdiagram2(qhT *qh, FILE *fp, printvridgeT printvridge, setT *vertices, qh_RIDGE innerouter, boolT inorder) {
  int totcount= 0;
  int vertex_i, vertex_n;
  vertexT *vertex;

  FORALLvertices
    vertex->seen= False;
  FOREACHvertex_i_(qh, vertices) {
    if (vertex) {
      if (qh->GOODvertex > 0 && qh_pointid(qh, vertex->point)+1 != qh->GOODvertex)
        continue;
      totcount += qh_eachvoronoi(qh, fp, printvridge, vertex, !qh_ALL, innerouter, inorder);
    }
  }
  return totcount;
} /* printvdiagram2 */

/*---------------------------------

  qh_printvertex(qh, fp, vertex )
    prints the information in a vertex
    Duplicated as operator<< [QhullVertex.cpp]
*/
void qh_printvertex(qhT *qh, FILE *fp, vertexT *vertex) {
  pointT *point;
  int k, count= 0;
  facetT *neighbor, **neighborp;
  realT r; /*bug fix*/

  if (!vertex) {
    qh_fprintf(qh, fp, 9234, "  NULLvertex\n");
    return;
  }
  qh_fprintf(qh, fp, 9235, "- p%d(v%d):", qh_pointid(qh, vertex->point), vertex->id);
  point= vertex->point;
  if (point) {
    for (k=qh->hull_dim; k--; ) {
      r= *point++;
      qh_fprintf(qh, fp, 9236, " %5.2g", r);
    }
  }
  if (vertex->deleted)
    qh_fprintf(qh, fp, 9237, " deleted");
  if (vertex->delridge)
    qh_fprintf(qh, fp, 9238, " delridge");
  if (vertex->newfacet)
    qh_fprintf(qh, fp, 9415, " newfacet");
  if (vertex->seen && qh->IStracing)
    qh_fprintf(qh, fp, 9416, " seen");
  if (vertex->seen2 && qh->IStracing)
    qh_fprintf(qh, fp, 9417, " seen2");
  qh_fprintf(qh, fp, 9239, "\n");
  if (vertex->neighbors) {
    qh_fprintf(qh, fp, 9240, "  neighbors:");
    FOREACHneighbor_(vertex) {
      if (++count % 100 == 0)
        qh_fprintf(qh, fp, 9241, "\n     ");
      qh_fprintf(qh, fp, 9242, " f%d", neighbor->id);
    }
    qh_fprintf(qh, fp, 9243, "\n");
  }
} /* printvertex */


/*---------------------------------

  qh_printvertexlist(qh, fp, string, facetlist, facets, printall )
    prints vertices used by a facetlist or facet set
    tests qh_skipfacet() if !printall
*/
void qh_printvertexlist(qhT *qh, FILE *fp, const char* string, facetT *facetlist,
                         setT *facets, boolT printall) {
  vertexT *vertex, **vertexp;
  setT *vertices;

  vertices= qh_facetvertices(qh, facetlist, facets, printall);
  qh_fprintf(qh, fp, 9244, "%s", string);
  FOREACHvertex_(vertices)
    qh_printvertex(qh, fp, vertex);
  qh_settempfree(qh, &vertices);
} /* printvertexlist */


/*---------------------------------

  qh_printvertices(qh, fp, string, vertices )
    prints vertices in a set
    duplicated as printVertexSet [QhullVertex.cpp]
*/
void qh_printvertices(qhT *qh, FILE *fp, const char* string, setT *vertices) {
  vertexT *vertex, **vertexp;

  qh_fprintf(qh, fp, 9245, "%s", string);
  FOREACHvertex_(vertices)
    qh_fprintf(qh, fp, 9246, " p%d(v%d)", qh_pointid(qh, vertex->point), vertex->id);
  qh_fprintf(qh, fp, 9247, "\n");
} /* printvertices */

/*---------------------------------

  qh_printvneighbors(qh, fp, facetlist, facets, printall )
    print vertex neighbors of vertices in facetlist and facets ('FN')

  notes:
    qh_countfacets clears facet->visitid for non-printed facets

  design:
    collect facet count and related statistics
    if necessary, build neighbor sets for each vertex
    collect vertices in facetlist and facets
    build a point array for point->vertex and point->coplanar facet
    for each point
      list vertex neighbors or coplanar facet
*/
void qh_printvneighbors(qhT *qh, FILE *fp, facetT* facetlist, setT *facets, boolT printall) {
  int numfacets, numsimplicial, numridges, totneighbors, numneighbors, numcoplanars, numtricoplanars;
  setT *vertices, *vertex_points, *coplanar_points;
  int numpoints= qh->num_points + qh_setsize(qh, qh->other_points);
  vertexT *vertex, **vertexp;
  int vertex_i, vertex_n;
  facetT *facet, **facetp, *neighbor, **neighborp;
  pointT *point, **pointp;

  qh_countfacets(qh, facetlist, facets, printall, &numfacets, &numsimplicial,
      &totneighbors, &numridges, &numcoplanars, &numtricoplanars);  /* sets facet->visitid */
  qh_fprintf(qh, fp, 9248, "%d\n", numpoints);
  qh_vertexneighbors(qh);
  vertices= qh_facetvertices(qh, facetlist, facets, printall);
  vertex_points= qh_settemp(qh, numpoints);
  coplanar_points= qh_settemp(qh, numpoints);
  qh_setzero(qh, vertex_points, 0, numpoints);
  qh_setzero(qh, coplanar_points, 0, numpoints);
  FOREACHvertex_(vertices)
    qh_point_add(qh, vertex_points, vertex->point, vertex);
  FORALLfacet_(facetlist) {
    FOREACHpoint_(facet->coplanarset)
      qh_point_add(qh, coplanar_points, point, facet);
  }
  FOREACHfacet_(facets) {
    FOREACHpoint_(facet->coplanarset)
      qh_point_add(qh, coplanar_points, point, facet);
  }
  FOREACHvertex_i_(qh, vertex_points) {
    if (vertex) {
      numneighbors= qh_setsize(qh, vertex->neighbors);
      qh_fprintf(qh, fp, 9249, "%d", numneighbors);
      qh_order_vertexneighbors(qh, vertex);
      FOREACHneighbor_(vertex)
        qh_fprintf(qh, fp, 9250, " %d",
                 neighbor->visitid ? neighbor->visitid - 1 : 0 - neighbor->id);
      qh_fprintf(qh, fp, 9251, "\n");
    }else if ((facet= SETelemt_(coplanar_points, vertex_i, facetT)))
      qh_fprintf(qh, fp, 9252, "1 %d\n",
                  facet->visitid ? facet->visitid - 1 : 0 - facet->id);
    else
      qh_fprintf(qh, fp, 9253, "0\n");
  }
  qh_settempfree(qh, &coplanar_points);
  qh_settempfree(qh, &vertex_points);
  qh_settempfree(qh, &vertices);
} /* printvneighbors */

/*---------------------------------

  qh_printvoronoi(qh, fp, format, facetlist, facets, printall )
    print voronoi diagram in 'o' or 'G' format
    for 'o' format
      prints voronoi centers for each facet and for infinity
      for each vertex, lists ids of printed facets or infinity
      assumes facetlist and facets are disjoint
    for 'G' format
      prints an OFF object
      adds a 0 coordinate to center
      prints infinity but does not list in vertices

  see:
    qh_printvdiagram()

  notes:
    if 'o',
      prints a line for each point except "at-infinity"
    if all facets are upperdelaunay,
      reverses lower and upper hull
*/
void qh_printvoronoi(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {
  int k, numcenters, numvertices= 0, numneighbors, numinf, vid=1, vertex_i, vertex_n;
  facetT *facet, **facetp, *neighbor, **neighborp;
  setT *vertices;
  vertexT *vertex;
  boolT isLower;
  unsigned int numfacets= (unsigned int)qh->num_facets;

  vertices= qh_markvoronoi(qh, facetlist, facets, printall, &isLower, &numcenters);
  FOREACHvertex_i_(qh, vertices) {
    if (vertex) {
      numvertices++;
      numneighbors= numinf= 0;
      FOREACHneighbor_(vertex) {
        if (neighbor->visitid == 0)
          numinf= 1;
        else if (neighbor->visitid < numfacets)
          numneighbors++;
      }
      if (numinf && !numneighbors) {
        SETelem_(vertices, vertex_i)= NULL;
        numvertices--;
      }
    }
  }
  if (format == qh_PRINTgeom)
    qh_fprintf(qh, fp, 9254, "{appearance {+edge -face} OFF %d %d 1 # Voronoi centers and cells\n",
                numcenters, numvertices);
  else
    qh_fprintf(qh, fp, 9255, "%d\n%d %d 1\n", qh->hull_dim-1, numcenters, qh_setsize(qh, vertices));
  if (format == qh_PRINTgeom) {
    for (k=qh->hull_dim-1; k--; )
      qh_fprintf(qh, fp, 9256, qh_REAL_1, 0.0);
    qh_fprintf(qh, fp, 9257, " 0 # infinity not used\n");
  }else {
    for (k=qh->hull_dim-1; k--; )
      qh_fprintf(qh, fp, 9258, qh_REAL_1, qh_INFINITE);
    qh_fprintf(qh, fp, 9259, "\n");
  }
  FORALLfacet_(facetlist) {
    if (facet->visitid && facet->visitid < numfacets) {
      if (format == qh_PRINTgeom)
        qh_fprintf(qh, fp, 9260, "# %d f%d\n", vid++, facet->id);
      qh_printcenter(qh, fp, format, NULL, facet);
    }
  }
  FOREACHfacet_(facets) {
    if (facet->visitid && facet->visitid < numfacets) {
      if (format == qh_PRINTgeom)
        qh_fprintf(qh, fp, 9261, "# %d f%d\n", vid++, facet->id);
      qh_printcenter(qh, fp, format, NULL, facet);
    }
  }
  FOREACHvertex_i_(qh, vertices) {
    numneighbors= 0;
    numinf=0;
    if (vertex) {
      qh_order_vertexneighbors(qh, vertex);
      FOREACHneighbor_(vertex) {
        if (neighbor->visitid == 0)
          numinf= 1;
        else if (neighbor->visitid < numfacets)
          numneighbors++;
      }
    }
    if (format == qh_PRINTgeom) {
      if (vertex) {
        qh_fprintf(qh, fp, 9262, "%d", numneighbors);
        FOREACHneighbor_(vertex) {
          if (neighbor->visitid && neighbor->visitid < numfacets)
            qh_fprintf(qh, fp, 9263, " %d", neighbor->visitid);
        }
        qh_fprintf(qh, fp, 9264, " # p%d(v%d)\n", vertex_i, vertex->id);
      }else
        qh_fprintf(qh, fp, 9265, " # p%d is coplanar or isolated\n", vertex_i);
    }else {
      if (numinf)
        numneighbors++;
      qh_fprintf(qh, fp, 9266, "%d", numneighbors);
      if (vertex) {
        FOREACHneighbor_(vertex) {
          if (neighbor->visitid == 0) {
            if (numinf) {
              numinf= 0;
              qh_fprintf(qh, fp, 9267, " %d", neighbor->visitid);
            }
          }else if (neighbor->visitid < numfacets)
            qh_fprintf(qh, fp, 9268, " %d", neighbor->visitid);
        }
      }
      qh_fprintf(qh, fp, 9269, "\n");
    }
  }
  if (format == qh_PRINTgeom)
    qh_fprintf(qh, fp, 9270, "}\n");
  qh_settempfree(qh, &vertices);
} /* printvoronoi */

/*---------------------------------

  qh_printvnorm(qh, fp, vertex, vertexA, centers, unbounded )
    print one separating plane of the Voronoi diagram for a pair of input sites
    unbounded==True if centers includes vertex-at-infinity

  assumes:
    qh_ASvoronoi and qh_vertexneighbors() already set

  note:
    parameter unbounded is UNUSED by this callback

  see:
    qh_printvdiagram()
    qh_eachvoronoi()
*/
void qh_printvnorm(qhT *qh, FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {
  pointT *normal;
  realT offset;
  int k;
  QHULL_UNUSED(unbounded);

  normal= qh_detvnorm(qh, vertex, vertexA, centers, &offset);
  qh_fprintf(qh, fp, 9271, "%d %d %d ",
      2+qh->hull_dim, qh_pointid(qh, vertex->point), qh_pointid(qh, vertexA->point));
  for (k=0; k< qh->hull_dim-1; k++)
    qh_fprintf(qh, fp, 9272, qh_REAL_1, normal[k]);
  qh_fprintf(qh, fp, 9273, qh_REAL_1, offset);
  qh_fprintf(qh, fp, 9274, "\n");
} /* printvnorm */

/*---------------------------------

  qh_printvridge(qh, fp, vertex, vertexA, centers, unbounded )
    print one ridge of the Voronoi diagram for a pair of input sites
    unbounded==True if centers includes vertex-at-infinity

  see:
    qh_printvdiagram()

  notes:
    the user may use a different function
    parameter unbounded is UNUSED
*/
void qh_printvridge(qhT *qh, FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {
  facetT *facet, **facetp;
  QHULL_UNUSED(unbounded);

  qh_fprintf(qh, fp, 9275, "%d %d %d", qh_setsize(qh, centers)+2,
       qh_pointid(qh, vertex->point), qh_pointid(qh, vertexA->point));
  FOREACHfacet_(centers)
    qh_fprintf(qh, fp, 9276, " %d", facet->visitid);
  qh_fprintf(qh, fp, 9277, "\n");
} /* printvridge */

/*---------------------------------

  qh_projectdim3(qh, source, destination )
    project 2-d 3-d or 4-d point to a 3-d point
    uses qh.DROPdim and qh.hull_dim
    source and destination may be the same

  notes:
    allocate 4 elements to destination just in case
*/
void qh_projectdim3(qhT *qh, pointT *source, pointT *destination) {
  int i,k;

  for (k=0, i=0; k < qh->hull_dim; k++) {
    if (qh->hull_dim == 4) {
      if (k != qh->DROPdim)
        destination[i++]= source[k];
    }else if (k == qh->DROPdim)
      destination[i++]= 0;
    else
      destination[i++]= source[k];
  }
  while (i < 3)
    destination[i++]= 0.0;
} /* projectdim3 */

/*---------------------------------

  qh_readfeasible(qh, dim, curline )
    read feasible point from current line and qh.fin

  returns:
    number of lines read from qh.fin
    sets qh.feasible_point with malloc'd coordinates

  notes:
    checks for qh.HALFspace
    assumes dim > 1

  see:
    qh_setfeasible
*/
int qh_readfeasible(qhT *qh, int dim, const char *curline) {
  boolT isfirst= True;
  int linecount= 0, tokcount= 0;
  const char *s;
  char *t, firstline[qh_MAXfirst+1];
  coordT *coords, value;

  if (!qh->HALFspace) {
    qh_fprintf(qh, qh->ferr, 6070, "qhull input error: feasible point(dim 1 coords) is only valid for halfspace intersection\n");
    qh_errexit(qh, qh_ERRinput, NULL, NULL);
  }
  if (qh->feasible_string)
    qh_fprintf(qh, qh->ferr, 7057, "qhull input warning: feasible point(dim 1 coords) overrides 'Hn,n,n' feasible point for halfspace intersection\n");
  if (!(qh->feasible_point= (coordT *)qh_malloc((size_t)dim * sizeof(coordT)))) {
    qh_fprintf(qh, qh->ferr, 6071, "qhull error: insufficient memory for feasible point\n");
    qh_errexit(qh, qh_ERRmem, NULL, NULL);
  }
  coords= qh->feasible_point;
  while ((s= (isfirst ?  curline : fgets(firstline, qh_MAXfirst, qh->fin)))) {
    if (isfirst)
      isfirst= False;
    else
      linecount++;
    while (*s) {
      while (isspace(*s))
        s++;
      value= qh_strtod(s, &t);
      if (s == t)
        break;
      s= t;
      *(coords++)= value;
      if (++tokcount == dim) {
        while (isspace(*s))
          s++;
        qh_strtod(s, &t);
        if (s != t) {
          qh_fprintf(qh, qh->ferr, 6072, "qhull input error: coordinates for feasible point do not finish out the line: %s\n",
               s);
          qh_errexit(qh, qh_ERRinput, NULL, NULL);
        }
        return linecount;
      }
    }
  }
  qh_fprintf(qh, qh->ferr, 6073, "qhull input error: only %d coordinates.  Could not read %d-d feasible point.\n",
           tokcount, dim);
  qh_errexit(qh, qh_ERRinput, NULL, NULL);
  return 0;
} /* readfeasible */

/*---------------------------------

  qh_readpoints(qh, numpoints, dimension, ismalloc )
    read points from qh.fin into qh.first_point, qh.num_points
    qh.fin is lines of coordinates, one per vertex, first line number of points
    if 'rbox D4',
      gives message
    if qh.ATinfinity,
      adds point-at-infinity for Delaunay triangulations

  returns:
    number of points, array of point coordinates, dimension, ismalloc True
    if qh.DELAUNAY & !qh.PROJECTinput, projects points to paraboloid
        and clears qh.PROJECTdelaunay
    if qh.HALFspace, reads optional feasible point, reads halfspaces,
        converts to dual.

  for feasible point in "cdd format" in 3-d:
    3 1
    coordinates
    comments
    begin
    n 4 real/integer
    ...
    end

  notes:
    dimension will change in qh_initqhull_globals if qh.PROJECTinput
    uses malloc() since qh_mem not initialized
    QH11012 FIX: qh_readpoints needs rewriting, too long
*/
coordT *qh_readpoints(qhT *qh, int *numpoints, int *dimension, boolT *ismalloc) {
  coordT *points, *coords, *infinity= NULL;
  realT paraboloid, maxboloid= -REALmax, value;
  realT *coordp= NULL, *offsetp= NULL, *normalp= NULL;
  char *s= 0, *t, firstline[qh_MAXfirst+1];
  int diminput=0, numinput=0, dimfeasible= 0, newnum, k, tempi;
  int firsttext=0, firstshort=0, firstlong=0, firstpoint=0;
  int tokcount= 0, linecount=0, maxcount, coordcount=0;
  boolT islong, isfirst= True, wasbegin= False;
  boolT isdelaunay= qh->DELAUNAY && !qh->PROJECTinput;

  if (qh->CDDinput) {
    while ((s= fgets(firstline, qh_MAXfirst, qh->fin))) {
      linecount++;
      if (qh->HALFspace && linecount == 1 && isdigit(*s)) {
        dimfeasible= qh_strtol(s, &s);
        while (isspace(*s))
          s++;
        if (qh_strtol(s, &s) == 1)
          linecount += qh_readfeasible(qh, dimfeasible, s);
        else
          dimfeasible= 0;
      }else if (!memcmp(firstline, "begin", (size_t)5) || !memcmp(firstline, "BEGIN", (size_t)5))
        break;
      else if (!*qh->rbox_command)
        strncat(qh->rbox_command, s, sizeof(qh->rbox_command)-1);
    }
    if (!s) {
      qh_fprintf(qh, qh->ferr, 6074, "qhull input error: missing \"begin\" for cdd-formated input\n");
      qh_errexit(qh, qh_ERRinput, NULL, NULL);
    }
  }
  while (!numinput && (s= fgets(firstline, qh_MAXfirst, qh->fin))) {
    linecount++;
    if (!memcmp(s, "begin", (size_t)5) || !memcmp(s, "BEGIN", (size_t)5))
      wasbegin= True;
    while (*s) {
      while (isspace(*s))
        s++;
      if (!*s)
        break;
      if (!isdigit(*s)) {
        if (!*qh->rbox_command) {
          strncat(qh->rbox_command, s, sizeof(qh->rbox_command)-1);
          firsttext= linecount;
        }
        break;
      }
      if (!diminput)
        diminput= qh_strtol(s, &s);
      else {
        numinput= qh_strtol(s, &s);
        if (numinput == 1 && diminput >= 2 && qh->HALFspace && !qh->CDDinput) {
          linecount += qh_readfeasible(qh, diminput, s); /* checks if ok */
          dimfeasible= diminput;
          diminput= numinput= 0;
        }else
          break;
      }
    }
  }
  if (!s) {
    qh_fprintf(qh, qh->ferr, 6075, "qhull input error: short input file.  Did not find dimension and number of points\n");
    qh_errexit(qh, qh_ERRinput, NULL, NULL);
  }
  if (diminput > numinput) {
    tempi= diminput;    /* exchange dim and n, e.g., for cdd input format */
    diminput= numinput;
    numinput= tempi;
  }
  if (diminput < 2) {
    qh_fprintf(qh, qh->ferr, 6220, "qhull input error: dimension %d (first or smaller number) should be at least 2\n",
            diminput);
    qh_errexit(qh, qh_ERRinput, NULL, NULL);
  }
  if (numinput < 1 || numinput > qh_POINTSmax) {
    qh_fprintf(qh, qh->ferr, 6411, "qhull input error: expecting between 1 and %d points.  Got %d %d-d points\n",
      qh_POINTSmax, numinput, diminput);
    qh_errexit(qh, qh_ERRinput, NULL, NULL);
    /* same error message in qh_initqhull_globals */
  }

  if (isdelaunay && qh->HALFspace) {
    qh_fprintf(qh, qh->ferr, 6037, "qhull option error (qh_readpoints): can not use Delaunay('d') or Voronoi('v') with halfspace intersection('H')\n");
    qh_errexit(qh, qh_ERRinput, NULL, NULL);
    /* otherwise corrupted memory allocations, same error message as in qh_initqhull_globals */
  }else if (isdelaunay) {
    qh->PROJECTdelaunay= False;
    if (qh->CDDinput)
      *dimension= diminput;
    else
      *dimension= diminput+1;
    *numpoints= numinput;
    if (qh->ATinfinity)
      (*numpoints)++;
  }else if (qh->HALFspace) {
    *dimension= diminput - 1;
    *numpoints= numinput;
    if (diminput < 3) {
      qh_fprintf(qh, qh->ferr, 6221, "qhull input error: dimension %d (first number, includes offset) should be at least 3 for halfspaces\n",
            diminput);
      qh_errexit(qh, qh_ERRinput, NULL, NULL);
    }
    if (dimfeasible) {
      if (dimfeasible != *dimension) {
        qh_fprintf(qh, qh->ferr, 6222, "qhull input error: dimension %d of feasible point is not one less than dimension %d for halfspaces\n",
          dimfeasible, diminput);
        qh_errexit(qh, qh_ERRinput, NULL, NULL);
      }
    }else
      qh_setfeasible(qh, *dimension);
  }else {
    if (qh->CDDinput)
      *dimension= diminput-1;
    else
      *dimension= diminput;
    *numpoints= numinput;
  }
  qh->normal_size= *dimension * (int)sizeof(coordT); /* for tracing with qh_printpoint */
  if (qh->HALFspace) {
    qh->half_space= coordp= (coordT *)qh_malloc((size_t)qh->normal_size + sizeof(coordT));
    if (qh->CDDinput) {
      offsetp= qh->half_space;
      normalp= offsetp + 1;
    }else {
      normalp= qh->half_space;
      offsetp= normalp + *dimension;
    }
  }
  qh->maxline= diminput * (qh_REALdigits + 5);
  maximize_(qh->maxline, 500);
  qh->line= (char *)qh_malloc((size_t)(qh->maxline+1) * sizeof(char));
  *ismalloc= True;  /* use malloc since memory not setup */
  coords= points= qh->temp_malloc=  /* numinput and diminput >=2 by QH6220 */
        (coordT *)qh_malloc((size_t)((*numpoints)*(*dimension))*sizeof(coordT));
  if (!coords || !qh->line || (qh->HALFspace && !qh->half_space)) {
    qh_fprintf(qh, qh->ferr, 6076, "qhull error: insufficient memory to read %d points\n",
            numinput);
    qh_errexit(qh, qh_ERRmem, NULL, NULL);
  }
  if (isdelaunay && qh->ATinfinity) {
    infinity= points + numinput * (*dimension);
    for (k= (*dimension) - 1; k--; )
      infinity[k]= 0.0;
  }
  maxcount= numinput * diminput;
  paraboloid= 0.0;
  while ((s= (isfirst ?  s : fgets(qh->line, qh->maxline, qh->fin)))) {
    if (!isfirst) {
      linecount++;
      if (*s == 'e' || *s == 'E') {
        if (!memcmp(s, "end", (size_t)3) || !memcmp(s, "END", (size_t)3)) {
          if (qh->CDDinput )
            break;
          else if (wasbegin)
            qh_fprintf(qh, qh->ferr, 7058, "qhull input warning: the input appears to be in cdd format.  If so, use 'Fd'\n");
        }
      }
    }
    islong= False;
    while (*s) {
      while (isspace(*s))
        s++;
      value= qh_strtod(s, &t);
      if (s == t) {
        if (!*qh->rbox_command)
         strncat(qh->rbox_command, s, sizeof(qh->rbox_command)-1);
        if (*s && !firsttext)
          firsttext= linecount;
        if (!islong && !firstshort && coordcount)
          firstshort= linecount;
        break;
      }
      if (!firstpoint)
        firstpoint= linecount;
      s= t;
      if (++tokcount > maxcount)
        continue;
      if (qh->HALFspace) {
        if (qh->CDDinput)
          *(coordp++)= -value; /* both coefficients and offset */
        else
          *(coordp++)= value;
      }else {
        *(coords++)= value;
        if (qh->CDDinput && !coordcount) {
          if (value != 1.0) {
            qh_fprintf(qh, qh->ferr, 6077, "qhull input error: for cdd format, point at line %d does not start with '1'\n",
                   linecount);
            qh_errexit(qh, qh_ERRinput, NULL, NULL);
          }
          coords--;
        }else if (isdelaunay) {
          paraboloid += value * value;
          if (qh->ATinfinity) {
            if (qh->CDDinput)
              infinity[coordcount-1] += value;
            else
              infinity[coordcount] += value;
          }
        }
      }
      if (++coordcount == diminput) {
        coordcount= 0;
        if (isdelaunay) {
          *(coords++)= paraboloid;
          maximize_(maxboloid, paraboloid);
          paraboloid= 0.0;
        }else if (qh->HALFspace) {
          if (!qh_sethalfspace(qh, *dimension, coords, &coords, normalp, offsetp, qh->feasible_point)) {
            qh_fprintf(qh, qh->ferr, 8048, "The halfspace was on line %d\n", linecount);
            if (wasbegin)
              qh_fprintf(qh, qh->ferr, 8049, "The input appears to be in cdd format.  If so, you should use option 'Fd'\n");
            qh_errexit(qh, qh_ERRinput, NULL, NULL);
          }
          coordp= qh->half_space;
        }
        while (isspace(*s))
          s++;
        if (*s) {
          islong= True;
          if (!firstlong)
            firstlong= linecount;
        }
      }
    }
    if (!islong && !firstshort && coordcount)
      firstshort= linecount;
    if (!isfirst && s - qh->line >= qh->maxline) {
      qh_fprintf(qh, qh->ferr, 6078, "qhull input error: line %d contained more than %d characters\n",
              linecount, (int) (s - qh->line));   /* WARN64 */
      qh_errexit(qh, qh_ERRinput, NULL, NULL);
    }
    isfirst= False;
  }
  if (qh->rbox_command[0])
    qh->rbox_command[strlen(qh->rbox_command)-1]= '\0'; /* remove \n, previous qh_errexit's display command as two lines */
  if (tokcount != maxcount) {
    newnum= fmin_(numinput, tokcount/diminput);
    if (qh->ALLOWshort)
      qh_fprintf(qh, qh->ferr, 7073, "qhull warning: instead of %d points in %d-d, input contains %d points and %d extra coordinates.\n",
          numinput, diminput, tokcount/diminput, tokcount % diminput);
    else
      qh_fprintf(qh, qh->ferr, 6410, "qhull error: instead of %d points in %d-d, input contains %d points and %d extra coordinates.\n",
          numinput, diminput, tokcount/diminput, tokcount % diminput);
    if (firsttext)
      qh_fprintf(qh, qh->ferr, 8051, "    Line %d is the first comment.\n", firsttext);
    qh_fprintf(qh, qh->ferr, 8033,   "    Line %d is the first point.\n", firstpoint);
    if (firstshort)
      qh_fprintf(qh, qh->ferr, 8052, "    Line %d is the first short line.\n", firstshort);
    if (firstlong)
      qh_fprintf(qh, qh->ferr, 8053, "    Line %d is the first long line.\n", firstlong);
    if (qh->ALLOWshort)
      qh_fprintf(qh, qh->ferr, 8054, "    Continuing with %d points.\n", newnum);
    else {
      qh_fprintf(qh, qh->ferr, 8077, "    Override with option 'Qa' (allow-short)\n");
      qh_errexit(qh, qh_ERRinput, NULL, NULL);
    }
    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 (!strcmp(qh->rbox_command, "./rbox D4"))
    qh_fprintf(qh, qh->ferr, 8055, "\n\
This is the qhull test case.  If any errors or core dumps occur,\n\
recompile qhull with 'make new'.  If errors still occur, there is\n\
an incompatibility.  You should try a different compiler.  You can also\n\
change the choices in user_r.h.  If you discover the source of the problem,\n\
please send mail to qhull_bug@qhull.org.\n\
\n\
Type 'qhull' for a short list of options.\n");
  qh_free(qh->line);
  qh->line= NULL;
  if (qh->half_space) {
    qh_free(qh->half_space);
    qh->half_space= NULL;
  }
  qh->temp_malloc= NULL;
  trace1((qh, qh->ferr, 1008,"qh_readpoints: read in %d %d-dimensional points\n",
          numinput, diminput));
  return(points);
} /* readpoints */


/*---------------------------------

  qh_setfeasible(qh, dim )
    set qh.feasible_point 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()
    called only once from qh_new_qhull, otherwise leaks memory
*/
void qh_setfeasible(qhT *qh, int dim) {
  int tokcount= 0;
  char *s;
  coordT *coords, value;

  if (!(s= qh->feasible_string)) {
    qh_fprintf(qh, qh->ferr, 6223, "qhull input error: halfspace intersection needs a feasible point.  Either prepend the input with 1 point or use 'Hn,n,n'.  See manual.\n");
    qh_errexit(qh, qh_ERRinput, NULL, NULL);
  }
  if (!(qh->feasible_point= (pointT *)qh_malloc((size_t)dim * sizeof(coordT)))) {
    qh_fprintf(qh, qh->ferr, 6079, "qhull error: insufficient memory for 'Hn,n,n'\n");
    qh_errexit(qh, qh_ERRmem, NULL, NULL);
  }
  coords= qh->feasible_point;
  while (*s) {
    value= qh_strtod(s, &s);
    if (++tokcount > dim) {
      qh_fprintf(qh, qh->ferr, 7059, "qhull input warning: more coordinates for 'H%s' than dimension %d\n",
          qh->feasible_string, dim);
      break;
    }
    *(coords++)= value;
    if (*s)
      s++;
  }
  while (++tokcount <= dim)
    *(coords++)= 0.0;
} /* setfeasible */

/*---------------------------------

  qh_skipfacet(qh, facet )
    returns 'True' if this facet is not to be printed

  notes:
    based on the user provided slice thresholds and 'good' specifications
*/
boolT qh_skipfacet(qhT *qh, facetT *facet) {
  facetT *neighbor, **neighborp;

  if (qh->PRINTneighbors) {
    if (facet->good)
      return !qh->PRINTgood;
    FOREACHneighbor_(facet) {
      if (neighbor->good)
        return False;
    }
    return True;
  }else if (qh->PRINTgood)
    return !facet->good;
  else if (!facet->normal)
    return True;
  return(!qh_inthresholds(qh, facet->normal, NULL));
} /* skipfacet */

/*---------------------------------

  qh_skipfilename(qh, string )
    returns pointer to character after filename

  notes:
    skips leading spaces
    ends with spacing or eol
    if starts with ' or " ends with the same, skipping \' or \"
    For qhull, qh_argv_to_command() only uses double quotes
*/
char *qh_skipfilename(qhT *qh, char *filename) {
  char *s= filename;  /* non-const due to return */
  char c;

  while (*s && isspace(*s))
    s++;
  c= *s++;
  if (c == '\0') {
    qh_fprintf(qh, qh->ferr, 6204, "qhull input error: filename expected, none found.\n");
    qh_errexit(qh, qh_ERRinput, NULL, NULL);
  }
  if (c == '\'' || c == '"') {
    while (*s !=c || s[-1] == '\\') {
      if (!*s) {
        qh_fprintf(qh, qh->ferr, 6203, "qhull input error: missing quote after filename -- %s\n", filename);
        qh_errexit(qh, qh_ERRinput, NULL, NULL);
      }
      s++;
    }
    s++;
  }
  else while (*s && !isspace(*s))
      s++;
  return s;
} /* skipfilename */

qhull-2020.2/src/libqhull_r/io_r.h0000644060175106010010000002060313661631133015217 0ustar  bbarber/*
  ---------------------------------

   io_r.h
   declarations of Input/Output functions

   see README, libqhull_r.h and io_r.c

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull_r/io_r.h#3 $$Change: 2953 $
   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
*/

#ifndef qhDEFio
#define qhDEFio 1

#include "libqhull_r.h"

/*============ constants and flags ==================*/

/*----------------------------------

  qh_MAXfirst
    maximum length of first two lines of stdin
*/
#define qh_MAXfirst  200

/*----------------------------------

  qh_MINradius
    min radius for Gp and Gv, fraction of maxcoord
*/
#define qh_MINradius 0.02

/*----------------------------------

  qh_GEOMepsilon
    adjust outer planes for 'lines closer' and geomview roundoff.
    This prevents bleed through.
*/
#define qh_GEOMepsilon 2e-3

/*----------------------------------

  qh_WHITESPACE
    possible values of white space
*/
#define qh_WHITESPACE " \n\t\v\r\f"


/*----------------------------------

  qh_RIDGE
    to select which ridges to print in qh_eachvoronoi
*/
typedef enum
{
    qh_RIDGEall= 0, qh_RIDGEinner, qh_RIDGEouter
}
qh_RIDGE;

/*----------------------------------

  printvridgeT
    prints results of qh_printvdiagram

  see:
    qh_printvridge for an example
*/
typedef void (*printvridgeT)(qhT *qh, FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);

/*============== -prototypes in alphabetical order =========*/

#ifdef __cplusplus
extern "C" {
#endif

void    qh_dfacet(qhT *qh, unsigned int id);
void    qh_dvertex(qhT *qh, unsigned int id);
int     qh_compare_facetarea(const void *p1, const void *p2);
int     qh_compare_facetvisit(const void *p1, const void *p2);
int     qh_compare_nummerge(const void *p1, const void *p2);
void    qh_copyfilename(qhT *qh, char *filename, int size, const char* source, int length);
void    qh_countfacets(qhT *qh, facetT *facetlist, setT *facets, boolT printall,
              int *numfacetsp, int *numsimplicialp, int *totneighborsp,
              int *numridgesp, int *numcoplanarsp, int *numnumtricoplanarsp);
pointT *qh_detvnorm(qhT *qh, vertexT *vertex, vertexT *vertexA, setT *centers, realT *offsetp);
setT   *qh_detvridge(qhT *qh, vertexT *vertex);
setT   *qh_detvridge3(qhT *qh, vertexT *atvertex, vertexT *vertex);
int     qh_eachvoronoi(qhT *qh, FILE *fp, printvridgeT printvridge, vertexT *atvertex, boolT visitall, qh_RIDGE innerouter, boolT inorder);
int     qh_eachvoronoi_all(qhT *qh, FILE *fp, printvridgeT printvridge, boolT isUpper, qh_RIDGE innerouter, boolT inorder);
void    qh_facet2point(qhT *qh, facetT *facet, pointT **point0, pointT **point1, realT *mindist);
setT   *qh_facetvertices(qhT *qh, facetT *facetlist, setT *facets, boolT allfacets);
void    qh_geomplanes(qhT *qh, facetT *facet, realT *outerplane, realT *innerplane);
void    qh_markkeep(qhT *qh, facetT *facetlist);
setT   *qh_markvoronoi(qhT *qh, facetT *facetlist, setT *facets, boolT printall, boolT *isLowerp, int *numcentersp);
void    qh_order_vertexneighbors(qhT *qh, vertexT *vertex);
void    qh_prepare_output(qhT *qh);
void    qh_printafacet(qhT *qh, FILE *fp, qh_PRINT format, facetT *facet, boolT printall);
void    qh_printbegin(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
void    qh_printcenter(qhT *qh, FILE *fp, qh_PRINT format, const char *string, facetT *facet);
void    qh_printcentrum(qhT *qh, FILE *fp, facetT *facet, realT radius);
void    qh_printend(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
void    qh_printend4geom(qhT *qh, FILE *fp, facetT *facet, int *num, boolT printall);
void    qh_printextremes(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall);
void    qh_printextremes_2d(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall);
void    qh_printextremes_d(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall);
void    qh_printfacet(qhT *qh, FILE *fp, facetT *facet);
void    qh_printfacet2math(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format, int notfirst);
void    qh_printfacet2geom(qhT *qh, FILE *fp, facetT *facet, realT color[3]);
void    qh_printfacet2geom_points(qhT *qh, FILE *fp, pointT *point1, pointT *point2,
                               facetT *facet, realT offset, realT color[3]);
void    qh_printfacet3math(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format, int notfirst);
void    qh_printfacet3geom_nonsimplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]);
void    qh_printfacet3geom_points(qhT *qh, FILE *fp, setT *points, facetT *facet, realT offset, realT color[3]);
void    qh_printfacet3geom_simplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]);
void    qh_printfacet3vertex(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format);
void    qh_printfacet4geom_nonsimplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]);
void    qh_printfacet4geom_simplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]);
void    qh_printfacetNvertex_nonsimplicial(qhT *qh, FILE *fp, facetT *facet, int id, qh_PRINT format);
void    qh_printfacetNvertex_simplicial(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format);
void    qh_printfacetheader(qhT *qh, FILE *fp, facetT *facet);
void    qh_printfacetridges(qhT *qh, FILE *fp, facetT *facet);
void    qh_printfacets(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
void    qh_printhyperplaneintersection(qhT *qh, FILE *fp, facetT *facet1, facetT *facet2,
                   setT *vertices, realT color[3]);
void    qh_printline3geom(qhT *qh, FILE *fp, pointT *pointA, pointT *pointB, realT color[3]);
void    qh_printneighborhood(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetA, facetT *facetB, boolT printall);
void    qh_printpoint(qhT *qh, FILE *fp, const char *string, pointT *point);
void    qh_printpointid(qhT *qh, FILE *fp, const char *string, int dim, pointT *point, int id);
void    qh_printpoint3(qhT *qh, FILE *fp, pointT *point);
void    qh_printpoints_out(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall);
void    qh_printpointvect(qhT *qh, FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius, realT color[3]);
void    qh_printpointvect2(qhT *qh, FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius);
void    qh_printridge(qhT *qh, FILE *fp, ridgeT *ridge);
void    qh_printspheres(qhT *qh, FILE *fp, setT *vertices, realT radius);
void    qh_printvdiagram(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
int     qh_printvdiagram2(qhT *qh, FILE *fp, printvridgeT printvridge, setT *vertices, qh_RIDGE innerouter, boolT inorder);
void    qh_printvertex(qhT *qh, FILE *fp, vertexT *vertex);
void    qh_printvertexlist(qhT *qh, FILE *fp, const char* string, facetT *facetlist,
                         setT *facets, boolT printall);
void    qh_printvertices(qhT *qh, FILE *fp, const char* string, setT *vertices);
void    qh_printvneighbors(qhT *qh, FILE *fp, facetT* facetlist, setT *facets, boolT printall);
void    qh_printvoronoi(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
void    qh_printvnorm(qhT *qh, FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
void    qh_printvridge(qhT *qh, FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
void    qh_produce_output(qhT *qh);
void    qh_produce_output2(qhT *qh);
void    qh_projectdim3(qhT *qh, pointT *source, pointT *destination);
int     qh_readfeasible(qhT *qh, int dim, const char *curline);
coordT *qh_readpoints(qhT *qh, int *numpoints, int *dimension, boolT *ismalloc);
void    qh_setfeasible(qhT *qh, int dim);
boolT   qh_skipfacet(qhT *qh, facetT *facet);
char   *qh_skipfilename(qhT *qh, char *filename);

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* qhDEFio */
qhull-2020.2/src/libqhull_r/libqhull_r.c0000644060175106010010000021516713661631132016431 0ustar  bbarber/*
  ---------------------------------

   libqhull_r.c
   Quickhull algorithm for convex hulls

   qhull() and top-level routines

   see qh-qhull_r.htm, libqhull_r.h, unix_r.c

   see qhull_ra.h for internal functions

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull_r/libqhull_r.c#17 $$Change: 2953 $
   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
*/

#include "qhull_ra.h"

/*============= functions in alphabetic order after qhull() =======*/

/*---------------------------------

  qh_qhull(qh)
    compute DIM3 convex hull of qh.num_points starting at qh.first_point
    qh->contains all global options and variables

  returns:
    returns polyhedron
      qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices,

    returns global variables
      qh.hulltime, qh.max_outside, qh.interior_point, qh.max_vertex, qh.min_vertex

    returns precision constants
      qh.ANGLEround, centrum_radius, cos_max, DISTround, MAXabs_coord, ONEmerge

  notes:
    unless needed for output
      qh.max_vertex and qh.min_vertex are max/min due to merges

  see:
    to add individual points to either qh.num_points
      use qh_addpoint()

    if qh.GETarea
      qh_produceoutput() returns qh.totarea and qh.totvol via qh_getarea()

  design:
    record starting time
    initialize hull and partition points
    build convex hull
    unless early termination
      update facet->maxoutside for vertices, coplanar, and near-inside points
    error if temporary sets exist
    record end time
*/

void qh_qhull(qhT *qh) {
  int numoutside;

  qh->hulltime= qh_CPUclock;
  if (qh->RERUN || qh->JOGGLEmax < REALmax/2)
    qh_build_withrestart(qh);
  else {
    qh_initbuild(qh);
    qh_buildhull(qh);
  }
  if (!qh->STOPadd && !qh->STOPcone && !qh->STOPpoint) {
    if (qh->ZEROall_ok && !qh->TESTvneighbors && qh->MERGEexact)
      qh_checkzero(qh, qh_ALL);
    if (qh->ZEROall_ok && !qh->TESTvneighbors && !qh->WAScoplanar) {
      trace2((qh, qh->ferr, 2055, "qh_qhull: all facets are clearly convex and no coplanar points.  Post-merging and check of maxout not needed.\n"));
      qh->DOcheckmax= False;
    }else {
      qh_initmergesets(qh /* qh.facet_mergeset,degen_mergeset,vertex_mergeset */);
      if (qh->MERGEexact || (qh->hull_dim > qh_DIMreduceBuild && qh->PREmerge))
        qh_postmerge(qh, "First post-merge", qh->premerge_centrum, qh->premerge_cos,
             (qh->POSTmerge ? False : qh->TESTvneighbors)); /* calls qh_reducevertices */
      else if (!qh->POSTmerge && qh->TESTvneighbors)
        qh_postmerge(qh, "For testing vertex neighbors", qh->premerge_centrum,
             qh->premerge_cos, True);                       /* calls qh_test_vneighbors */
      if (qh->POSTmerge)
        qh_postmerge(qh, "For post-merging", qh->postmerge_centrum,
             qh->postmerge_cos, qh->TESTvneighbors);
      if (qh->visible_list == qh->facet_list) {            /* qh_postmerge was called */
        qh->findbestnew= True;
        qh_partitionvisible(qh, !qh_ALL, &numoutside /* qh.visible_list */);
        qh->findbestnew= False;
        qh_deletevisible(qh /* qh.visible_list */);        /* stops at first !f.visible */
        qh_resetlists(qh, False, qh_RESETvisible /* qh.visible_list newvertex_list qh.newfacet_list */);
      }
      qh_all_vertexmerges(qh, -1, NULL, NULL);
      qh_freemergesets(qh);
    }
    if (qh->TRACEpoint == qh_IDunknown && qh->TRACElevel > qh->IStracing) {
      qh->IStracing= qh->TRACElevel;
      qh_fprintf(qh, qh->ferr, 2112, "qh_qhull: finished qh_buildhull and qh_postmerge, start tracing (TP-1)\n");
    }
    if (qh->DOcheckmax){
      if (qh->REPORTfreq) {
        qh_buildtracing(qh, NULL, NULL);
        qh_fprintf(qh, qh->ferr, 8115, "\nTesting all coplanar points.\n");
      }
      qh_check_maxout(qh);
    }
    if (qh->KEEPnearinside && !qh->maxoutdone)
      qh_nearcoplanar(qh);
  }
  if (qh_setsize(qh, qh->qhmem.tempstack) != 0) {
    qh_fprintf(qh, qh->ferr, 6164, "qhull internal error (qh_qhull): temporary sets not empty(%d) at end of Qhull\n",
             qh_setsize(qh, qh->qhmem.tempstack));
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  qh->hulltime= qh_CPUclock - qh->hulltime;
  qh->QHULLfinished= True;
  trace1((qh, qh->ferr, 1036, "Qhull: algorithm completed\n"));
} /* qhull */

/*---------------------------------

  qh_addpoint(qh, furthest, facet, checkdist )
    add point (usually furthest point) above facet to hull
    if checkdist,
      check that point is above facet.
      if point is not outside of the hull, uses qh_partitioncoplanar()
      assumes that facet is defined by qh_findbestfacet()
    else if facet specified,
      assumes that point is above facet (major damage if below)
    for Delaunay triangulations,
      Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed
      Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates.

  returns:
    returns False if user requested an early termination
      qh.visible_list, newfacet_list, delvertex_list, NEWfacets may be defined
    updates qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices
    clear qh.maxoutdone (will need to call qh_check_maxout() for facet->maxoutside)
    if unknown point, adds a pointer to qh.other_points
      do not deallocate the point's coordinates

  notes:
    called from qh_initbuild, qh_buildhull, and qh_addpoint
    tail recursive call if merged a pinchedvertex due to a duplicated ridge
      no more than qh.num_vertices calls (QH6296)
    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
    if called from a user application after qh_qhull and 'QJ' (joggle),
      facet merging for precision problems is disabled by default

  design:
    exit if qh.STOPadd vertices 'TAn'
    add point to other_points if needed
    if checkdist
      if point not above facet
        partition coplanar point
        exit
    exit if pre STOPpoint requested
    find horizon and visible facets for point
    build cone of new facets to the horizon
    exit if build cone fails due to qh.ONLYgood
    tail recursive call if build cone fails due to pinched vertices
    exit if STOPcone requested
    merge non-convex new facets
    if merge found, many merges, or 'Qf'
       use qh_findbestnew() instead of qh_findbest()
    partition outside points from visible facets
    delete visible facets
    check polyhedron if requested
    exit if post STOPpoint requested
    reset working lists of facets and vertices
*/
boolT qh_addpoint(qhT *qh, pointT *furthest, facetT *facet, boolT checkdist) {
  realT dist, pbalance;
  facetT *replacefacet, *newfacet;
  vertexT *apex;
  boolT isoutside= False;
  int numpart, numpoints, goodvisible, goodhorizon, apexpointid;

  qh->maxoutdone= False;
  if (qh_pointid(qh, furthest) == qh_IDunknown)
    qh_setappend(qh, &qh->other_points, furthest);
  if (!facet) {
    qh_fprintf(qh, qh->ferr, 6213, "qhull internal error (qh_addpoint): NULL facet.  Need to call qh_findbestfacet first\n");
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  qh_detmaxoutside(qh);
  if (checkdist) {
    facet= qh_findbest(qh, furthest, facet, !qh_ALL, !qh_ISnewfacets, !qh_NOupper,
                        &dist, &isoutside, &numpart);
    zzadd_(Zpartition, numpart);
    if (!isoutside) {
      zinc_(Znotmax);  /* last point of outsideset is no longer furthest. */
      facet->notfurthest= True;
      qh_partitioncoplanar(qh, furthest, facet, &dist, qh->findbestnew);
      return True;
    }
  }
  qh_buildtracing(qh, furthest, facet);
  if (qh->STOPpoint < 0 && qh->furthest_id == -qh->STOPpoint-1) {
    facet->notfurthest= True;
    return False;
  }
  qh_findhorizon(qh, furthest, facet, &goodvisible, &goodhorizon);
  if (qh->ONLYgood && !qh->GOODclosest && !(goodvisible+goodhorizon)) {
    zinc_(Znotgood);
    facet->notfurthest= True;
    /* last point of outsideset is no longer furthest.  This is ok
        since all points of the outside are likely to be bad */
    qh_resetlists(qh, False, qh_RESETvisible /* qh.visible_list newvertex_list qh.newfacet_list */);
    return True;
  }
  apex= qh_buildcone(qh, furthest, facet, goodhorizon, &replacefacet);
  /* qh.newfacet_list, visible_list, newvertex_list */
  if (!apex) {
    if (qh->ONLYgood)
      return True; /* ignore this furthest point, a good new facet was not found */
    if (replacefacet) {
      if (qh->retry_addpoint++ >= qh->num_vertices) {
        qh_fprintf(qh, qh->ferr, 6296, "qhull internal error (qh_addpoint): infinite loop (%d retries) of merging pinched vertices due to dupridge for point p%d, facet f%d, and %d vertices\n",
          qh->retry_addpoint, qh_pointid(qh, furthest), facet->id, qh->num_vertices);
        qh_errexit(qh, qh_ERRqhull, facet, NULL);
      }
      /* retry qh_addpoint after resolving a dupridge via qh_merge_pinchedvertices */
      return qh_addpoint(qh, furthest, replacefacet, True /* checkdisk */);
    }
    qh->retry_addpoint= 0;
    return True; /* ignore this furthest point, resolved a dupridge by making furthest a coplanar point */
  }
  if (qh->retry_addpoint) {
    zinc_(Zretryadd);
    zadd_(Zretryaddtot, qh->retry_addpoint);
    zmax_(Zretryaddmax, qh->retry_addpoint);
    qh->retry_addpoint= 0;
  }
  apexpointid= qh_pointid(qh, apex->point);
  zzinc_(Zprocessed);
  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_initmergesets(qh /* qh.facet_mergeset,degen_mergeset,vertex_mergeset */);
    qh_premerge(qh, apexpointid, qh->premerge_centrum, qh->premerge_cos /* qh.newfacet_list */);
    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;
  if (qh->IStracing >= 4)
    qh_checkpolygon(qh, qh->visible_list);
  qh_partitionvisible(qh, !qh_ALL, &numpoints /* qh.visible_list */);
  qh->findbestnew= False;
  qh->findbest_notsharp= False;
  zinc_(Zpbalance);
  pbalance= numpoints - (realT) qh->hull_dim /* assumes all points extreme */
                * (qh->num_points - qh->num_vertices)/qh->num_vertices;
  wadd_(Wpbalance, pbalance);
  wadd_(Wpbalance2, pbalance * pbalance);
  qh_deletevisible(qh /* qh.visible_list */);
  zmax_(Zmaxvertex, qh->num_vertices);
  qh->NEWfacets= False;
  if (qh->IStracing >= 4) {
    if (qh->num_facets < 200)
      qh_printlists(qh);
    qh_printfacetlist(qh, qh->newfacet_list, NULL, True);
    qh_checkpolygon(qh, qh->facet_list);
  }else if (qh->CHECKfrequently) {
    if (qh->num_facets < 1000)
      qh_checkpolygon(qh, qh->facet_list);
    else
      qh_checkpolygon(qh, qh->newfacet_list);
  }
  if (qh->STOPpoint > 0 && qh->furthest_id == qh->STOPpoint-1 && qh_setsize(qh, qh->vertex_mergeset) > 0)
    return False;
  qh_resetlists(qh, True, qh_RESETvisible /* qh.visible_list newvertex_list qh.newfacet_list */);
  if (qh->facet_mergeset) {
    /* vertex merges occur after facet merges (qh_premerge) and qh_resetlists */
    qh_all_vertexmerges(qh, apexpointid, NULL, NULL);
    qh_freemergesets(qh);
  }
  /* qh_triangulate(qh); to test qh.TRInormals */
  if (qh->STOPpoint > 0 && qh->furthest_id == qh->STOPpoint-1)
    return False;
  trace2((qh, qh->ferr, 2056, "qh_addpoint: added p%d to convex hull with point balance %2.2g\n",
    qh_pointid(qh, furthest), pbalance));
  return True;
} /* addpoint */

/*---------------------------------

  qh_build_withrestart(qh)
    allow restarts due to qh.JOGGLEmax while calling qh_buildhull()
       qh_errexit always undoes qh_build_withrestart()
    qh.FIRSTpoint/qh.NUMpoints is point array
       it may be moved by qh_joggleinput
*/
void qh_build_withrestart(qhT *qh) {
  int restart;
  vertexT *vertex, **vertexp;

  qh->ALLOWrestart= True;
  while (True) {
    restart= setjmp(qh->restartexit); /* simple statement for CRAY J916 */
    if (restart) {       /* only from qh_joggle_restart() */
      qh->last_errcode= qh_ERRnone;
      zzinc_(Zretry);
      wmax_(Wretrymax, qh->JOGGLEmax);
      /* QH7078 warns about using 'TCn' with 'QJn' */
      qh->STOPcone= qh_IDunknown; /* if break from joggle, prevents normal output */
      FOREACHvertex_(qh->del_vertices) {
        if (vertex->point && !vertex->partitioned)
          vertex->partitioned= True; /* avoid error in qh_freebuild -> qh_delvertex */
      }
    }
    if (!qh->RERUN && qh->JOGGLEmax < REALmax/2) {
      if (qh->build_cnt > qh_JOGGLEmaxretry) {
        qh_fprintf(qh, qh->ferr, 6229, "qhull input error: %d attempts to construct a convex hull with joggled input.  Increase joggle above 'QJ%2.2g' or modify qh_JOGGLE... parameters in user_r.h\n",
           qh->build_cnt, qh->JOGGLEmax);
        qh_errexit(qh, qh_ERRinput, NULL, NULL);
      }
      if (qh->build_cnt && !restart)
        break;
    }else if (qh->build_cnt && qh->build_cnt >= qh->RERUN)
      break;
    qh->STOPcone= 0;
    qh_freebuild(qh, True);  /* first call is a nop */
    qh->build_cnt++;
    if (!qh->qhull_optionsiz)
      qh->qhull_optionsiz= (int)strlen(qh->qhull_options);   /* WARN64 */
    else {
      qh->qhull_options[qh->qhull_optionsiz]= '\0';
      qh->qhull_optionlen= qh_OPTIONline;  /* starts a new line */
    }
    qh_option(qh, "_run", &qh->build_cnt, NULL);
    if (qh->build_cnt == qh->RERUN) {
      qh->IStracing= qh->TRACElastrun;  /* duplicated from qh_initqhull_globals */
      if (qh->TRACEpoint != qh_IDnone || qh->TRACEdist < REALmax/2 || qh->TRACEmerge) {
        qh->TRACElevel= (qh->IStracing? qh->IStracing : 3);
        qh->IStracing= 0;
      }
      qh->qhmem.IStracing= qh->IStracing;
    }
    if (qh->JOGGLEmax < REALmax/2)
      qh_joggleinput(qh);
    qh_initbuild(qh);
    qh_buildhull(qh);
    if (qh->JOGGLEmax < REALmax/2 && !qh->MERGING)
      qh_checkconvex(qh, qh->facet_list, qh_ALGORITHMfault);
  }
  qh->ALLOWrestart= False;
} /* qh_build_withrestart */

/*---------------------------------

  qh_buildcone(qh, furthest, facet, goodhorizon, &replacefacet )
    build cone of new facets from furthest to the horizon
    goodhorizon is count of good, horizon facets from qh_find_horizon

  returns:
    returns apex of cone with qh.newfacet_list and qh.first_newfacet (f.id)
    returns NULL if qh.ONLYgood and no good facets
    returns NULL and retryfacet if merging pinched vertices will resolve a dupridge
      a horizon vertex was nearly adjacent to another vertex
      will retry qh_addpoint
    returns NULL if resolve a dupridge by making furthest a coplanar point
      furthest was nearly adjacent to an existing vertex
    updates qh.degen_mergeset (MRGridge) if resolve a dupridge by merging facets
    updates qh.newfacet_list, visible_list, newvertex_list
    updates qh.facet_list, vertex_list, num_facets, num_vertices

  notes:
    called by qh_addpoint
    see qh_triangulate, it triangulates non-simplicial facets in post-processing

  design:
    make new facets for point to horizon
    compute balance statistics
    make hyperplanes for point
    exit if qh.ONLYgood and not good (qh_buildcone_onlygood)
    match neighboring new facets
    if dupridges
      exit if !qh.IGNOREpinched and dupridge resolved by coplanar furthest
      retry qh_buildcone if !qh.IGNOREpinched and dupridge resolved by qh_buildcone_mergepinched
      otherwise dupridges resolved by merging facets
    update vertex neighbors and delete interior vertices
*/
vertexT *qh_buildcone(qhT *qh, pointT *furthest, facetT *facet, int goodhorizon, facetT **retryfacet) {
  vertexT *apex;
  realT newbalance;
  int numnew;

  *retryfacet= NULL;
  qh->first_newfacet= qh->facet_id;
  qh->NEWtentative= (qh->MERGEpinched || qh->ONLYgood); /* cleared by qh_attachnewfacets or qh_resetlists */
  apex= qh_makenewfacets(qh, furthest /* qh.newfacet_list visible_list, attaches new facets if !qh.NEWtentative */);
  numnew= (int)(qh->facet_id - qh->first_newfacet);
  newbalance= numnew - (realT)(qh->num_facets - qh->num_visible) * qh->hull_dim / qh->num_vertices;
  /* newbalance statistics updated below if the new facets are accepted */
  if (qh->ONLYgood) { /* qh.MERGEpinched is false by QH6362 */
    if (!qh_buildcone_onlygood(qh, apex, goodhorizon /* qh.newfacet_list */)) {
      facet->notfurthest= True;
      return NULL;
    }
  }else if(qh->MERGEpinched) {
#ifndef qh_NOmerge
    if (qh_buildcone_mergepinched(qh, apex, facet, retryfacet /* qh.newfacet_list */))
      return NULL;
#else
    qh_fprintf(qh, qh->ferr, 6375, "qhull option error (qh_buildcone): option 'Q14' (qh.MERGEpinched) is not available due to qh_NOmerge\n");
    qh_errexit(qh, qh_ERRinput, NULL, NULL);
#endif
  }else {
    /* qh_makenewfacets attached new facets to the horizon */
    qh_matchnewfacets(qh); /* ignore returned value.  qh_forcedmerges will merge dupridges if any */
    qh_makenewplanes(qh /* qh.newfacet_list */);
    qh_update_vertexneighbors_cone(qh);
  }
  wadd_(Wnewbalance, newbalance);
  wadd_(Wnewbalance2, newbalance * newbalance);
  trace2((qh, qh->ferr, 2067, "qh_buildcone: created %d newfacets for p%d(v%d) new facet balance %2.2g\n",
    numnew, qh_pointid(qh, furthest), apex->id, newbalance));
  return apex;
} /* buildcone */

#ifndef qh_NOmerge
/*---------------------------------

  qh_buildcone_mergepinched(qh, apex, facet, maxdupdist, &retryfacet )
    build cone of new facets from furthest to the horizon
    maxdupdist>0.0 for merging dupridges (qh_matchdupridge)

  returns:
    returns True if merged a pinched vertex and deleted the cone of new facets
      if retryfacet is set
        a dupridge was resolved by qh_merge_pinchedvertices
        retry qh_addpoint
      otherwise
        apex/furthest was partitioned as a coplanar point
        ignore this furthest point
    returns False if no dupridges or if dupridges will be resolved by MRGridge
    updates qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices

  notes:
    only called from qh_buildcone with qh.MERGEpinched

  design:
    match neighboring new facets
    if matching detected dupridges with a wide merge (qh_RATIOtrypinched)
      if pinched vertices (i.e., nearly adjacent)
        delete the cone of new facets
        delete the apex and reset the facet lists
        if coplanar, pinched apex
          partition the apex as a coplanar point
        else
           repeatedly merge the nearest pair of pinched vertices and subsequent facet merges
        return True
      otherwise
        MRGridge are better than vertex merge, but may report an error
    attach new facets
    make hyperplanes for point
    update vertex neighbors and delete interior vertices
*/
boolT qh_buildcone_mergepinched(qhT *qh, vertexT *apex, facetT *facet, facetT **retryfacet) {
  facetT *newfacet, *nextfacet;
  pointT *apexpoint;
  coordT maxdupdist;
  int apexpointid;
  boolT iscoplanar;

  *retryfacet= NULL;
  maxdupdist= qh_matchnewfacets(qh);
  if (maxdupdist > qh_RATIOtrypinched * qh->ONEmerge) { /* one or more dupridges with a wide merge */
    if (qh->IStracing >= 4 && qh->num_facets < 1000)
      qh_printlists(qh);
    qh_initmergesets(qh /* qh.facet_mergeset,degen_mergeset,vertex_mergeset */);
    if (qh_getpinchedmerges(qh, apex, maxdupdist, &iscoplanar /* qh.newfacet_list, qh.vertex_mergeset */)) {
      for (newfacet=qh->newfacet_list; newfacet && newfacet->next; newfacet= nextfacet) {
        nextfacet= newfacet->next;
        qh_delfacet(qh, newfacet);
      }
      apexpoint= apex->point;
      apexpointid= qh_pointid(qh, apexpoint);
      qh_delvertex(qh, apex);
      qh_resetlists(qh, False, qh_RESETvisible /* qh.visible_list newvertex_list qh.newfacet_list */);
      if (iscoplanar) {
        zinc_(Zpinchedapex);
        facet->notfurthest= True;
        qh_partitioncoplanar(qh, apexpoint, facet, NULL, qh->findbestnew);
      }else {
        qh_all_vertexmerges(qh, apexpointid, facet, retryfacet);
      }
      qh_freemergesets(qh); /* errors if not empty */
      return True;
    }
    /* MRGridge are better than vertex merge, but may report an error */
    qh_freemergesets(qh);
  }
  qh_attachnewfacets(qh /* qh.visible_list */);
  qh_makenewplanes(qh /* qh.newfacet_list */);
  qh_update_vertexneighbors_cone(qh);
  return False;
} /* buildcone_mergepinched */
#endif /* !qh_NOmerge */

/*---------------------------------

  qh_buildcone_onlygood(qh, apex, goodhorizon )
    build cone of good, new facets from apex and its qh.newfacet_list to the horizon
    goodhorizon is count of good, horizon facets from qh_find_horizon

  returns:
    False if a f.good facet or a qh.GOODclosest facet is not found
    updates qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices

  notes:
    called from qh_buildcone
    QH11030 FIX: Review effect of qh.GOODclosest on qh_buildcone_onlygood ('Qg').  qh_findgood preserves old value if didn't find a good facet.  See qh_findgood_all for disabling

  design:
    make hyperplanes for point
    if qh_findgood fails to find a f.good facet or a qh.GOODclosest facet
      delete cone of new facets
      return NULL (ignores apex)
    else
      attach cone to horizon
      match neighboring new facets
*/
boolT qh_buildcone_onlygood(qhT *qh, vertexT *apex, int goodhorizon) {
  facetT *newfacet, *nextfacet;

  qh_makenewplanes(qh /* qh.newfacet_list */);
  if(qh_findgood(qh, qh->newfacet_list, goodhorizon) == 0) {
    if (!qh->GOODclosest) {
      for (newfacet=qh->newfacet_list; newfacet && newfacet->next; newfacet= nextfacet) {
        nextfacet= newfacet->next;
        qh_delfacet(qh, newfacet);
      }
      qh_delvertex(qh, apex);
      qh_resetlists(qh, False /*no stats*/, qh_RESETvisible /* qh.visible_list newvertex_list qh.newfacet_list */);
      zinc_(Znotgoodnew);
      /* !good outside points dropped from hull */
      return False;
    }
  }
  qh_attachnewfacets(qh /* qh.visible_list */);
  qh_matchnewfacets(qh); /* ignore returned value.  qh_forcedmerges will merge dupridges if any */
  qh_update_vertexneighbors_cone(qh);
  return True;
} /* buildcone_onlygood */

/*---------------------------------

  qh_buildhull(qh)
    construct a convex hull by adding outside points one at a time

  returns:

  notes:
    may be called multiple times
    checks facet and vertex lists for incorrect flags
    to recover from STOPcone, call qh_deletevisible and qh_resetlists

  design:
    check visible facet and newfacet flags
    check newfacet vertex flags and qh.STOPcone/STOPpoint
    for each facet with a furthest outside point
      add point to facet
      exit if qh.STOPcone or qh.STOPpoint requested
    if qh.NARROWhull for initial simplex
      partition remaining outside points to coplanar sets
*/
void qh_buildhull(qhT *qh) {
  facetT *facet;
  pointT *furthest;
  vertexT *vertex;
  int id;

  trace1((qh, qh->ferr, 1037, "qh_buildhull: start build hull\n"));
  FORALLfacets {
    if (facet->visible || facet->newfacet) {
      qh_fprintf(qh, qh->ferr, 6165, "qhull internal error (qh_buildhull): visible or new facet f%d in facet list\n",
                   facet->id);
      qh_errexit(qh, qh_ERRqhull, facet, NULL);
    }
  }
  FORALLvertices {
    if (vertex->newfacet) {
      qh_fprintf(qh, qh->ferr, 6166, "qhull internal error (qh_buildhull): new vertex f%d in vertex list\n",
                   vertex->id);
      qh_errprint(qh, "ERRONEOUS", NULL, NULL, NULL, vertex);
      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
    }
    id= qh_pointid(qh, vertex->point);
    if ((qh->STOPpoint>0 && id == qh->STOPpoint-1) ||
        (qh->STOPpoint<0 && id == -qh->STOPpoint-1) ||
        (qh->STOPcone>0 && id == qh->STOPcone-1)) {
      trace1((qh, qh->ferr, 1038,"qh_buildhull: stop point or cone P%d in initial hull\n", id));
      return;
    }
  }
  qh->facet_next= qh->facet_list;      /* advance facet when processed */
  while ((furthest= qh_nextfurthest(qh, &facet))) {
    qh->num_outside--;  /* if ONLYmax, furthest may not be outside */
    if (qh->STOPadd>0 && (qh->num_vertices - qh->hull_dim - 1 >= qh->STOPadd - 1)) {
      trace1((qh, qh->ferr, 1059, "qh_buildhull: stop after adding %d vertices\n", qh->STOPadd-1));
      return;
    }
    if (!qh_addpoint(qh, furthest, facet, qh->ONLYmax))
      break;
  }
  if (qh->NARROWhull) /* move points from outsideset to coplanarset */
    qh_outcoplanar(qh /* facet_list */ );
  if (qh->num_outside && !furthest) {
    qh_fprintf(qh, qh->ferr, 6167, "qhull internal error (qh_buildhull): %d outside points were never processed.\n", qh->num_outside);
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  trace1((qh, qh->ferr, 1039, "qh_buildhull: completed the hull construction\n"));
} /* buildhull */


/*---------------------------------

  qh_buildtracing(qh, furthest, facet )
    trace an iteration of qh_buildhull() for furthest point and facet
    if !furthest, prints progress message

  returns:
    tracks progress with qh.lastreport, lastcpu, lastfacets, lastmerges, lastplanes, lastdist
    updates qh.furthest_id (-3 if furthest is NULL)
    also resets visit_id, vertext_visit on wrap around

  see:
    qh_tracemerging()

  design:
    if !furthest
      print progress message
      exit
    if 'TFn' iteration
      print progress message
    else if tracing
      trace furthest point and facet
    reset qh.visit_id and qh.vertex_visit if overflow may occur
    set qh.furthest_id for tracing
*/
void qh_buildtracing(qhT *qh, pointT *furthest, facetT *facet) {
  realT dist= 0;
  double 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= (double)qh_CPUclock - (double)qh->hulltime;
    cpu /= (double)qh_SECticks;
    total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
    qh_fprintf(qh, qh->ferr, 8118, "\n\
At %02d:%02d:%02d & %2.5g CPU secs, qhull has created %d facets and merged %d.\n\
 The current hull contains %d facets and %d vertices.  Last point was p%d\n",
      tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, qh->facet_id -1,
      total, qh->num_facets, qh->num_vertices, qh->furthest_id);
    return;
  }
  furthestid= qh_pointid(qh, furthest);
#ifndef qh_NOtrace
  if (qh->TRACEpoint == furthestid) {
    trace1((qh, qh->ferr, 1053, "qh_buildtracing: start trace T%d for point TP%d above facet f%d\n", qh->TRACElevel, furthestid, facet->id));
    qh->IStracing= qh->TRACElevel;
    qh->qhmem.IStracing= qh->TRACElevel;
  }else if (qh->TRACEpoint != qh_IDnone && qh->TRACEdist < REALmax/2) {
    qh->IStracing= 0;
    qh->qhmem.IStracing= 0;
  }
#endif
  if (qh->REPORTfreq && (qh->facet_id-1 > qh->lastreport + (unsigned int)qh->REPORTfreq)) {
    qh->lastreport= qh->facet_id-1;
    time(&timedata);
    tp= localtime(&timedata);
    cpu= (double)qh_CPUclock - (double)qh->hulltime;
    cpu /= (double)qh_SECticks;
    total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
    zinc_(Zdistio);
    qh_distplane(qh, furthest, facet, &dist);
    qh_fprintf(qh, qh->ferr, 8119, "\n\
At %02d:%02d:%02d & %2.5g CPU secs, qhull has created %d facets and merged %d.\n\
 The current hull contains %d facets and %d vertices.  There are %d\n\
 outside points.  Next is point p%d(v%d), %2.2g above f%d.\n",
      tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, qh->facet_id -1,
      total, qh->num_facets, qh->num_vertices, qh->num_outside+1,
      furthestid, qh->vertex_id, dist, getid_(facet));
  }else if (qh->IStracing >=1) {
    cpu= (double)qh_CPUclock - (double)qh->hulltime;
    cpu /= (double)qh_SECticks;
    qh_distplane(qh, furthest, facet, &dist);
    qh_fprintf(qh, qh->ferr, 1049, "qh_addpoint: add p%d(v%d) %2.2g above f%d to hull of %d facets, %d merges, %d outside at %4.4g CPU secs.  Previous p%d(v%d) delta %4.4g CPU, %d facets, %d merges, %d hyperplanes, %d distplanes, %d retries\n",
      furthestid, qh->vertex_id, dist, getid_(facet), qh->num_facets, zzval_(Ztotmerge), qh->num_outside+1, cpu, qh->furthest_id, qh->vertex_id - 1,
      cpu - qh->lastcpu, qh->num_facets - qh->lastfacets,  zzval_(Ztotmerge) - qh->lastmerges, zzval_(Zsetplane) - qh->lastplanes, zzval_(Zdistplane) - qh->lastdist, qh->retry_addpoint);
    qh->lastcpu= cpu;
    qh->lastfacets= qh->num_facets;
    qh->lastmerges= zzval_(Ztotmerge);
    qh->lastplanes= zzval_(Zsetplane);
    qh->lastdist= zzval_(Zdistplane);
  }
  zmax_(Zvisit2max, (int)qh->visit_id/2);
  if (qh->visit_id > (unsigned int) INT_MAX) { /* 31 bits */
    zinc_(Zvisit);
    if (!qh_checklists(qh, qh->facet_list)) {
      qh_fprintf(qh, qh->ferr, 6370, "qhull internal error: qh_checklists failed on reset of qh.visit_id %u\n", qh->visit_id);
      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
    }
    qh->visit_id= 0;
    FORALLfacets
      facet->visitid= 0;
  }
  zmax_(Zvvisit2max, (int)qh->vertex_visit/2);
  if (qh->vertex_visit > (unsigned int) INT_MAX) { /* 31 bits */
    zinc_(Zvvisit);
    if (qh->visit_id && !qh_checklists(qh, qh->facet_list)) {
      qh_fprintf(qh, qh->ferr, 6371, "qhull internal error: qh_checklists failed on reset of qh.vertex_visit %u\n", qh->vertex_visit);
      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
    }
    qh->vertex_visit= 0;
    FORALLvertices
      vertex->visitid= 0;
  }
  qh->furthest_id= furthestid;
  qh->RANDOMdist= qh->old_randomdist;
} /* buildtracing */

/*---------------------------------

  qh_errexit2(qh, exitcode, facet, otherfacet )
    return exitcode to system after an error
    report two facets

  returns:
    assumes exitcode non-zero

  see:
    normally use qh_errexit() in user_r.c(reports a facet and a ridge)
*/
void qh_errexit2(qhT *qh, int exitcode, facetT *facet, facetT *otherfacet) {
  qh->tracefacet= NULL;  /* avoid infinite recursion through qh_fprintf */
  qh->traceridge= NULL;
  qh->tracevertex= NULL;
  qh_errprint(qh, "ERRONEOUS", facet, otherfacet, NULL, NULL);
  qh_errexit(qh, exitcode, NULL, NULL);
} /* errexit2 */


/*---------------------------------

  qh_findhorizon(qh, point, facet, goodvisible, goodhorizon )
    given a visible facet, find the point's horizon and visible facets
    for all facets, !facet-visible

  returns:
    returns qh.visible_list/num_visible with all visible facets
      marks visible facets with ->visible
    updates count of good visible and good horizon facets
    updates qh.max_outside, qh.max_vertex, facet->maxoutside

  see:
    similar to qh_delpoint()

  design:
    move facet to qh.visible_list at end of qh.facet_list
    for all visible facets
     for each unvisited neighbor of a visible facet
       compute distance of point to neighbor
       if point above neighbor
         move neighbor to end of qh.visible_list
       else if point is coplanar with neighbor
         update qh.max_outside, qh.max_vertex, neighbor->maxoutside
         mark neighbor coplanar (will create a samecycle later)
         update horizon statistics
*/
void qh_findhorizon(qhT *qh, pointT *point, facetT *facet, int *goodvisible, int *goodhorizon) {
  facetT *neighbor, **neighborp, *visible;
  int numhorizon= 0, coplanar= 0;
  realT dist;

  trace1((qh, qh->ferr, 1040, "qh_findhorizon: find horizon for point p%d facet f%d\n",qh_pointid(qh, point),facet->id));
  *goodvisible= *goodhorizon= 0;
  zinc_(Ztotvisible);
  qh_removefacet(qh, facet);  /* visible_list at end of qh->facet_list */
  qh_appendfacet(qh, facet);
  qh->num_visible= 1;
  if (facet->good)
    (*goodvisible)++;
  qh->visible_list= facet;
  facet->visible= True;
  facet->f.replace= NULL;
  if (qh->IStracing >=4)
    qh_errprint(qh, "visible", facet, NULL, NULL, NULL);
  qh->visit_id++;
  FORALLvisible_facets {
    if (visible->tricoplanar && !qh->TRInormals) {
      qh_fprintf(qh, qh->ferr, 6230, "qhull internal error (qh_findhorizon): does not work for tricoplanar facets.  Use option 'Q11'\n");
      qh_errexit(qh, qh_ERRqhull, visible, NULL);
    }
    if (qh_setsize(qh, visible->neighbors) == 0) {
      qh_fprintf(qh, qh->ferr, 6295, "qhull internal error (qh_findhorizon): visible facet f%d does not have neighbors\n", visible->id);
      qh_errexit(qh, qh_ERRqhull, visible, NULL);
    }
    visible->visitid= qh->visit_id;
    FOREACHneighbor_(visible) {
      if (neighbor->visitid == qh->visit_id)
        continue;
      neighbor->visitid= qh->visit_id;
      zzinc_(Znumvisibility);
      qh_distplane(qh, point, neighbor, &dist);
      if (dist > qh->MINvisible) {
        zinc_(Ztotvisible);
        qh_removefacet(qh, neighbor);  /* append to end of qh->visible_list */
        qh_appendfacet(qh, neighbor);
        neighbor->visible= True;
        neighbor->f.replace= NULL;
        qh->num_visible++;
        if (neighbor->good)
          (*goodvisible)++;
        if (qh->IStracing >=4)
          qh_errprint(qh, "visible", neighbor, NULL, NULL, NULL);
      }else {
        if (dist >= -qh->MAXcoplanar) {
          neighbor->coplanarhorizon= True;
          zzinc_(Zcoplanarhorizon);
          qh_joggle_restart(qh, "coplanar horizon");
          coplanar++;
          if (qh->MERGING) {
            if (dist > 0) {
              maximize_(qh->max_outside, dist);
              maximize_(qh->max_vertex, dist);
#if qh_MAXoutside
              maximize_(neighbor->maxoutside, dist);
#endif
            }else
              minimize_(qh->min_vertex, dist);  /* due to merge later */
          }
          trace2((qh, qh->ferr, 2057, "qh_findhorizon: point p%d is coplanar to horizon f%d, dist=%2.7g < qh->MINvisible(%2.7g)\n",
              qh_pointid(qh, point), neighbor->id, dist, qh->MINvisible));
        }else
          neighbor->coplanarhorizon= False;
        zinc_(Ztothorizon);
        numhorizon++;
        if (neighbor->good)
          (*goodhorizon)++;
        if (qh->IStracing >=4)
          qh_errprint(qh, "horizon", neighbor, NULL, NULL, NULL);
      }
    }
  }
  if (!numhorizon) {
    qh_joggle_restart(qh, "empty horizon");
    qh_fprintf(qh, qh->ferr, 6168, "qhull topology error (qh_findhorizon): empty horizon for p%d.  It was above all facets.\n", qh_pointid(qh, point));
    if (qh->num_facets < 100) {
      qh_printfacetlist(qh, qh->facet_list, NULL, True);
    }
    qh_errexit(qh, qh_ERRtopology, NULL, NULL);
  }
  trace1((qh, qh->ferr, 1041, "qh_findhorizon: %d horizon facets(good %d), %d visible(good %d), %d coplanar\n",
       numhorizon, *goodhorizon, qh->num_visible, *goodvisible, coplanar));
  if (qh->IStracing >= 4 && qh->num_facets < 100)
    qh_printlists(qh);
} /* findhorizon */

/*---------------------------------

  qh_joggle_restart(qh, reason )
    if joggle ('QJn') and not merging, restart on precision and topology errors
*/
void qh_joggle_restart(qhT *qh, const char *reason) {

  if (qh->JOGGLEmax < REALmax/2) {
    if (qh->ALLOWrestart && !qh->PREmerge && !qh->MERGEexact) {
      trace0((qh, qh->ferr, 26, "qh_joggle_restart: qhull restart because of %s\n", reason));
      /* May be called repeatedly if qh->ALLOWrestart */
      longjmp(qh->restartexit, qh_ERRprec);
    }
  }
} /* qh_joggle_restart */

/*---------------------------------

  qh_nextfurthest(qh, visible )
    returns next furthest point and visible facet for qh_addpoint()
    starts search at qh.facet_next

  returns:
    removes furthest point from outside set
    NULL if none available
    advances qh.facet_next over facets with empty outside sets

  design:
    for each facet from qh.facet_next
      if empty outside set
        advance qh.facet_next
      else if qh.NARROWhull
        determine furthest outside point
        if furthest point is not outside
          advance qh.facet_next(point will be coplanar)
    remove furthest point from outside set
*/
pointT *qh_nextfurthest(qhT *qh, facetT **visible) {
  facetT *facet;
  int size, idx, loopcount= 0;
  realT randr, dist;
  pointT *furthest;

  while ((facet= qh->facet_next) != qh->facet_tail) {
    if (!facet || loopcount++ > qh->num_facets) {
      qh_fprintf(qh, qh->ferr, 6406, "qhull internal error (qh_nextfurthest): null facet or infinite loop detected for qh.facet_next f%d facet_tail f%d\n",
        getid_(facet), getid_(qh->facet_tail));
      qh_printlists(qh);
      qh_errexit2(qh, qh_ERRqhull, facet, qh->facet_tail);
    }
    if (!facet->outsideset) {
      qh->facet_next= facet->next;
      continue;
    }
    SETreturnsize_(facet->outsideset, size);
    if (!size) {
      qh_setfree(qh, &facet->outsideset);
      qh->facet_next= facet->next;
      continue;
    }
    if (qh->NARROWhull) {
      if (facet->notfurthest)
        qh_furthestout(qh, facet);
      furthest= (pointT *)qh_setlast(facet->outsideset);
#if qh_COMPUTEfurthest
      qh_distplane(qh, furthest, facet, &dist);
      zinc_(Zcomputefurthest);
#else
      dist= facet->furthestdist;
#endif
      if (dist < qh->MINoutside) { /* remainder of outside set is coplanar for qh_outcoplanar */
        qh->facet_next= facet->next;
        continue;
      }
    }
    if (!qh->RANDOMoutside && !qh->VIRTUALmemory) {
      if (qh->PICKfurthest) {
        qh_furthestnext(qh /* qh.facet_list */);
        facet= qh->facet_next;
      }
      *visible= facet;
      return ((pointT *)qh_setdellast(facet->outsideset));
    }
    if (qh->RANDOMoutside) {
      int outcoplanar= 0;
      if (qh->NARROWhull) {
        FORALLfacets {
          if (facet == qh->facet_next)
            break;
          if (facet->outsideset)
            outcoplanar += qh_setsize(qh, facet->outsideset);
        }
      }
      randr= qh_RANDOMint;
      randr= randr/(qh_RANDOMmax+1);
      randr= floor((qh->num_outside - outcoplanar) * randr);
      idx= (int)randr;
      FORALLfacet_(qh->facet_next) {
        if (facet->outsideset) {
          SETreturnsize_(facet->outsideset, size);
          if (!size)
            qh_setfree(qh, &facet->outsideset);
          else if (size > idx) {
            *visible= facet;
            return ((pointT *)qh_setdelnth(qh, facet->outsideset, idx));
          }else
            idx -= size;
        }
      }
      qh_fprintf(qh, qh->ferr, 6169, "qhull internal error (qh_nextfurthest): num_outside %d is too low\nby at least %d, or a random real %g >= 1.0\n",
              qh->num_outside, idx+1, randr);
      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
    }else { /* VIRTUALmemory */
      facet= qh->facet_tail->previous;
      if (!(furthest= (pointT *)qh_setdellast(facet->outsideset))) {
        if (facet->outsideset)
          qh_setfree(qh, &facet->outsideset);
        qh_removefacet(qh, facet);
        qh_prependfacet(qh, facet, &qh->facet_list);
        continue;
      }
      *visible= facet;
      return furthest;
    }
  }
  return NULL;
} /* nextfurthest */

/*---------------------------------

  qh_partitionall(qh, vertices, points, numpoints )
    partitions all points in points/numpoints to the outsidesets of facets
    vertices= vertices in qh.facet_list(!partitioned)

  returns:
    builds facet->outsideset
    does not partition qh.GOODpoint
    if qh.ONLYgood && !qh.MERGING,
      does not partition qh.GOODvertex

  notes:
    faster if qh.facet_list sorted by anticipated size of outside set

  design:
    initialize pointset with all points
    remove vertices from pointset
    remove qh.GOODpointp from pointset (unless it's qh.STOPcone or qh.STOPpoint)
    for all facets
      for all remaining points in pointset
        compute distance from point to facet
        if point is outside facet
          remove point from pointset (by not reappending)
          update bestpoint
          append point or old bestpoint to facet's outside set
      append bestpoint to facet's outside set (furthest)
    for all points remaining in pointset
      partition point into facets' outside sets and coplanar sets
*/
void qh_partitionall(qhT *qh, setT *vertices, pointT *points, int numpoints){
  setT *pointset;
  vertexT *vertex, **vertexp;
  pointT *point, **pointp, *bestpoint;
  int size, point_i, point_n, point_end, remaining, i, id;
  facetT *facet;
  realT bestdist= -REALmax, dist, distoutside;

  trace1((qh, qh->ferr, 1042, "qh_partitionall: partition all points into outside sets\n"));
  pointset= qh_settemp(qh, numpoints);
  qh->num_outside= 0;
  pointp= SETaddr_(pointset, pointT);
  for (i=numpoints, point= points; i--; point += qh->hull_dim)
    *(pointp++)= point;
  qh_settruncate(qh, pointset, numpoints);
  FOREACHvertex_(vertices) {
    if ((id= qh_pointid(qh, vertex->point)) >= 0)
      SETelem_(pointset, id)= NULL;
  }
  id= qh_pointid(qh, qh->GOODpointp);
  if (id >=0 && qh->STOPcone-1 != id && -qh->STOPpoint-1 != id)
    SETelem_(pointset, id)= NULL;
  if (qh->GOODvertexp && qh->ONLYgood && !qh->MERGING) { /* matches qhull()*/
    if ((id= qh_pointid(qh, qh->GOODvertexp)) >= 0)
      SETelem_(pointset, id)= NULL;
  }
  if (!qh->BESToutside) {  /* matches conditional for qh_partitionpoint below */
    distoutside= qh_DISToutside; /* multiple of qh.MINoutside & qh.max_outside, see user_r.h */
    zval_(Ztotpartition)= qh->num_points - qh->hull_dim - 1; /*misses GOOD... */
    remaining= qh->num_facets;
    point_end= numpoints;
    FORALLfacets {
      size= point_end/(remaining--) + 100;
      facet->outsideset= qh_setnew(qh, size);
      bestpoint= NULL;
      point_end= 0;
      FOREACHpoint_i_(qh, pointset) {
        if (point) {
          zzinc_(Zpartitionall);
          qh_distplane(qh, point, facet, &dist);
          if (dist < distoutside)
            SETelem_(pointset, point_end++)= point;
          else {
            qh->num_outside++;
            if (!bestpoint) {
              bestpoint= point;
              bestdist= dist;
            }else if (dist > bestdist) {
              qh_setappend(qh, &facet->outsideset, bestpoint);
              bestpoint= point;
              bestdist= dist;
            }else
              qh_setappend(qh, &facet->outsideset, point);
          }
        }
      }
      if (bestpoint) {
        qh_setappend(qh, &facet->outsideset, bestpoint);
#if !qh_COMPUTEfurthest
        facet->furthestdist= bestdist;
#endif
      }else
        qh_setfree(qh, &facet->outsideset);
      qh_settruncate(qh, pointset, point_end);
    }
  }
  /* if !qh->BESToutside, pointset contains points not assigned to outsideset */
  if (qh->BESToutside || qh->MERGING || qh->KEEPcoplanar || qh->KEEPinside || qh->KEEPnearinside) {
    qh->findbestnew= True;
    FOREACHpoint_i_(qh, pointset) {
      if (point)
        qh_partitionpoint(qh, point, qh->facet_list);
    }
    qh->findbestnew= False;
  }
  zzadd_(Zpartitionall, zzval_(Zpartition));
  zzval_(Zpartition)= 0;
  qh_settempfree(qh, &pointset);
  if (qh->IStracing >= 4)
    qh_printfacetlist(qh, qh->facet_list, NULL, True);
} /* partitionall */


/*---------------------------------

  qh_partitioncoplanar(qh, point, facet, dist, allnew )
    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 allnew (qh.findbestnew)
      searches new facets instead of using qh_findbest()

  returns:
    qh.max_ouside updated
    if qh.KEEPcoplanar or qh.KEEPinside
      point assigned to best coplanarset
    qh.repart_facetid==0 (for detecting infinite recursion via qh_partitionpoint)

  notes:
    facet->maxoutside is updated at end by qh_check_maxout

  design:
    if dist undefined
      find best facet for point
      if point sufficiently below facet (depends on qh.NEARinside and qh.KEEPinside)
        exit
    if keeping coplanar/nearinside/inside points
      if point is above furthest coplanar point
        append point to coplanar set (it is the new furthest)
        update qh.max_outside
      else
        append point one before end of coplanar set
    else if point is clearly outside of qh.max_outside and bestfacet->coplanarset
    and bestfacet is more than perpendicular to facet
      repartition the point using qh_findbest() -- it may be put on an outsideset
    else
      update qh.max_outside
*/
void qh_partitioncoplanar(qhT *qh, pointT *point, facetT *facet, realT *dist, boolT allnew) {
  facetT *bestfacet;
  pointT *oldfurthest;
  realT bestdist, angle, nearest, dist2= 0.0;
  int numpart= 0;
  boolT isoutside, oldfindbest, repartition= False;

  trace4((qh, qh->ferr, 4090, "qh_partitioncoplanar: partition coplanar point p%d starting with f%d dist? %2.2g, allnew? %d, gh.repart_facetid f%d\n",
    qh_pointid(qh, point), facet->id, (dist ? *dist : 0.0), allnew, qh->repart_facetid));
  qh->WAScoplanar= True;
  if (!dist) {
    if (allnew)
      bestfacet= qh_findbestnew(qh, point, facet, &bestdist, qh_ALL, &isoutside, &numpart);
    else
      bestfacet= qh_findbest(qh, point, facet, qh_ALL, !qh_ISnewfacets, qh->DELAUNAY,
                          &bestdist, &isoutside, &numpart);
    zinc_(Ztotpartcoplanar);
    zzadd_(Zpartcoplanar, numpart);
    if (!qh->DELAUNAY && !qh->KEEPinside) { /*  for 'd', bestdist skips upperDelaunay facets */
      if (qh->KEEPnearinside) {
        if (bestdist < -qh->NEARinside) {
          zinc_(Zcoplanarinside);
          trace4((qh, qh->ferr, 4062, "qh_partitioncoplanar: point p%d is more than near-inside facet f%d dist %2.2g allnew? %d\n",
                  qh_pointid(qh, point), bestfacet->id, bestdist, allnew));
          qh->repart_facetid= 0;
          return;
        }
      }else if (bestdist < -qh->MAXcoplanar) {
          trace4((qh, qh->ferr, 4063, "qh_partitioncoplanar: point p%d is inside facet f%d dist %2.2g allnew? %d\n",
                  qh_pointid(qh, point), bestfacet->id, bestdist, allnew));
        zinc_(Zcoplanarinside);
        qh->repart_facetid= 0;
        return;
      }
    }
  }else {
    bestfacet= facet;
    bestdist= *dist;
  }
  if(bestfacet->visible){
    qh_fprintf(qh, qh->ferr, 6405, "qhull internal error (qh_partitioncoplanar): cannot partition coplanar p%d of f%d into visible facet f%d\n",
        qh_pointid(qh, point), facet->id, bestfacet->id);
    qh_errexit2(qh, qh_ERRqhull, facet, bestfacet);
  }
  if (bestdist > qh->max_outside) {
    if (!dist && facet != bestfacet) { /* can't be recursive from qh_partitionpoint since facet != bestfacet */
      zinc_(Zpartangle);
      angle= qh_getangle(qh, facet->normal, bestfacet->normal);
      if (angle < 0) {
        nearest= qh_vertex_bestdist(qh, bestfacet->vertices);
        /* typically due to deleted vertex and coplanar facets, e.g.,
        RBOX 1000 s Z1 G1e-13 t1001185205 | QHULL Tv */
        zinc_(Zpartcorner);
        trace2((qh, qh->ferr, 2058, "qh_partitioncoplanar: repartition coplanar point p%d from f%d as an outside point above corner facet f%d dist %2.2g with angle %2.2g\n",
          qh_pointid(qh, point), facet->id, bestfacet->id, bestdist, angle));
        repartition= True;
      }
    }
    if (!repartition) {
      if (bestdist > qh->MAXoutside * qh_RATIOcoplanaroutside) {
        nearest= qh_vertex_bestdist(qh, bestfacet->vertices);
        if (facet->id == bestfacet->id) {
          if (facet->id == qh->repart_facetid) {
            qh_fprintf(qh, qh->ferr, 6404, "Qhull internal error (qh_partitioncoplanar): infinite loop due to recursive call to qh_partitionpoint.  Repartition point p%d from f%d as a outside point dist %2.2g nearest vertices %2.2g\n",
              qh_pointid(qh, point), facet->id, bestdist, nearest);
            qh_errexit(qh, qh_ERRqhull, facet, NULL);
          }
          qh->repart_facetid= facet->id; /* reset after call to qh_partitionpoint */
        }
        if (point == qh->coplanar_apex) {
          /* otherwise may loop indefinitely, the point is well above a facet, yet near a vertex */
          qh_fprintf(qh, qh->ferr, 6425, "Qhull topology error (qh_partitioncoplanar): can not repartition coplanar point p%d from f%d as outside point above f%d.  It previously failed to form a cone of facets, dist %2.2g, nearest vertices %2.2g\n",
            qh_pointid(qh, point), facet->id, bestfacet->id, bestdist, nearest);
          qh_errexit(qh, qh_ERRtopology, facet, NULL);
        }
        if (nearest < 2 * qh->MAXoutside * qh_RATIOcoplanaroutside) {
          zinc_(Zparttwisted);
          qh_fprintf(qh, qh->ferr, 7085, "Qhull precision warning: repartition coplanar point p%d from f%d as an outside point above twisted facet f%d dist %2.2g nearest vertices %2.2g\n",
            qh_pointid(qh, point), facet->id, bestfacet->id, bestdist, nearest);
        }else {
          zinc_(Zparthidden);
          qh_fprintf(qh, qh->ferr, 7086, "Qhull precision warning: repartition coplanar point p%d from f%d as an outside point above hidden facet f%d dist %2.2g nearest vertices %2.2g\n",
            qh_pointid(qh, point), facet->id, bestfacet->id, bestdist, nearest);
        }
        repartition= True;
      }
    }
    if (repartition) {
      oldfindbest= qh->findbestnew;
      qh->findbestnew= False;
      qh_partitionpoint(qh, point, bestfacet);
      qh->findbestnew= oldfindbest;
      qh->repart_facetid= 0;
      return;
    }
    qh->repart_facetid= 0;
    qh->max_outside= bestdist;
    if (bestdist > qh->TRACEdist || qh->IStracing >= 3) {
      qh_fprintf(qh, qh->ferr, 3041, "qh_partitioncoplanar: == p%d from f%d increases qh.max_outside to %2.2g of f%d last p%d\n",
                     qh_pointid(qh, point), facet->id, bestdist, bestfacet->id, qh->furthest_id);
      qh_errprint(qh, "DISTANT", facet, bestfacet, NULL, NULL);
    }
  }
  if (qh->KEEPcoplanar + qh->KEEPinside + qh->KEEPnearinside) {
    oldfurthest= (pointT *)qh_setlast(bestfacet->coplanarset);
    if (oldfurthest) {
      zinc_(Zcomputefurthest);
      qh_distplane(qh, oldfurthest, bestfacet, &dist2);
    }
    if (!oldfurthest || dist2 < bestdist)
      qh_setappend(qh, &bestfacet->coplanarset, point);
    else
      qh_setappend2ndlast(qh, &bestfacet->coplanarset, point);
  }
  trace4((qh, qh->ferr, 4064, "qh_partitioncoplanar: point p%d is coplanar with facet f%d (or inside) dist %2.2g\n",
          qh_pointid(qh, point), bestfacet->id, bestdist));
} /* partitioncoplanar */

/*---------------------------------

  qh_partitionpoint(qh, point, facet )
    assigns point to an outside set, coplanar set, or inside set (i.e., dropt)
    if qh.findbestnew
      uses qh_findbestnew() to search all new facets
    else
      uses qh_findbest()

  notes:
    after qh_distplane(), this and qh_findbest() are most expensive in 3-d

  design:
    find best facet for point
      (either exhaustive search of new facets or directed search from facet)
    if qh.NARROWhull
      retain coplanar and nearinside points as outside points
    if point is outside bestfacet
      if point above furthest point for bestfacet
        append point to outside set (it becomes the new furthest)
        if outside set was empty
          move bestfacet to end of qh.facet_list (i.e., after qh.facet_next)
        update bestfacet->furthestdist
      else
        append point one before end of outside set
    else if point is coplanar to bestfacet
      if keeping coplanar points or need to update qh.max_outside
        partition coplanar point into bestfacet
    else if near-inside point
      partition as coplanar point into bestfacet
    else is an inside point
      if keeping inside points
        partition as coplanar point into bestfacet
*/
void qh_partitionpoint(qhT *qh, pointT *point, facetT *facet) {
  realT bestdist, previousdist;
  boolT isoutside, isnewoutside= False;
  facetT *bestfacet;
  int numpart;

  if (qh->findbestnew)
    bestfacet= qh_findbestnew(qh, point, facet, &bestdist, qh->BESToutside, &isoutside, &numpart);
  else
    bestfacet= qh_findbest(qh, point, facet, qh->BESToutside, qh_ISnewfacets, !qh_NOupper,
                          &bestdist, &isoutside, &numpart);
  zinc_(Ztotpartition);
  zzadd_(Zpartition, numpart);
  if(bestfacet->visible){
    qh_fprintf(qh, qh->ferr, 6293, "qhull internal error (qh_partitionpoint): cannot partition p%d of f%d into visible facet f%d\n",
      qh_pointid(qh, point), facet->id, bestfacet->id);
    qh_errexit2(qh, qh_ERRqhull, facet, bestfacet);
  }
  if (qh->NARROWhull) {
    if (qh->DELAUNAY && !isoutside && bestdist >= -qh->MAXcoplanar)
      qh_joggle_restart(qh, "nearly incident point (narrow hull)");
    if (qh->KEEPnearinside) {
      if (bestdist >= -qh->NEARinside)
        isoutside= True;
    }else if (bestdist >= -qh->MAXcoplanar)
      isoutside= True;
  }

  if (isoutside) {
    if (!bestfacet->outsideset
    || !qh_setlast(bestfacet->outsideset)) { /* empty outside set */
      qh_setappend(qh, &(bestfacet->outsideset), point);
      if (!qh->NARROWhull || bestdist > qh->MINoutside)
        isnewoutside= True;
#if !qh_COMPUTEfurthest
      bestfacet->furthestdist= bestdist;
#endif
    }else {
#if qh_COMPUTEfurthest
      zinc_(Zcomputefurthest);
      qh_distplane(qh, oldfurthest, bestfacet, &previousdist);
      if (previousdist < bestdist)
        qh_setappend(qh, &(bestfacet->outsideset), point);
      else
        qh_setappend2ndlast(qh, &(bestfacet->outsideset), point);
#else
      previousdist= bestfacet->furthestdist;
      if (previousdist < bestdist) {
        qh_setappend(qh, &(bestfacet->outsideset), point);
        bestfacet->furthestdist= bestdist;
        if (qh->NARROWhull && previousdist < qh->MINoutside && bestdist >= qh->MINoutside)
          isnewoutside= True;
      }else
        qh_setappend2ndlast(qh, &(bestfacet->outsideset), point);
#endif
    }
    if (isnewoutside && qh->facet_next != bestfacet) {
      if (bestfacet->newfacet) {
        if (qh->facet_next->newfacet)
          qh->facet_next= qh->newfacet_list; /* make sure it's after qh.facet_next */
      }else {
        qh_removefacet(qh, bestfacet);  /* make sure it's after qh.facet_next */
        qh_appendfacet(qh, bestfacet);
        if(qh->newfacet_list){
          bestfacet->newfacet= True;
        }
      }
    }
    qh->num_outside++;
    trace4((qh, qh->ferr, 4065, "qh_partitionpoint: point p%d is outside facet f%d newfacet? %d, newoutside? %d (or narrowhull)\n",
          qh_pointid(qh, point), bestfacet->id, bestfacet->newfacet, isnewoutside));
  }else if (qh->DELAUNAY || bestdist >= -qh->MAXcoplanar) { /* for 'd', bestdist skips upperDelaunay facets */
    if (qh->DELAUNAY)
      qh_joggle_restart(qh, "nearly incident point");
    /* allow coplanar points with joggle, may be interior */
    zzinc_(Zcoplanarpart);
    if ((qh->KEEPcoplanar + qh->KEEPnearinside) || bestdist > qh->max_outside)
      qh_partitioncoplanar(qh, point, bestfacet, &bestdist, qh->findbestnew);
    else {
      trace4((qh, qh->ferr, 4066, "qh_partitionpoint: point p%d is coplanar to facet f%d (dropped)\n",
          qh_pointid(qh, point), bestfacet->id));
    }
  }else if (qh->KEEPnearinside && bestdist >= -qh->NEARinside) {
    zinc_(Zpartnear);
    qh_partitioncoplanar(qh, point, bestfacet, &bestdist, qh->findbestnew);
  }else {
    zinc_(Zpartinside);
    trace4((qh, qh->ferr, 4067, "qh_partitionpoint: point p%d is inside all facets, closest to f%d dist %2.2g\n",
          qh_pointid(qh, point), bestfacet->id, bestdist));
    if (qh->KEEPinside)
      qh_partitioncoplanar(qh, point, bestfacet, &bestdist, qh->findbestnew);
  }
} /* partitionpoint */

/*---------------------------------

  qh_partitionvisible(qh, allpoints, numoutside )
    partitions outside points in visible facets (qh.visible_list) to qh.newfacet_list
    if keeping coplanar/near-inside/inside points
      partitions coplanar points; repartitions if 'allpoints' (not used)
    1st neighbor (if any) of visible facets points to a horizon facet or a new facet

  returns:
    updates outside sets and coplanar sets of qh.newfacet_list
    updates qh.num_outside (count of outside points)
    does not truncate f.outsideset, f.coplanarset, or qh.del_vertices (see qh_deletevisible)

  notes:
    called by qh_qhull, qh_addpoint, and qh_all_vertexmerges
    qh.findbest_notsharp should be clear (extra work if set)

  design:
    for all visible facets with outside set or coplanar set
      select a newfacet for visible facet
      if outside set
        partition outside set into new facets
      if coplanar set and keeping coplanar/near-inside/inside points
        if allpoints
          partition coplanar set into new facets, may be assigned outside
        else
          partition coplanar set into coplanar sets of new facets
    for each deleted vertex
      if allpoints
        partition vertex into new facets, may be assigned outside
      else
        partition vertex into coplanar sets of new facets
*/
void qh_partitionvisible(qhT *qh, boolT allpoints, int *numoutside /* qh.visible_list */) {
  facetT *visible, *newfacet;
  pointT *point, **pointp;
  int delsize, coplanar=0, size;
  vertexT *vertex, **vertexp;

  trace3((qh, qh->ferr, 3042, "qh_partitionvisible: partition outside and coplanar points of visible and merged facets f%d into new facets f%d\n",
    qh->visible_list->id, qh->newfacet_list->id));
  if (qh->ONLYmax)
    maximize_(qh->MINoutside, qh->max_vertex);
  *numoutside= 0;
  FORALLvisible_facets {
    if (!visible->outsideset && !visible->coplanarset)
      continue;
    newfacet= qh_getreplacement(qh, visible);
    if (!newfacet)
      newfacet= qh->newfacet_list;
    if (!newfacet->next) {
      qh_fprintf(qh, qh->ferr, 6170, "qhull topology error (qh_partitionvisible): all new facets deleted as\n       degenerate facets. Can not continue.\n");
      qh_errexit(qh, qh_ERRtopology, NULL, NULL);
    }
    if (visible->outsideset) {
      size= qh_setsize(qh, visible->outsideset);
      *numoutside += size;
      qh->num_outside -= size;
      FOREACHpoint_(visible->outsideset)
        qh_partitionpoint(qh, point, newfacet);
    }
    if (visible->coplanarset && (qh->KEEPcoplanar + qh->KEEPinside + qh->KEEPnearinside)) {
      size= qh_setsize(qh, visible->coplanarset);
      coplanar += size;
      FOREACHpoint_(visible->coplanarset) {
        if (allpoints) /* not used */
          qh_partitionpoint(qh, point, newfacet);
        else
          qh_partitioncoplanar(qh, point, newfacet, NULL, qh->findbestnew);
      }
    }
  }
  delsize= qh_setsize(qh, qh->del_vertices);
  if (delsize > 0) {
    trace3((qh, qh->ferr, 3049, "qh_partitionvisible: partition %d deleted vertices as coplanar? %d points into new facets f%d\n",
      delsize, !allpoints, qh->newfacet_list->id));
    FOREACHvertex_(qh->del_vertices) {
      if (vertex->point && !vertex->partitioned) {
        if (!qh->newfacet_list || qh->newfacet_list == qh->facet_tail) {
          qh_fprintf(qh, qh->ferr, 6284, "qhull internal error (qh_partitionvisible): all new facets deleted or none defined.  Can not partition deleted v%d.\n", vertex->id);
          qh_errexit(qh, qh_ERRqhull, NULL, NULL);
        }
        if (allpoints) /* not used */
          /* [apr'2019] infinite loop if vertex recreates the same facets from the same horizon
             e.g., qh_partitionpoint if qh.DELAUNAY with qh.MERGEindependent for all mergetype, ../eg/qtest.sh t427764 '1000 s W1e-13 D3' 'd' */
          qh_partitionpoint(qh, vertex->point, qh->newfacet_list);
        else
          qh_partitioncoplanar(qh, vertex->point, qh->newfacet_list, NULL, qh_ALL); /* search all new facets */
        vertex->partitioned= True;
      }
    }
  }
  trace1((qh, qh->ferr, 1043,"qh_partitionvisible: partitioned %d points from outsidesets, %d points from coplanarsets, and %d deleted vertices\n", *numoutside, coplanar, delsize));
} /* partitionvisible */

/*---------------------------------

  qh_printsummary(qh, fp )
    prints summary to fp

  notes:
    not in io_r.c so that user_eg.c can prevent io_r.c from loading
    qh_printsummary and qh_countfacets must match counts
    updates qh.facet_visit to detect infinite loop

  design:
    determine number of points, vertices, and coplanar points
    print summary
*/
void qh_printsummary(qhT *qh, FILE *fp) {
  realT ratio, outerplane, innerplane;
  double cpu;
  int size, id, nummerged, numpinched, numvertices, numcoplanars= 0, nonsimplicial=0, numdelaunay= 0;
  facetT *facet;
  const char *s;
  int numdel= zzval_(Zdelvertextot);
  int numtricoplanars= 0;
  boolT goodused;

  size= qh->num_points + qh_setsize(qh, qh->other_points);
  numvertices= qh->num_vertices - qh_setsize(qh, qh->del_vertices);
  id= qh_pointid(qh, qh->GOODpointp);
  if (!qh_checklists(qh, qh->facet_list) && !qh->ERREXITcalled) {
    qh_fprintf(qh, fp, 6372, "qhull internal error: qh_checklists failed at qh_printsummary\n");
    if (qh->num_facets < 4000)
      qh_printlists(qh);
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  if (qh->DELAUNAY && qh->ERREXITcalled) {
    /* update f.good and determine qh.num_good as in qh_findgood_all */
    FORALLfacets {
      if (facet->visible)
        facet->good= False; /* will be deleted */
      else if (facet->good) {
        if (facet->normal && !qh_inthresholds(qh, facet->normal, NULL))
          facet->good= False;
        else
          numdelaunay++;
      }
    }
    qh->num_good= numdelaunay;
  }
  FORALLfacets {
    if (facet->coplanarset)
      numcoplanars += qh_setsize(qh, facet->coplanarset);
    if (facet->good) {
      if (facet->simplicial) {
        if (facet->keepcentrum && facet->tricoplanar)
          numtricoplanars++;
      }else if (qh_setsize(qh, facet->vertices) != qh->hull_dim)
        nonsimplicial++;
    }
  }
  if (id >=0 && qh->STOPcone-1 != id && -qh->STOPpoint-1 != id)
    size--;
  if (qh->STOPadd || qh->STOPcone || qh->STOPpoint)
    qh_fprintf(qh, fp, 9288, "\nEarly exit due to 'TAn', 'TVn', 'TCn', 'TRn', or precision error with 'QJn'.");
  goodused= False;
  if (qh->ERREXITcalled)
    ; /* qh_findgood_all not called */
  else if (qh->UPPERdelaunay) {
    if (qh->GOODvertex || qh->GOODpoint || qh->SPLITthresholds)
      goodused= True;
  }else if (qh->DELAUNAY) {
    if (qh->GOODvertex || qh->GOODpoint || qh->GOODthreshold)
      goodused= True;
  }else if (qh->num_good > 0 || qh->GOODthreshold)
    goodused= True;
  nummerged= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
  if (qh->VORONOI) {
    if (qh->UPPERdelaunay)
      qh_fprintf(qh, fp, 9289, "\n\
Furthest-site Voronoi vertices by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);
    else
      qh_fprintf(qh, fp, 9290, "\n\
Voronoi diagram by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);
    qh_fprintf(qh, fp, 9291, "  Number of Voronoi regions%s: %d\n",
              qh->ATinfinity ? " and at-infinity" : "", numvertices);
    if (numdel)
      qh_fprintf(qh, fp, 9292, "  Total number of deleted points due to merging: %d\n", numdel);
    if (numcoplanars - numdel > 0)
      qh_fprintf(qh, fp, 9293, "  Number of nearly incident points: %d\n", numcoplanars - numdel);
    else if (size - numvertices - numdel > 0)
      qh_fprintf(qh, fp, 9294, "  Total number of nearly incident points: %d\n", size - numvertices - numdel);
    qh_fprintf(qh, fp, 9295, "  Number of%s Voronoi vertices: %d\n",
              goodused ? " 'good'" : "", qh->num_good);
    if (nonsimplicial)
      qh_fprintf(qh, fp, 9296, "  Number of%s non-simplicial Voronoi vertices: %d\n",
              goodused ? " 'good'" : "", nonsimplicial);
  }else if (qh->DELAUNAY) {
    if (qh->UPPERdelaunay)
      qh_fprintf(qh, fp, 9297, "\n\
Furthest-site Delaunay triangulation by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);
    else
      qh_fprintf(qh, fp, 9298, "\n\
Delaunay triangulation by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);
    qh_fprintf(qh, fp, 9299, "  Number of input sites%s: %d\n",
              qh->ATinfinity ? " and at-infinity" : "", numvertices);
    if (numdel)
      qh_fprintf(qh, fp, 9300, "  Total number of deleted points due to merging: %d\n", numdel);
    if (numcoplanars - numdel > 0)
      qh_fprintf(qh, fp, 9301, "  Number of nearly incident points: %d\n", numcoplanars - numdel);
    else if (size - numvertices - numdel > 0)
      qh_fprintf(qh, fp, 9302, "  Total number of nearly incident points: %d\n", size - numvertices - numdel);
    qh_fprintf(qh, fp, 9303, "  Number of%s Delaunay regions: %d\n",
              goodused ? " 'good'" : "", qh->num_good);
    if (nonsimplicial)
      qh_fprintf(qh, fp, 9304, "  Number of%s non-simplicial Delaunay regions: %d\n",
              goodused ? " 'good'" : "", nonsimplicial);
  }else if (qh->HALFspace) {
    qh_fprintf(qh, fp, 9305, "\n\
Halfspace intersection by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);
    qh_fprintf(qh, fp, 9306, "  Number of halfspaces: %d\n", size);
    qh_fprintf(qh, fp, 9307, "  Number of non-redundant halfspaces: %d\n", numvertices);
    if (numcoplanars) {
      if (qh->KEEPinside && qh->KEEPcoplanar)
        s= "similar and redundant";
      else if (qh->KEEPinside)
        s= "redundant";
      else
        s= "similar";
      qh_fprintf(qh, fp, 9308, "  Number of %s halfspaces: %d\n", s, numcoplanars);
    }
    qh_fprintf(qh, fp, 9309, "  Number of intersection points: %d\n", qh->num_facets - qh->num_visible);
    if (goodused)
      qh_fprintf(qh, fp, 9310, "  Number of 'good' intersection points: %d\n", qh->num_good);
    if (nonsimplicial)
      qh_fprintf(qh, fp, 9311, "  Number of%s non-simplicial intersection points: %d\n",
              goodused ? " 'good'" : "", nonsimplicial);
  }else {
    qh_fprintf(qh, fp, 9312, "\n\
Convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);
    qh_fprintf(qh, fp, 9313, "  Number of vertices: %d\n", numvertices);
    if (numcoplanars) {
      if (qh->KEEPinside && qh->KEEPcoplanar)
        s= "coplanar and interior";
      else if (qh->KEEPinside)
        s= "interior";
      else
        s= "coplanar";
      qh_fprintf(qh, fp, 9314, "  Number of %s points: %d\n", s, numcoplanars);
    }
    qh_fprintf(qh, fp, 9315, "  Number of facets: %d\n", qh->num_facets - qh->num_visible);
    if (goodused)
      qh_fprintf(qh, fp, 9316, "  Number of 'good' facets: %d\n", qh->num_good);
    if (nonsimplicial)
      qh_fprintf(qh, fp, 9317, "  Number of%s non-simplicial facets: %d\n",
              goodused ? " 'good'" : "", nonsimplicial);
  }
  if (numtricoplanars)
      qh_fprintf(qh, fp, 9318, "  Number of triangulated facets: %d\n", numtricoplanars);
  qh_fprintf(qh, fp, 9319, "\nStatistics for: %s | %s",
                      qh->rbox_command, qh->qhull_command);
  if (qh->ROTATErandom != INT_MIN)
    qh_fprintf(qh, fp, 9320, " QR%d\n\n", qh->ROTATErandom);
  else
    qh_fprintf(qh, fp, 9321, "\n\n");
  qh_fprintf(qh, fp, 9322, "  Number of points processed: %d\n", zzval_(Zprocessed));
  qh_fprintf(qh, fp, 9323, "  Number of hyperplanes created: %d\n", zzval_(Zsetplane));
  if (qh->DELAUNAY)
    qh_fprintf(qh, fp, 9324, "  Number of facets in hull: %d\n", qh->num_facets - qh->num_visible);
  qh_fprintf(qh, fp, 9325, "  Number of distance tests for qhull: %d\n", zzval_(Zpartition)+
      zzval_(Zpartitionall)+zzval_(Znumvisibility)+zzval_(Zpartcoplanar));
#if 0  /* NOTE: must print before printstatistics() */
  {realT stddev, ave;
  qh_fprintf(qh, fp, 9326, "  average new facet balance: %2.2g\n",
          wval_(Wnewbalance)/zval_(Zprocessed));
  stddev= qh_stddev(zval_(Zprocessed), wval_(Wnewbalance),
                                 wval_(Wnewbalance2), &ave);
  qh_fprintf(qh, fp, 9327, "  new facet standard deviation: %2.2g\n", stddev);
  qh_fprintf(qh, fp, 9328, "  average partition balance: %2.2g\n",
          wval_(Wpbalance)/zval_(Zpbalance));
  stddev= qh_stddev(zval_(Zpbalance), wval_(Wpbalance),
                                 wval_(Wpbalance2), &ave);
  qh_fprintf(qh, fp, 9329, "  partition standard deviation: %2.2g\n", stddev);
  }
#endif
  if (nummerged) {
    qh_fprintf(qh, fp, 9330,"  Number of distance tests for merging: %d\n",zzval_(Zbestdist)+
          zzval_(Zcentrumtests)+zzval_(Zvertextests)+zzval_(Zdistcheck)+zzval_(Zdistzero));
    qh_fprintf(qh, fp, 9331,"  Number of distance tests for checking: %d\n",zzval_(Zcheckpart)+zzval_(Zdistconvex));
    qh_fprintf(qh, fp, 9332,"  Number of merged facets: %d\n", nummerged);
  }
  numpinched= zzval_(Zpinchduplicate) + zzval_(Zpinchedvertex);
  if (numpinched)
    qh_fprintf(qh, fp, 9375,"  Number of merged pinched vertices: %d\n", numpinched);
  if (!qh->RANDOMoutside && qh->QHULLfinished) {
    cpu= (double)qh->hulltime;
    cpu /= (double)qh_SECticks;
    wval_(Wcpu)= cpu;
    qh_fprintf(qh, fp, 9333, "  CPU seconds to compute hull (after input): %2.4g\n", cpu);
  }
  if (qh->RERUN) {
    if (!qh->PREmerge && !qh->MERGEexact)
      qh_fprintf(qh, fp, 9334, "  Percentage of runs with precision errors: %4.1f\n",
           zzval_(Zretry)*100.0/qh->build_cnt);  /* careful of order */
  }else if (qh->JOGGLEmax < REALmax/2) {
    if (zzval_(Zretry))
      qh_fprintf(qh, fp, 9335, "  After %d retries, input joggled by: %2.2g\n",
         zzval_(Zretry), qh->JOGGLEmax);
    else
      qh_fprintf(qh, fp, 9336, "  Input joggled by: %2.2g\n", qh->JOGGLEmax);
  }
  if (qh->totarea != 0.0)
    qh_fprintf(qh, fp, 9337, "  %s facet area:   %2.8g\n",
            zzval_(Ztotmerge) ? "Approximate" : "Total", qh->totarea);
  if (qh->totvol != 0.0)
    qh_fprintf(qh, fp, 9338, "  %s volume:       %2.8g\n",
            zzval_(Ztotmerge) ? "Approximate" : "Total", qh->totvol);
  if (qh->MERGING) {
    qh_outerinner(qh, NULL, &outerplane, &innerplane);
    if (outerplane > 2 * qh->DISTround) {
      qh_fprintf(qh, fp, 9339, "  Maximum distance of point above facet: %2.2g", outerplane);
      ratio= outerplane/(qh->ONEmerge + qh->DISTround);
      /* don't report ratio if MINoutside is large */
      if (ratio > 0.05 && 2* qh->ONEmerge > qh->MINoutside && qh->JOGGLEmax > REALmax/2)
        qh_fprintf(qh, fp, 9340, " (%.1fx)\n", ratio);
      else
        qh_fprintf(qh, fp, 9341, "\n");
    }
    if (innerplane < -2 * qh->DISTround) {
      qh_fprintf(qh, fp, 9342, "  Maximum distance of vertex below facet: %2.2g", innerplane);
      ratio= -innerplane/(qh->ONEmerge+qh->DISTround);
      if (ratio > 0.05 && qh->JOGGLEmax > REALmax/2)
        qh_fprintf(qh, fp, 9343, " (%.1fx)\n", ratio);
      else
        qh_fprintf(qh, fp, 9344, "\n");
    }
  }
  qh_fprintf(qh, fp, 9345, "\n");
} /* printsummary */


qhull-2020.2/src/libqhull_r/libqhull_r.h0000644060175106010010000016650013723600675016441 0ustar  bbarber/*
  ---------------------------------

   libqhull_r.h
   user-level header file for using qhull.a library

   see qh-qhull_r.htm, qhull_ra.h

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull_r/libqhull_r.h#16 $$Change: 3037 $
   $DateTime: 2020/09/03 17:28:32 $$Author: bbarber $

   includes function prototypes for libqhull_r.c, geom_r.c, global_r.c, io_r.c, user_r.c

   use mem_r.h for mem_r.c
   use qset_r.h for qset_r.c

   see unix_r.c for an example of using libqhull_r.h

   recompile qhull if you change this file
*/

#ifndef qhDEFlibqhull
#define qhDEFlibqhull 1

/*=========================== -included files ==============*/

/* user_r.h first for QHULL_CRTDBG */
#include "user_r.h"      /* user definable constants (e.g., realT). */

#include "mem_r.h"   /* Needed for qhT in libqhull_r.h */
#include "qset_r.h"   /* Needed for QHULL_LIB_CHECK */
/* include stat_r.h after defining boolT.  Needed for qhT in libqhull_r.h */

#include 
#include 
#include 
#include 
#include 

#ifndef __STDC__
#ifndef __cplusplus
#if     !defined(_MSC_VER)
#error  Neither __STDC__ nor __cplusplus is defined.  Please use strict ANSI C or C++ to compile
#error  Qhull.  You may need to turn off compiler extensions in your project configuration.  If
#error  your compiler is a standard C compiler, you can delete this warning from libqhull_r.h
#endif
#endif
#endif

/*============ constants and basic types ====================*/

extern const char qh_version[]; /* defined in global_r.c */
extern const char qh_version2[]; /* defined in global_r.c */

/*----------------------------------

  coordT
    coordinates and coefficients are stored as realT (i.e., double)

  notes:
    Qhull works well if realT is 'float'.  If so joggle (QJ) is not effective.

    Could use 'float' for data and 'double' for calculations (realT vs. coordT)
      This requires many type casts, and adjusted error bounds.
      Also C compilers may do expressions in double anyway.
*/
#define coordT realT

/*----------------------------------

  pointT
    a point is an array of coordinates, usually qh.hull_dim
    qh_pointid returns
      qh_IDnone if point==0 or qh is undefined
      qh_IDinterior for qh.interior_point
      qh_IDunknown if point is neither in qh.first_point... nor qh.other_points

  notes:
    qh.STOPcone and qh.STOPpoint assume that qh_IDunknown==-1 (other negative numbers indicate points)
    qh_IDunknown is also returned by getid_() for unknown facet, ridge, or vertex
*/
#define pointT coordT
typedef enum
{
    qh_IDnone= -3, qh_IDinterior= -2, qh_IDunknown= -1
}
qh_pointT;

/*----------------------------------

  flagT
    Boolean flag as a bit
*/
#define flagT unsigned int

/*----------------------------------

  boolT
    boolean value, either True or False

  notes:
    needed for portability
    Use qh_False/qh_True as synonyms
*/
#define boolT unsigned int
#ifdef False
#undef False
#endif
#ifdef True
#undef True
#endif
#define False 0
#define True 1
#define qh_False 0
#define qh_True 1

#include "stat_r.h"  /* needs boolT */

/*----------------------------------

  qh_CENTER
    to distinguish facet->center
*/
typedef enum
{
    qh_ASnone= 0,    /* If not MERGING and not VORONOI */
    qh_ASvoronoi,    /* Set by qh_clearcenters on qh_prepare_output, or if not MERGING and VORONOI */
    qh_AScentrum     /* If MERGING (assumed during merging) */
}
qh_CENTER;

/*----------------------------------

  qh_PRINT
    output formats for printing (qh.PRINTout).
    'Fa' 'FV' 'Fc' 'FC'


   notes:
   some of these names are similar to qhT names.  The similar names are only
   used in switch statements in qh_printbegin() etc.
*/
typedef enum {qh_PRINTnone= 0,
  qh_PRINTarea, qh_PRINTaverage,           /* 'Fa' 'FV' 'Fc' 'FC' */
  qh_PRINTcoplanars, qh_PRINTcentrums,
  qh_PRINTfacets, qh_PRINTfacets_xridge,   /* 'f' 'FF' 'G' 'FI' 'Fi' 'Fn' */
  qh_PRINTgeom, qh_PRINTids, qh_PRINTinner, qh_PRINTneighbors,
  qh_PRINTnormals, qh_PRINTouter, qh_PRINTmaple, /* 'n' 'Fo' 'i' 'm' 'Fm' 'FM', 'o' */
  qh_PRINTincidences, qh_PRINTmathematica, qh_PRINTmerges, qh_PRINToff,
  qh_PRINToptions, qh_PRINTpointintersect, /* 'FO' 'Fp' 'FP' 'p' 'FQ' 'FS' */
  qh_PRINTpointnearest, qh_PRINTpoints, qh_PRINTqhull, qh_PRINTsize,
  qh_PRINTsummary, qh_PRINTtriangles,      /* 'Fs' 'Ft' 'Fv' 'FN' 'Fx' */
  qh_PRINTvertices, qh_PRINTvneighbors, qh_PRINTextremes,
  qh_PRINTEND} qh_PRINT;

/*----------------------------------

  qh_ALL
    argument flag for selecting everything
*/
#define qh_ALL      True
#define qh_NOupper  True      /* argument for qh_findbest */
#define qh_IScheckmax  True   /* argument for qh_findbesthorizon */
#define qh_ISnewfacets  True  /* argument for qh_findbest */
#define qh_RESETvisible  True /* argument for qh_resetlists */

/*----------------------------------

  qh_ERR...
    Qhull exit status codes, for indicating errors
    See: MSG_ERROR (6000) and MSG_WARNING (7000) [user_r.h]
*/
#define qh_ERRnone  0    /* no error occurred during qhull */
#define qh_ERRinput 1    /* input inconsistency */
#define qh_ERRsingular 2 /* singular input data, calls qh_printhelp_singular */
#define qh_ERRprec  3    /* precision error, calls qh_printhelp_degenerate */
#define qh_ERRmem   4    /* insufficient memory, matches mem_r.h */
#define qh_ERRqhull 5    /* internal error detected, matches mem_r.h, calls qh_printhelp_internal */
#define qh_ERRother 6    /* other error detected */
#define qh_ERRtopology 7 /* topology error, maybe due to nearly adjacent vertices, calls qh_printhelp_topology */
#define qh_ERRwide 8     /* wide facet error, maybe due to nearly adjacent vertices, calls qh_printhelp_wide */
#define qh_ERRdebug 9    /* qh_errexit from debugging code */

/*----------------------------------

qh_FILEstderr
Fake stderr to distinguish error output from normal output
For C++ interface.  Must redefine qh_fprintf_qhull
*/
#define qh_FILEstderr ((FILE *)1)

/* ============ -structures- ====================
   each of the following structures is defined by a typedef
   all realT and coordT fields occur at the beginning of a structure
        (otherwise space may be wasted due to alignment)
   define all flags together and pack into 32-bit number

   DEFqhT and DEFsetT are likewise defined in mem_r.h, qset_r.h, and stat_r.h
*/

typedef struct vertexT vertexT;
typedef struct ridgeT ridgeT;
typedef struct facetT facetT;

#ifndef DEFqhT
#define DEFqhT 1
typedef struct qhT qhT;          /* defined below */
#endif

#ifndef DEFsetT
#define DEFsetT 1
typedef struct setT setT;        /* defined in qset_r.h */
#endif

/*----------------------------------

  facetT
    defines a facet

  notes:
   qhull() generates the hull as a list of facets.

  topological information:
    f.previous,next     doubly-linked list of facets, next is always defined
    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 or Voronoi center for output
    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
*/
/* QhullFacet.cpp -- Update static initializer list for s_empty_facet if add or remove 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 qh_mergefacet
                        Actual outer plane is +DISTround and
                        computed outer plane is +2*DISTround.
                        Initial maxoutside is qh.DISTround, otherwise distance tests need to account for DISTround */
#endif
  coordT   offset;      /* exact offset of hyperplane from origin */
  coordT  *normal;      /* normal of hyperplane, hull_dim coefficients */
                        /*   if f.tricoplanar, shared with a neighbor */
  union {               /* in order of testing */
   realT   area;        /* area of facet, only in io_r.c if  f.isarea */
   facetT *replace;     /* replacement facet for qh.NEWfacets with f.visible
                             NULL if qh_mergedegen_redundant, interior, or !NEWfacets */
   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;      /* set according to qh.CENTERtype */
                        /*   qh_ASnone:    no center (not MERGING) */
                        /*   qh_AScentrum: centrum for testing convexity (qh_getcentrum) */
                        /*                 assumed qh_AScentrum while merging */
                        /*   qh_ASvoronoi: Voronoi center (qh_facetcenter) */
                        /* after constructing the hull, it may be changed (qh_clearcenter) */
                        /* if tricoplanar and !keepcentrum, shared with a neighbor */
  facetT  *previous;    /* previous facet in the facet_list or NULL, for C++ interface */
  facetT  *next;        /* next facet in the facet_list or facet_tail */
  setT    *vertices;    /* vertices for this facet, inverse sorted by ID
                           if simplicial, 1st vertex was apex/furthest
                           qh_reduce_vertices removes extraneous vertices via qh_remove_extravertices
                           if f.visible, vertices may be on qh.del_vertices */
  setT    *ridges;      /* explicit ridges for nonsimplicial facets or nonsimplicial neighbors.
                           For simplicial facets, neighbors define the ridges
                           qh_makeridges() converts simplicial facets by creating ridges prior to merging
                           If qh.NEWtentative, new facets have horizon ridge, but not vice versa
                           if f.visible && qh.NEWfacets, ridges is empty */
  setT    *neighbors;   /* neighbors of the facet.  Neighbors may be f.visible
                           If simplicial, the kth neighbor is opposite the kth vertex and the
                           first neighbor is the horizon facet for the first vertex.
                           dupridges marked by qh_DUPLICATEridge (0x01) and qh_MERGEridge (0x02)
                           if f.visible && qh.NEWfacets, neighbors is empty */
  setT    *outsideset;  /* set of points outside this facet
                           if non-empty, last point is furthest
                           if NARROWhull, includes coplanars (less than qh.MINoutside) 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 int visitid; /* visit_id, for visiting all neighbors,
                           all uses are independent */
  unsigned int id;      /* unique identifier from qh.facet_id, 1..qh.facet_id, 0 is sentinel, printed as 'f%d' */
  unsigned int nummerge:9; /* number of merges */
#define qh_MAXnummerge 511 /* 2^9-1 */
                        /* 23 flags (at most 23 due to nummerge), printed by "flags:" in io_r.c */
  flagT    tricoplanar:1; /* True if TRIangulate and simplicial and coplanar with a neighbor */
                          /*   all tricoplanars share the same apex */
                          /*   all tricoplanars share the same ->center, ->normal, ->offset, ->maxoutside */
                          /*     ->keepcentrum is true for the owner.  It has the ->coplanareset */
                          /*   if ->degenerate, does not span facet (one logical ridge) */
                          /*   during qh_triangulate, f.trivisible points to original facet */
  flagT    newfacet:1;  /* True if facet on qh.newfacet_list (new/qh.first_newfacet 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 facet has one or more dupridge in a new facet (qh_matchneighbor),
                             a dupridge has a subridge shared by more than one new facet */
  flagT    mergeridge:1; /* True if facet or neighbor has a qh_MERGEridge (qh_mark_dupridges)
                            ->normal defined for mergeridge and mergeridge2 */
  flagT    mergeridge2:1; /* True if neighbor has a qh_MERGEridge (qh_mark_dupridges) */
  flagT    coplanarhorizon:1;  /* True if horizon facet is coplanar at last use */
  flagT     mergehorizon:1; /* True if will merge into horizon (its first neighbor w/ f.coplanarhorizon). */
  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
                             Set by qh_updatetested if more than qh_MAXnewcentrum extra vertices
                             Set by qh_mergefacet if |maxdist| > qh.WIDEfacet */
  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)
                         Maybe merge degenerate and redundant to gain another flag */
};


/*----------------------------------

  ridgeT
    defines a ridge

  notes:
  a ridge is hull_dim-1 simplex between two neighboring facets.  If the
  facets are non-simplicial, there may be more than one ridge between
  two facets.  E.G. a 4-d hypercube has two triangles between each pair
  of neighboring facets.

  topological information:
    vertices            a set of vertices
    top,bottom          neighboring facets with orientation

  geometric information:
    tested              True if ridge is clearly convex
    nonconvex           True if ridge is non-convex
*/
/* QhullRidge.cpp -- Update static initializer list for s_empty_ridge if add or remove fields */
struct ridgeT {
  setT    *vertices;    /* vertices belonging to this ridge, inverse sorted by ID
                           NULL if a degen ridge (matchsame) */
  facetT  *top;         /* top facet for this ridge */
  facetT  *bottom;      /* bottom facet for this ridge
                        ridge oriented by odd/even vertex order and top/bottom */
  unsigned int id;      /* unique identifier.  Same size as vertex_id, printed as 'r%d' */
  flagT    seen:1;      /* used to perform operations only once */
  flagT    tested:1;    /* True when ridge is tested for convexity by centrum or opposite vertices */
  flagT    nonconvex:1; /* True if getmergeset detected a non-convex neighbor
                           only one ridge between neighbors may have nonconvex */
  flagT    mergevertex:1; /* True if pending qh_appendvertexmerge due to
                             qh_maybe_duplicateridge or qh_maybe_duplicateridges
                             disables check for duplicate vertices in qh_checkfacet */
  flagT    mergevertex2:1; /* True if qh_drop_mergevertex of MRGvertices, printed but not used */
  flagT    simplicialtop:1; /* True if top was simplicial (original vertices) */
  flagT    simplicialbot:1; /* True if bottom was simplicial (original vertices)
                             use qh_test_centrum_merge if top and bot, need to retest since centrum may change */
};

/*----------------------------------

  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
*/
/* QhullVertex.cpp -- Update static initializer list for s_empty_vertex if add or remove fields */
struct vertexT {
  vertexT *next;        /* next vertex in vertex_list or vertex_tail */
  vertexT *previous;    /* previous vertex in vertex_list or NULL, for C++ interface */
  pointT  *point;       /* hull_dim coordinates (coordT) */
  setT    *neighbors;   /* neighboring facets of vertex, qh_vertexneighbors()
                           initialized in io_r.c or after first merge
                           qh_update_vertices for qh_addpoint or qh_triangulate
                           updated by merges
                           qh_order_vertexneighbors by 2-d (orientation) 3-d (adjacency), n-d (f.visitid,id) */
  unsigned int id;      /* unique identifier, 1..qh.vertex_id,  0 for sentinel, printed as 'r%d' */
  unsigned int visitid; /* for use with qh.vertex_visit, size must match */
  flagT    seen:1;      /* used to perform operations only once */
  flagT    seen2:1;     /* another seen flag */
  flagT    deleted:1;   /* vertex will be deleted via qh.del_vertices */
  flagT    delridge:1;  /* vertex belonged to a deleted ridge, cleared by qh_reducevertices */
  flagT    newfacet:1;  /* true if vertex is in a new facet
                           vertex is on qh.newvertex_list and it has a facet on qh.newfacet_list
                           or vertex is on qh.newvertex_list due to qh_newvertices while merging
                           cleared by qh_resetlists */
  flagT    partitioned:1; /* true if deleted vertex has been partitioned */
};

/*======= -global variables -qh ============================*/

/*----------------------------------

  qhT
   All global variables for qhull are in qhT.  It includes qhmemT, qhstatT, and rbox globals

   This version of Qhull is reentrant, but it is not thread-safe.

   Do not run separate threads on the same instance of qhT.

   QHULL_LIB_CHECK checks that a program and the corresponding
   qhull library were built with the same type of header files.

   QHULL_LIB_TYPE is QHULL_NON_REENTRANT, QHULL_QH_POINTER, or QHULL_REENTRANT
*/

#define QHULL_NON_REENTRANT 0
#define QHULL_QH_POINTER 1
#define QHULL_REENTRANT 2

#define QHULL_LIB_TYPE QHULL_REENTRANT

#define QHULL_LIB_CHECK qh_lib_check(QHULL_LIB_TYPE, sizeof(qhT), sizeof(vertexT), sizeof(ridgeT), sizeof(facetT), sizeof(setT), sizeof(qhmemT));
#define QHULL_LIB_CHECK_RBOX qh_lib_check(QHULL_LIB_TYPE, sizeof(qhT), sizeof(vertexT), sizeof(ridgeT), sizeof(facetT), 0, 0);

struct qhT {

/*----------------------------------

  qh constants
    configuration flags and constants for Qhull

  notes:
    The user configures Qhull by defining flags.  They are
    copied into qh by qh_setflags().  qh-quick_r.htm#options defines the flags.
*/
  boolT ALLpoints;        /* true 'Qs' if search all points for initial simplex */
  boolT ALLOWshort;       /* true 'Qa' allow input with fewer or more points than coordinates */
  boolT ALLOWwarning;     /* true 'Qw' if allow option warnings */
  boolT ALLOWwide;        /* true 'Q12' if allow wide facets and wide dupridges, c.f. qh_WIDEmaxoutside */
  boolT ANGLEmerge;       /* true 'Q1' if sort potential merges by type/angle instead of type/distance  */
  boolT APPROXhull;       /* true 'Wn' if MINoutside set */
  realT MINoutside;       /*   Minimum distance for an outside point ('Wn' or 2*qh.MINvisible) */
  boolT ANNOTATEoutput;   /* true 'Ta' if annotate output with message codes */
  boolT ATinfinity;       /* true 'Qz' if point num_points-1 is "at-infinity"
                             for improving precision in Delaunay triangulations */
  boolT AVOIDold;         /* true 'Q4' if avoid old->new merges */
  boolT BESToutside;      /* true 'Qf' if partition points into best outsideset */
  boolT CDDinput;         /* true 'Pc' if input uses CDD format (1.0/offset first) */
  boolT CDDoutput;        /* true 'PC' if print normals in CDD format (offset first) */
  boolT CHECKduplicates;  /* true 'Q15' if qh_maybe_duplicateridges after each qh_mergefacet */
  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' or 'v' if computing DELAUNAY triangulation */
  boolT DOintersections;  /* true 'Gh' if print hyperplane intersections */
  int   DROPdim;          /* drops dim 'GDn' for 4-d -> 3-d output */
  boolT FLUSHprint;       /* true 'Tf' if flush after qh_fprintf for segfaults */
  boolT FORCEoutput;      /* true 'Po' if forcing output despite degeneracies */
  int   GOODpoint;        /* 'QGn' or 'QG-n' (n+1, n-1), good facet if visible from point n (or not) */
  pointT *GOODpointp;     /*   the actual point */
  boolT GOODthreshold;    /* true 'Pd/PD' if qh.lower_threshold/upper_threshold defined
                             set if qh.UPPERdelaunay (qh_initbuild)
                             false if qh.SPLITthreshold */
  int   GOODvertex;       /* 'QVn' or 'QV-n' (n+1, n-1), good facet if vertex for point n (or not) */
  pointT *GOODvertexp;     /*   the actual point */
  boolT HALFspace;        /* true 'Hn,n,n' if halfspace intersection */
  boolT ISqhullQh;        /* Set by Qhull.cpp on initialization */
  int   IStracing;        /* 'Tn' 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*/
  int   MAXwide;          /* 'QWn' max ratio for wide facet, otherwise error unless Q12-allow-wide */
  boolT MERGEexact;       /* true 'Qx' if exact merges (concave, degen, dupridge, flipped)
                             tested by qh_checkzero and qh_test_*_merge */
  boolT MERGEindependent; /* true if merging independent sets of coplanar facets. 'Q2' disables */
  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 MERGEpinched;     /* true 'Q14' if merging pinched vertices due to dupridge */
  boolT MERGEvertices;    /* true if merging redundant vertices, 'Q3' disables or qh.hull_dim > qh_DIMmergeVertex */
  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, qh_check_points may fail */
  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
                             PGood set if 'd', 'PAn', 'PFn', 'PMn', 'QGn', 'QG-n', 'QVn', or 'QV-n' */
  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 RANDOMdist;       /* true 'Rn' if randomly change distplane and setfacetplane */
  realT RANDOMfactor;     /*    maximum random perturbation */
  realT RANDOMa;          /*    qh_randomfactor is randr * RANDOMa + RANDOMb */
  realT RANDOMb;
  boolT RANDOMoutside;    /* true 'Qr' if select a random outside point */
  int   REPORTfreq;       /* 'TFn' 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' n<-1 random seed, n==-1 time is seed, n==0 random rotation by time, n>0 rotate input */
  boolT SCALEinput;       /* true 'Qbk' if scaling input */
  boolT SCALElast;        /* true 'Qbb' if scale last coord to max prev coord */
  boolT SETroundoff;      /* true 'En' if qh.DISTround is predefined */
  boolT SKIPcheckmax;     /* true 'Q5' if skip qh_check_maxout, qh_check_points may fail */
  boolT SKIPconvex;       /* true 'Q6' if skip convexity testing during pre-merge */
  boolT SPLITthresholds;  /* true 'Pd/PD' if upper_/lower_threshold defines a region
                               else qh.GOODthresholds
                               set if qh.DELAUNAY (qh_initbuild)
                               used only for printing (!for qh.ONLYgood) */
  int   STOPadd;          /* 'TAn' 1+n for stop after adding n vertices */
  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, use qh_IDunknown (-1) after qh_buildhull and qh_postmerge */
  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 ->normal and ->center (sets Qt) */
  boolT UPPERdelaunay;    /* true 'Qu' if computing furthest-site Delaunay */
  boolT USEstdout;        /* true 'Tz' if using stdout instead of stderr */
  boolT VERIFYoutput;     /* true 'Tv' if verify output at end of qhull */
  boolT VIRTUALmemory;    /* true 'Q7' if depth-first processing in buildhull */
  boolT VORONOI;          /* true 'v' if computing Voronoi diagram, also sets qh.DELAUNAY */

  /*--------input constants ---------*/
  realT AREAfactor;       /* 1/(hull_dim-1)! for converting det's to area */
  boolT DOcheckmax;       /* true if calling qh_check_maxout (!qh.SKIPcheckmax && qh.MERGING) */
  char  *feasible_string;  /* feasible point 'Hn,n,n' for halfspace intersection */
  coordT *feasible_point;  /*    as coordinates, both malloc'd */
  boolT GETarea;          /* true 'Fa', 'FA', 'FS', 'PAn', 'PFn' if compute facet area/Voronoi volume in io_r.c */
  boolT KEEPnearinside;   /* true if near-inside points in coplanarset */
  int   hull_dim;         /* dimension of hull, set by initbuffers */
  int   input_dim;        /* dimension of input, set by initbuffers */
  int   num_points;       /* number of input points */
  pointT *first_point;    /* array of input points, see POINTSmalloc */
  boolT POINTSmalloc;     /*   true if qh.first_point/num_points allocated */
  pointT *input_points;   /* copy of original qh.first_point for input points for qh_joggleinput */
  boolT input_malloc;     /* true if qh.input_points malloc'd */
  char  qhull_command[256];/* command line that invoked this program */
  int   qhull_commandsiz2; /*    size of qhull_command at qh_clear_outputflags */
  char  rbox_command[256]; /* command line that produced the input points */
  char  qhull_options[512];/* descriptive list of options */
  int   qhull_optionlen;  /*    length of last line */
  int   qhull_optionsiz;  /*    size of qhull_options at qh_build_withrestart */
  int   qhull_optionsiz2; /*    size of qhull_options at qh_clear_outputflags */
  int   run_id;           /* non-zero, random identifier for this instance of qhull */
  boolT VERTEXneighbors;  /* true if maintaining vertex neighbors */
  boolT ZEROcentrum;      /* true if 'C-0' or 'C-0 Qx' and not post-merging or 'A-n'.  Sets ZEROall_ok */
  realT *upper_threshold; /* don't print if facet->normal[k]>=upper_threshold[k]
                             must set either GOODthreshold or SPLITthreshold
                             if qh.DELAUNAY, default is 0.0 for upper envelope (qh_initbuild) */
  realT *lower_threshold; /* don't print if facet->normal[k] <=lower_threshold[k] */
  realT *upper_bound;     /* scale point[k] to new upper bound */
  realT *lower_bound;     /* scale point[k] to new lower bound
                             project if both upper_ and lower_bound == 0 */

/*----------------------------------

  qh precision constants
    precision constants for Qhull

  notes:
    qh_detroundoff [geom2_r.c] 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 ('Cn' + 2*qh.DISTround) */
  realT cos_max;          /* max cosine for convexity (roundoff added) */
  realT DISTround;        /* max round off error for distances, qh.SETroundoff ('En') overrides qh_distround */
  realT MAXabs_coord;     /* max absolute coordinate */
  realT MAXlastcoord;     /* max last coordinate for qh_scalelast */
  realT MAXoutside;       /* max target for qh.max_outside/f.maxoutside, base for qh_RATIO...
                             recomputed at qh_addpoint, unrelated to qh_MAXoutside */
  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 */
  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 */
  boolT NARROWhull;       /* set in qh_initialhull if angle < qh_MAXnarrow */

/*----------------------------------

  qh internal constants
    internal constants for Qhull
*/
  char qhull[sizeof("qhull")]; /* "qhull" for checking ownership while debugging */
  jmp_buf errexit;        /* exit label for qh_errexit, defined by setjmp() and NOerrexit */
  char    jmpXtra[40];    /* extra bytes in case jmp_buf is defined wrong by compiler */
  jmp_buf restartexit;    /* restart label for qh_errexit, defined by setjmp() and ALLOWrestart */
  char    jmpXtra2[40];   /* extra bytes in case jmp_buf is defined wrong by compiler*/
  FILE *  fin;            /* pointer to input file, init by qh_initqhull_start2 */
  FILE *  fout;           /* pointer to output file */
  FILE *  ferr;           /* pointer to error file */
  pointT *interior_point; /* center point of the initial simplex*/
  int     normal_size;    /* size in bytes for facet normals and point coords */
  int     center_size;    /* size in bytes for Voronoi centers */
  int     TEMPsize;       /* size for small, temporary sets (in quick mem) */

/*----------------------------------

  qh facet and vertex lists
    defines lists of facets, new facets, visible facets, vertices, and
    new vertices.  Includes counts, next ids, and trace ids.
  see:
    qh_resetlists()
*/
  facetT *facet_list;     /* first facet */
  facetT *facet_tail;     /* end of facet_list (dummy facet with id 0 and next==NULL) */
  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
                             qh_postmerge sets newfacet_list to facet_list */
  facetT *visible_list;   /* list of visible facets preceding newfacet_list,
                             end of visible list if !facet->visible, same as newfacet_list
                             qh_findhorizon sets visible_list at end of facet_list
                             qh_willdelete prepends to visible_list
                             qh_triangulate appends mirror facets to visible_list at end of facet_list
                             qh_postmerge sets visible_list to facet_list
                             qh_deletevisible deletes the visible facets */
  int       num_visible;  /* current number of visible facets */
  unsigned int tracefacet_id; /* set at init, then can print whenever */
  facetT  *tracefacet;    /*   set in newfacet/mergefacet, undone in delfacet and qh_errexit */
  unsigned int traceridge_id; /* set at init, then can print whenever */
  ridgeT  *traceridge;    /*   set in newridge, undone in delridge, errexit, errexit2, makenew_nonsimplicial, mergecycle_ridges */
  unsigned int tracevertex_id; /* set at buildtracing, can print whenever */
  vertexT *tracevertex;   /*   set in newvertex, undone in delvertex and qh_errexit */
  vertexT *vertex_list;   /* list of all vertices, to vertex_tail */
  vertexT *vertex_tail;   /*      end of vertex_list (dummy vertex with ID 0, next NULL) */
  vertexT *newvertex_list; /* list of vertices in newfacet_list, to vertex_tail
                             all vertices have 'newfacet' set */
  int   num_facets;       /* number of facets in facet_list
                             includes visible 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 qh_findgood_all or qh_markkeep) */
  unsigned int facet_id;  /* ID of next, new facet from newfacet() */
  unsigned int ridge_id;  /* ID of next, new ridge from newridge() */
  unsigned int vertex_id; /* ID of next, new vertex from newvertex() */
  unsigned int first_newfacet; /* ID of first_newfacet for qh_buildcone, or 0 if none */

/*----------------------------------

  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 long' to avoid wrap-around errors */
  boolT ALLOWrestart;     /* true if qh_joggle_restart 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 */
  int   last_errcode;     /* last errcode from qh_fprintf, reset in qh_build_withrestart */
  facetT *GOODclosest;    /* closest facet to GOODthreshold in qh_findgood */
  pointT *coplanar_apex;  /* last apex declared a coplanar point by qh_getpinchedmerges, prevents infinite loop */
  boolT hasAreaVolume;    /* true if totarea, totvol was defined by qh_getarea */
  boolT hasTriangulation; /* true if triangulation created by qh_triangulate */
  boolT isRenameVertex;   /* true during qh_merge_pinchedvertices, disables duplicate ridge vertices in qh_checkfacet */
  realT JOGGLEmax;        /* set 'QJn' if randomly joggle input. 'QJ'/'QJ0.0' sets default (qh_detjoggle) */
  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 qh_makecone/qh_attachnewfacets to qh_resetlists */
  boolT NEWtentative;     /* true while new facets are tentative due to !qh.IGNOREpinched or qh.ONLYgood
                              from qh_makecone to qh_attachnewfacets */
  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, cleared after setjmp.  See qh.ERREXITcalled */
  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 */
  unsigned int repart_facetid; /* previous facetid to prevent recursive qh_partitioncoplanar+qh_partitionpoint */
  int   retry_addpoint;   /* number of retries of qh_addpoint due to merging pinched vertices */
  boolT QHULLfinished;    /* True after qhull() is finished */
  realT totarea;          /* 'FA': total facet area computed by qh_getarea, hasAreaVolume */
  realT totvol;           /* 'FA': total volume computed by qh_getarea, hasAreaVolume */
  unsigned int visit_id;  /* unique ID for searching neighborhoods, */
  unsigned int vertex_visit; /* unique ID for searching vertices, reset with qh_buildtracing */
  boolT WAScoplanar;      /* True if qh_partitioncoplanar (qh_check_maxout) */
  boolT ZEROall_ok;       /* True if qh_checkzero always succeeds */

/*----------------------------------

  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 *vertex_mergeset;  /* temporary set of vertex merges */
  setT *hash_table;       /* hash table for matching ridges in qh_matchfacets
                             size is setsize() */
  setT *other_points;     /* additional points */
  setT *del_vertices;     /* vertices to partition and delete with visible
                             facets.  v.deleted is set for checkfacet */

/*----------------------------------

  qh global buffers
    defines buffers for maxtrix operations, input, and error messages
*/
  coordT *gm_matrix;      /* (dim+1)Xdim matrix for geom_r.c */
  coordT **gm_row;        /* array of gm_matrix rows */
  char* line;             /* malloc'd input line of maxline+1 chars */
  int maxline;
  coordT *half_space;     /* malloc'd input array for halfspace (qh.normal_size+coordT) */
  coordT *temp_malloc;    /* malloc'd input array for points */

/*----------------------------------

  qh static variables
    defines static variables for individual functions

  notes:
    do not use 'static' within a function.  Multiple instances of qhull
    may exist.

    do not assume zero initialization, 'QPn' may cause a restart
*/
  boolT ERREXITcalled;    /* true during qh_errexit (prevents duplicate calls).  see qh.NOerrexit */
  boolT firstcentrum;     /* for qh_printcentrum */
  boolT old_randomdist;   /* save RANDOMdist flag during io, tracing, or statistics */
  setT *coplanarfacetset; /* set of coplanar facets for searching qh_findbesthorizon() */
  realT last_low;         /* qh_scalelast parameters for qh_setdelaunay */
  realT last_high;
  realT last_newhigh;
  realT lastcpu;          /* for qh_buildtracing */
  int   lastfacets;       /*   last qh.num_facets */
  int   lastmerges;       /*   last zzval_(Ztotmerge) */ 
  int   lastplanes;       /*   last zzval_(Zsetplane) */ 
  int   lastdist;         /*   last zzval_(Zdistplane) */ 
  unsigned int lastreport; /*  last qh.facet_id */
  int mergereport;        /* for qh_tracemerging */
  setT *old_tempstack;    /* for saving qh->qhmem.tempstack in save_qhull */
  int   ridgeoutnum;      /* number of ridges for 4OFF output (qh_printbegin,etc) */

/*----------------------------------

  qh memory management, rbox globals, and statistics

  Replaces global data structures defined for libqhull
*/
  int     last_random;    /* Last random number from qh_rand (random_r.c) */
  jmp_buf rbox_errexit;   /* errexit from rboxlib_r.c, defined by qh_rboxpoints() only */
  char    jmpXtra3[40];   /* extra bytes in case jmp_buf is defined wrong by compiler */
  int     rbox_isinteger;
  double  rbox_out_offset;
  void *  cpp_object;     /* C++ pointer.  Currently used by RboxPoints.qh_fprintf_rbox */
  void *  cpp_other;      /* C++ pointer.  Reserved for other users */
  void *  cpp_user;       /* C++ pointer.  Currently used by QhullUser.qh_fprintf */

  /* Last, otherwise zero'd by qh_initqhull_start2 (global_r.c */
  qhmemT  qhmem;          /* Qhull managed memory (mem_r.h) */
  /* After qhmem because its size depends on the number of statistics */
  qhstatT qhstat;         /* Qhull statistics (stat_r.h) */
};

/*=========== -macros- =========================*/

/*----------------------------------

  otherfacet_(ridge, facet)
    return neighboring facet for a ridge in facet
*/
#define otherfacet_(ridge, facet) \
                        (((ridge)->top == (facet)) ? (ridge)->bottom : (ridge)->top)

/*----------------------------------

  getid_(p)
    return int ID for facet, ridge, or vertex
    return qh_IDunknown(-1) if NULL
    return 0 if facet_tail or vertex_tail
*/
#define getid_(p)       ((p) ? (int)((p)->id) : qh_IDunknown)

/*============== FORALL macros ===================*/

/*----------------------------------

  FORALLfacets { ... }
    assign 'facet' to each facet in qh.facet_list

  notes:
    uses 'facetT *facet;'
    assumes last facet is a sentinel
    assumes qh defined

  see:
    FORALLfacet_( facetlist )
*/
#define FORALLfacets for (facet=qh->facet_list;facet && facet->next;facet=facet->next)

/*----------------------------------

  FORALLpoints { ... }
    assign 'point' to each point in qh.first_point, qh.num_points

  notes:
    assumes qh defined

  declare:
    coordT *point, *pointtemp;
*/
#define FORALLpoints FORALLpoint_(qh, qh->first_point, qh->num_points)

/*----------------------------------

  FORALLpoint_(qh, points, num) { ... }
    assign 'point' to each point in points array of num points

  declare:
    coordT *point, *pointtemp;
*/
#define FORALLpoint_(qh, points, num) for (point=(points), \
      pointtemp= (points)+qh->hull_dim*(num); point < pointtemp; point += qh->hull_dim)

/*----------------------------------

  FORALLvertices { ... }
    assign 'vertex' to each vertex in qh.vertex_list

  declare:
    vertexT *vertex;

  notes:
    assumes qh.vertex_list terminated by NULL or a sentinel (v.next==NULL)
    assumes qh defined
*/
#define FORALLvertices for (vertex=qh->vertex_list;vertex && vertex->next;vertex= vertex->next)

/*----------------------------------

  FOREACHfacet_( facets ) { ... }
    assign 'facet' to each facet in facets

  declare:
    facetT *facet, **facetp;

  notes:
    assumes set is not modified

  see:
    FOREACHsetelement_
*/
#define FOREACHfacet_(facets)    FOREACHsetelement_(facetT, facets, facet)

/*----------------------------------

  FOREACHneighbor_( facet ) { ... }
    assign 'neighbor' to each neighbor in facet->neighbors

  FOREACHneighbor_( vertex ) { ... }
    assign 'neighbor' to each neighbor in vertex->neighbors

  declare:
    facetT *neighbor, **neighborp;

  notes:
    assumes set is not modified

  see:
    FOREACHsetelement_
*/
#define FOREACHneighbor_(facet)  FOREACHsetelement_(facetT, facet->neighbors, neighbor)

/*----------------------------------

  FOREACHpoint_( points ) { ... }
    assign 'point' to each point in points set

  declare:
    pointT *point, **pointp;

  notes:
    assumes set is not modified

  see:
    FOREACHsetelement_
*/
#define FOREACHpoint_(points)    FOREACHsetelement_(pointT, points, point)

/*----------------------------------

  FOREACHridge_( ridges ) { ... }
    assign 'ridge' to each ridge in ridges set

  declare:
    ridgeT *ridge, **ridgep;

  notes:
    assumes set is not modified

  see:
    FOREACHsetelement_
*/
#define FOREACHridge_(ridges)    FOREACHsetelement_(ridgeT, ridges, ridge)

/*----------------------------------

  FOREACHvertex_( vertices ) { ... }
    assign 'vertex' to each vertex in vertices set

  declare:
    vertexT *vertex, **vertexp;

  notes:
    assumes set is not modified

  see:
    FOREACHsetelement_
*/
#define FOREACHvertex_(vertices) FOREACHsetelement_(vertexT, vertices,vertex)

/*----------------------------------

  FOREACHfacet_i_(qh, facets ) { ... }
    assign 'facet' and 'facet_i' for each facet in facets set

  declare:
    facetT *facet;
    int     facet_n, facet_i;

  see:
    FOREACHsetelement_i_
*/
#define FOREACHfacet_i_(qh, facets)    FOREACHsetelement_i_(qh, facetT, facets, facet)

/*----------------------------------

  FOREACHneighbor_i_(qh, facet ) { ... }
    assign 'neighbor' and 'neighbor_i' for each neighbor in facet->neighbors

  declare:
    facetT *neighbor;
    int     neighbor_n, neighbor_i;

  notes:
    see FOREACHsetelement_i_
    for facet neighbors of vertex, need to define a new macro
*/
#define FOREACHneighbor_i_(qh, facet)  FOREACHsetelement_i_(qh, facetT, facet->neighbors, neighbor)

/*----------------------------------

  FOREACHpoint_i_(qh, points ) { ... }
    assign 'point' and 'point_i' for each point in points set

  declare:
    pointT *point;
    int     point_n, point_i;

  see:
    FOREACHsetelement_i_
*/
#define FOREACHpoint_i_(qh, points)    FOREACHsetelement_i_(qh, pointT, points, point)

/*----------------------------------

  FOREACHridge_i_(qh, ridges ) { ... }
    assign 'ridge' and 'ridge_i' for each ridge in ridges set

  declare:
    ridgeT *ridge;
    int     ridge_n, ridge_i;

  see:
    FOREACHsetelement_i_
*/
#define FOREACHridge_i_(qh, ridges)    FOREACHsetelement_i_(qh, ridgeT, ridges, ridge)

/*----------------------------------

  FOREACHvertex_i_(qh, vertices ) { ... }
    assign 'vertex' and 'vertex_i' for each vertex in vertices set

  declare:
    vertexT *vertex;
    int     vertex_n, vertex_i;

  see:
    FOREACHsetelement_i_
*/
#define FOREACHvertex_i_(qh, vertices) FOREACHsetelement_i_(qh, vertexT, vertices, vertex)

#ifdef __cplusplus
extern "C" {
#endif

/********* -libqhull_r.c prototypes (duplicated from qhull_ra.h) **********************/

void    qh_qhull(qhT *qh);
boolT   qh_addpoint(qhT *qh, pointT *furthest, facetT *facet, boolT checkdist);
void    qh_errexit2(qhT *qh, int exitcode, facetT *facet, facetT *otherfacet);
void    qh_printsummary(qhT *qh, FILE *fp);

/********* -user_r.c prototypes (alphabetical) **********************/

void    qh_errexit(qhT *qh, int exitcode, facetT *facet, ridgeT *ridge);
void    qh_errprint(qhT *qh, const char* string, facetT *atfacet, facetT *otherfacet, ridgeT *atridge, vertexT *atvertex);
int     qh_new_qhull(qhT *qh, int dim, int numpoints, coordT *points, boolT ismalloc,
                char *qhull_cmd, FILE *outfile, FILE *errfile);
void    qh_printfacetlist(qhT *qh, facetT *facetlist, setT *facets, boolT printall);
void    qh_printhelp_degenerate(qhT *qh, FILE *fp);
void    qh_printhelp_internal(qhT *qh, FILE *fp);
void    qh_printhelp_narrowhull(qhT *qh, FILE *fp, realT minangle);
void    qh_printhelp_singular(qhT *qh, FILE *fp);
void    qh_printhelp_topology(qhT *qh, FILE *fp);
void    qh_printhelp_wide(qhT *qh, FILE *fp);
void    qh_user_memsizes(qhT *qh);

/********* -usermem_r.c prototypes (alphabetical) **********************/
void    qh_exit(int exitcode);
void    qh_fprintf_stderr(int msgcode, const char *fmt, ... );
void    qh_free(void *mem);
void   *qh_malloc(size_t size);

/********* -userprintf_r.c and userprintf_rbox_r.c prototypes **********************/
void    qh_fprintf(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... );
void    qh_fprintf_rbox(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... );

/***** -geom_r.c/geom2_r.c/random_r.c prototypes (duplicated from geom_r.h, random_r.h) ****************/

facetT *qh_findbest(qhT *qh, pointT *point, facetT *startfacet,
                     boolT bestoutside, boolT newfacets, boolT noupper,
                     realT *dist, boolT *isoutside, int *numpart);
facetT *qh_findbestnew(qhT *qh, pointT *point, facetT *startfacet,
                     realT *dist, boolT bestoutside, boolT *isoutside, int *numpart);
boolT   qh_gram_schmidt(qhT *qh, int dim, realT **rows);
void    qh_outerinner(qhT *qh, facetT *facet, realT *outerplane, realT *innerplane);
void    qh_printsummary(qhT *qh, FILE *fp);
void    qh_projectinput(qhT *qh);
void    qh_randommatrix(qhT *qh, realT *buffer, int dim, realT **row);
void    qh_rotateinput(qhT *qh, realT **rows);
void    qh_scaleinput(qhT *qh);
void    qh_setdelaunay(qhT *qh, int dim, int count, pointT *points);
coordT  *qh_sethalfspace_all(qhT *qh, int dim, int count, coordT *halfspaces, pointT *feasible);

/***** -global_r.c prototypes (alphabetical) ***********************/

unsigned long qh_clock(qhT *qh);
void    qh_checkflags(qhT *qh, char *command, char *hiddenflags);
void    qh_clear_outputflags(qhT *qh);
void    qh_freebuffers(qhT *qh);
void    qh_freeqhull(qhT *qh, boolT allmem);
void    qh_init_A(qhT *qh, FILE *infile, FILE *outfile, FILE *errfile, int argc, char *argv[]);
void    qh_init_B(qhT *qh, coordT *points, int numpoints, int dim, boolT ismalloc);
void    qh_init_qhull_command(qhT *qh, int argc, char *argv[]);
void    qh_initbuffers(qhT *qh, coordT *points, int numpoints, int dim, boolT ismalloc);
void    qh_initflags(qhT *qh, char *command);
void    qh_initqhull_buffers(qhT *qh);
void    qh_initqhull_globals(qhT *qh, coordT *points, int numpoints, int dim, boolT ismalloc);
void    qh_initqhull_mem(qhT *qh);
void    qh_initqhull_outputflags(qhT *qh);
void    qh_initqhull_start(qhT *qh, FILE *infile, FILE *outfile, FILE *errfile);
void    qh_initqhull_start2(qhT *qh, FILE *infile, FILE *outfile, FILE *errfile);
void    qh_initthresholds(qhT *qh, char *command);
void    qh_lib_check(int qhullLibraryType, int qhTsize, int vertexTsize, int ridgeTsize, int facetTsize, int setTsize, int qhmemTsize);
void    qh_option(qhT *qh, const char *option, int *i, realT *r);
void    qh_zero(qhT *qh, FILE *errfile);

/***** -io_r.c prototypes (duplicated from io_r.h) ***********************/

void    qh_dfacet(qhT *qh, unsigned int id);
void    qh_dvertex(qhT *qh, unsigned int id);
void    qh_printneighborhood(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetA, facetT *facetB, boolT printall);
void    qh_produce_output(qhT *qh);
coordT *qh_readpoints(qhT *qh, int *numpoints, int *dimension, boolT *ismalloc);


/********* -mem_r.c prototypes (duplicated from mem_r.h) **********************/

void qh_meminit(qhT *qh, FILE *ferr);
void qh_memfreeshort(qhT *qh, int *curlong, int *totlong);

/********* -poly_r.c/poly2_r.c prototypes (duplicated from poly_r.h) **********************/

void    qh_check_output(qhT *qh);
void    qh_check_points(qhT *qh);
setT   *qh_facetvertices(qhT *qh, facetT *facetlist, setT *facets, boolT allfacets);
facetT *qh_findbestfacet(qhT *qh, pointT *point, boolT bestoutside,
           realT *bestdist, boolT *isoutside);
vertexT *qh_nearvertex(qhT *qh, facetT *facet, pointT *point, realT *bestdistp);
pointT *qh_point(qhT *qh, int id);
setT   *qh_pointfacet(qhT *qh /* qh.facet_list */);
int     qh_pointid(qhT *qh, pointT *point);
setT   *qh_pointvertex(qhT *qh /* qh.facet_list */);
void    qh_setvoronoi_all(qhT *qh);
void    qh_triangulate(qhT *qh /* qh.facet_list */);

/********* -rboxlib_r.c prototypes **********************/
int     qh_rboxpoints(qhT *qh, char* rbox_command);
void    qh_errexit_rbox(qhT *qh, int exitcode);

/********* -stat_r.c prototypes (duplicated from stat_r.h) **********************/

void    qh_collectstatistics(qhT *qh);
void    qh_printallstatistics(qhT *qh, FILE *fp, const char *string);

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* qhDEFlibqhull */
qhull-2020.2/src/libqhull_r/libqhull_r.pro0000644060175106010010000000401413431072716016774 0ustar  bbarber# -------------------------------------------------
# libqhull_r.pro -- Qt project for Qhull shared library
#
# It uses reentrant Qhull
# -------------------------------------------------

include(../qhull-warn.pri)

DESTDIR = ../../lib
DLLDESTDIR = ../../bin
TEMPLATE = lib
CONFIG += shared warn_on
CONFIG -= qt

build_pass:CONFIG(debug, debug|release):{
    TARGET = qhull_rd
    OBJECTS_DIR = Debug
}else:build_pass:CONFIG(release, debug|release):{
    TARGET = qhull_r
    OBJECTS_DIR = Release
}
win32-msvc* : QMAKE_LFLAGS += /INCREMENTAL:NO

win32-msvc* : DEF_FILE += ../../src/libqhull_r/qhull_r-exports.def

# Order object files by frequency of execution.  Small files at end.
# libqhull_r/libqhull_r.pro and ../qhull-libqhull-src_r.pri have the same SOURCES and HEADERS

SOURCES += ../libqhull_r/global_r.c
SOURCES += ../libqhull_r/stat_r.c
SOURCES += ../libqhull_r/geom2_r.c
SOURCES += ../libqhull_r/poly2_r.c
SOURCES += ../libqhull_r/merge_r.c
SOURCES += ../libqhull_r/libqhull_r.c
SOURCES += ../libqhull_r/geom_r.c
SOURCES += ../libqhull_r/poly_r.c
SOURCES += ../libqhull_r/qset_r.c
SOURCES += ../libqhull_r/mem_r.c
SOURCES += ../libqhull_r/random_r.c
SOURCES += ../libqhull_r/usermem_r.c
SOURCES += ../libqhull_r/userprintf_r.c
SOURCES += ../libqhull_r/io_r.c
SOURCES += ../libqhull_r/user_r.c
SOURCES += ../libqhull_r/rboxlib_r.c
SOURCES += ../libqhull_r/userprintf_rbox_r.c

HEADERS += ../libqhull_r/geom_r.h
HEADERS += ../libqhull_r/io_r.h
HEADERS += ../libqhull_r/libqhull_r.h
HEADERS += ../libqhull_r/mem_r.h
HEADERS += ../libqhull_r/merge_r.h
HEADERS += ../libqhull_r/poly_r.h
HEADERS += ../libqhull_r/random_r.h
HEADERS += ../libqhull_r/qhull_ra.h
HEADERS += ../libqhull_r/qset_r.h
HEADERS += ../libqhull_r/stat_r.h
HEADERS += ../libqhull_r/user_r.h

OTHER_FILES += qh-geom_r.htm
OTHER_FILES += qh-globa_r.htm
OTHER_FILES += qh-io_r.htm
OTHER_FILES += qh-mem_r.htm
OTHER_FILES += qh-merge_r.htm
OTHER_FILES += qh-poly_r.htm
OTHER_FILES += qh-qhull_r.htm
OTHER_FILES += qh-set_r.htm
OTHER_FILES += qh-stat_r.htm
OTHER_FILES += qh-user_r.htm
qhull-2020.2/src/libqhull_r/Makefile0000644060175106010010000002465013724272003015561 0ustar  bbarber# Simple gcc Makefile for reentrant qhull and rbox (default gcc/g++)
#
#   make help
#   See README.txt and ../../Makefile
#       
# Variables
#   DESTDIR        directory for staged installs (GNU Makefile standards)
#   PREFIX         install directory for 'make install' (default /usr/local)
#   BINDIR         directory where to copy executables
#   DOCDIR         directory where to copy html documentation
#   INCDIR         directory where to copy headers
#   LIBDIR         directory where to copy libraries
#   MANDIR         directory where to copy manual pages
#   PCDIR          directory where to copy pkg-config files
#   PRINTMAN       command for printing manual pages
#   PRINTC         command for printing C files
#   CC             ANSI C or C++ compiler
#   CC_OPTS1       options used to compile .c files
#   CC_OPTS2       options used to link .o files
#   CC_OPTS3       options to build shared libraries
#
#   LIBQHULL_OBJS  .o files for linking
#   LIBQHULL_HDRS  .h files for printing
#   CFILES         .c files for printing
#   DOCFILES       documentation files
#   FILES          miscellaneous files for printing
#   TFILES         .txt versions of html files
#   FILES          all other files
#   LIBQHULL_OBJS  specifies the object files of libqhullstatic_r.a
#
# Results
#   rbox           Generates points sets for qhull, qconvex, etc.
#   qhull          Computes convex hulls and related structures
#   qconvex, qdelaunay, qhalf, qvoronoi
#                  Specializations of qhull for each geometric structure
#   libqhullstatic_r.a Static library for reentrant qhull
#   testqset_r     Standalone test of reentrant qset_r.c with mem_r.c
#   user_eg        An example of using qhull (reentrant)
#   user_eg2       An example of using qhull (reentrant)
#
# Make targets
#   make           Build results using gcc or another compiler
#   make all
#   make clean     Remove object files
#   make cleanall  Remove generated files
#   make doc       Print documentation
#   make help
#   make install   Copy results and documentation to BINDIR, DOCDIR, INCDIR, LIBDIR, MANDIR, PCDOC
#   make uninstall Delete Qhull files from BINDIR, DOCDIR, INCDIR, LIBDIR, MANDIR, PCDOC
#   make new       Rebuild qhull and rbox from source
#   make printall  Print all files
#   make qtest     Quick test of qset, rbox, and qhull
#   make test      Quck test of qhull, qconvex, etc.
#
# $Id: //main/2019/qhull/src/libqhull_r/Makefile#13 $

# Do not replace tabs with spaces.  Needed for build rules
# Unix line endings (\n)

PREFIX ?= /usr/local
BINDIR ?= bin
INCDIR ?= include
LIBDIR ?= lib
DOCDIR ?= share/doc/qhull
MANDIR ?= share/man/man1
PCDIR  ?= $(LIBDIR)/pkgconfig

ABS_BINDIR = $(DESTDIR)$(PREFIX)/$(BINDIR)
ABS_INCDIR = $(DESTDIR)$(PREFIX)/$(INCDIR)
ABS_LIBDIR = $(DESTDIR)$(PREFIX)/$(LIBDIR)
ABS_DOCDIR = $(DESTDIR)$(PREFIX)/$(DOCDIR)
ABS_MANDIR = $(DESTDIR)$(PREFIX)/$(MANDIR)
ABS_PCDIR  = $(DESTDIR)$(PREFIX)/$(PCDIR)

qhull_VERSION=$(shell grep 'set.qhull_VERSION ' ../../CMakeLists.txt | grep -o '[0-9.]\+' || echo 0unknown)

# 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, -O3 for optimization, -g for debugging, -pg for profiling
# caller may define CC_WARNINGS
# Qhull uses less memory for 32-bit builds on 64-bit hosts
# Enable 32-bit builds with 'make M32=-m32'
# M32     = -m32
# -fpic is required for linking to shared libraries
# -fpic may be slower for 32-bit builds on 64-bit hosts
# Disable -fpic with 'make FPIC=' 
FPIC      = -fpic
CC        = gcc
CC_OPTS1  = -O3 -ansi -I../../src $(CC_WARNINGS) $(M32) $(FPIC)

# for Sun's cc compiler, -fast or O2 for optimization, -g for debugging, -Xc for ANSI
#CC       = cc
#CC_OPTS1 = -Xc -v -fast -I../../src 

# for Silicon Graphics cc compiler, -O2 for optimization, -g for debugging
#CC       = cc
#CC_OPTS1 = -ansi -O2 -I../../src 

# for Next cc compiler with fat executable
#CC       = cc
#CC_OPTS1 = -ansi -O2 -I../../src -arch m68k -arch i386 -arch hppa

# For loader, ld, 
CC_OPTS2 = $(CC_OPTS1)

# Default targets for make

all: qhull_links qhull_all qtest

help:
	head -n 54 Makefile

clean:
	rm -f *.o 
	# Delete linked files from other directories [qhull_links]
	rm -f qconvex_r.c unix_r.c qdelaun_r.c qhalf_r.c qvoronoi_r.c rbox_r.c
	rm -f user_eg_r.c user_eg2_r.c testqset_r.c
	
cleanall: clean
	rm -f qconvex qdelaunay qhalf qvoronoi qhull *.exe
	rm -f core user_eg_r user_eg2_r testqset_r libqhullstatic_r.a

doc: 
	$(PRINTMAN) $(TXTFILES) $(DOCFILES)

install:
	mkdir -p $(ABS_BINDIR)
	mkdir -p $(ABS_DOCDIR)
	mkdir -p $(ABS_DOCDIR)/src
	mkdir -p $(ABS_INCDIR)/libqhull_r
	mkdir -p $(ABS_LIBDIR)
	mkdir -p $(ABS_MANDIR)
	mkdir -p $(ABS_PCDIR)
	cp -p qconvex qdelaunay qhalf qhull qvoronoi rbox $(ABS_BINDIR)
	cp -p libqhullstatic_r.a $(ABS_LIBDIR)
	(cd ../.. && cp -p README.txt REGISTER.txt Announce.txt COPYING.txt index.htm $(ABS_DOCDIR)/)
	(cd ../.. && cp -pr html $(ABS_DOCDIR)/)
	(cd ../.. && cp -p src/Changes.txt $(ABS_DOCDIR)/src/)
	cp -p ../../html/qhull.man $(ABS_MANDIR)/qhull.1
	cp -p ../../html/rbox.man $(ABS_MANDIR)/rbox.1
	cp *.h $(ABS_INCDIR)/libqhull_r
	sed \
		-e 's#@qhull_VERSION@#$(qhull_VERSION)#' \
		-e 's#@CMAKE_INSTALL_PREFIX@#$(PREFIX)#' \
		-e 's#@LIB_INSTALL_DIR@#$(LIBDIR)#' \
		-e 's#@INCLUDE_INSTALL_DIR@#$(INCDIR)#' \
		-e 's#@LIBRARY_NAME@#qhullstatic_r#' \
		-e 's#@LIBRARY_DESCRIPTION@#Qhull reentrant static library#' \
		../../build/qhull.pc.in > $(ABS_PCDIR)/qhullstatic_r.pc

uninstall:
	-(cd $(ABS_BINDIR) && rm -f qconvex qdelaunay qhalf qhull qvoronoi rbox)
	-(cd $(ABS_BINDIR) && rm -f qconvex.exe qdelaunay.exe qhalf.exe qhull.exe qvoronoi.exe rbox.exe)
	-(cd $(ABS_MANDIR) && rm -f qhull.1 rbox.1)
	-(cd $(ABS_DOCDIR) && rm -f README.txt REGISTER.txt Announce.txt COPYING.txt index.htm src/Changes.txt)
	-(cd $(ABS_DOCDIR) && rm -rf html)
	-(cd $(ABS_LIBDIR) && rm -f libqhullstatic_r.a)
	-(cd $(ABS_INCDIR) && rm -rf libqhull_r)
	-(cd $(ABS_PCDIR) && rm -f qhullstatic_r.pc)
	-rmdir $(ABS_DOCDIR)/src
	-rmdir $(ABS_DOCDIR)

new:	cleanall all

printall: doc printh printc printf

printh:
	$(PRINTC) $(LIBQHULL_HDRS)

printc:
	$(PRINTC) $(CFILES)

# LIBQHULL_OBJS_1 ordered by frequency of execution with small files at end.  Better locality.
# Same definitions as ../../Makefile

LIBQHULLS_OBJS_1= global_r.o stat_r.o geom2_r.o poly2_r.o merge_r.o \
	libqhull_r.o geom_r.o poly_r.o qset_r.o mem_r.o random_r.o 

LIBQHULLS_OBJS_2= $(LIBQHULLS_OBJS_1) usermem_r.o userprintf_r.o io_r.o user_r.o

LIBQHULLS_OBJS= $(LIBQHULLS_OBJS_2)  rboxlib_r.o userprintf_rbox_r.o

LIBQHULL_HDRS= user_r.h libqhull_r.h qhull_ra.h geom_r.h \
	io_r.h mem_r.h merge_r.h poly_r.h random_r.h \
	qset_r.h stat_r.h

# CFILES for 'printc', ordered alphabetically after libqhull_r.c 
CFILES= ../qhull/unix_r.c libqhull_r.c geom_r.c geom2_r.c global_r.c io_r.c \
	mem_r.c merge_r.c poly_r.c poly2_r.c random_r.c rboxlib_r.c \
	qset_r.c stat_r.c user_r.c usermem_r.c userprintf_r.c \
	../qconvex/qconvex_r.c ../qdelaunay/qdelaun_r.c \
	../qhalf/qhalf_r.c ../qvoronoi/qvoronoi_r.c

TXTFILES= ../../Announce.txt ../../REGISTER.txt ../../COPYING.txt ../../README.txt ../Changes.txt
DOCFILES= ../../html/rbox.txt ../../html/qhull.txt

.c.o:
	$(CC) -c $(CC_OPTS1) -o $@ $<

# Work around problems with ../ in Red Hat Linux
qhull_links:
	# On MINSYS, 'ln -s' may create a copy instead of a symbolic link
	[ -f qconvex_r.c ]  || ln -s ../qconvex/qconvex_r.c
	[ -f qdelaun_r.c ]  || ln -s ../qdelaunay/qdelaun_r.c
	[ -f qhalf_r.c ]    || ln -s ../qhalf/qhalf_r.c
	[ -f qvoronoi_r.c ] || ln -s ../qvoronoi/qvoronoi_r.c
	[ -f rbox_r.c ]     || ln -s ../rbox/rbox_r.c
	[ -f testqset_r.c ] || ln -s ../testqset_r/testqset_r.c
	[ -f unix_r.c ]     || ln -s ../qhull/unix_r.c
	[ -f user_eg_r.c ]  || ln -s ../user_eg/user_eg_r.c
	[ -f user_eg2_r.c ] || ln -s ../user_eg2/user_eg2_r.c
	# user_eg3_r.c not compiled.  It requires all of libqhullcpp; use qhull/Makefile instead

# compile qhull without using bin/libqhullstatic_r.a
qhull_all: qconvex_r.o qdelaun_r.o qhalf_r.o qvoronoi_r.o unix_r.o user_eg_r.o user_eg2_r.o rbox_r.o testqset_r.o $(LIBQHULLS_OBJS)
	$(CC) -o qconvex $(CC_OPTS2) $(LIBQHULLS_OBJS_2) qconvex_r.o -lm
	$(CC) -o qdelaunay $(CC_OPTS2) $(LIBQHULLS_OBJS_2) qdelaun_r.o -lm
	$(CC) -o qhalf $(CC_OPTS2) $(LIBQHULLS_OBJS_2) qhalf_r.o -lm
	$(CC) -o qvoronoi $(CC_OPTS2) $(LIBQHULLS_OBJS_2) qvoronoi_r.o -lm
	$(CC) -o qhull $(CC_OPTS2) $(LIBQHULLS_OBJS_2) unix_r.o -lm
	$(CC) -o rbox $(CC_OPTS2) $(LIBQHULLS_OBJS) rbox_r.o -lm
	$(CC) -o user_eg $(CC_OPTS2) $(LIBQHULLS_OBJS_2) user_eg_r.o -lm
	$(CC) -o user_eg2 $(CC_OPTS2) $(LIBQHULLS_OBJS_1) user_eg2_r.o  usermem_r.o userprintf_r.o io_r.o -lm
	$(CC) -o testqset_r $(CC_OPTS2) mem_r.o qset_r.o usermem_r.o testqset_r.o -lm
	-ar -rs libqhullstatic_r.a $(LIBQHULLS_OBJS)
	#libqhullstatic_r.a is not needed for qhull
	#If 'ar -rs' fails try using 'ar -s' with 'ranlib'
	#ranlib libqhullstatic_r.a

qtest:
	@echo ============================================
	@echo == make qtest ==============================
	@echo ============================================
	@echo -n "== "
	@date
	@echo
	@echo Testing qset_r.c and mem_r.c with testqset_r
	./testqset_r 10000
	@echo Run the qhull smoketest
	./rbox D4 | ./qhull
	@echo ============================================
	@echo == To smoketest qhull programs
	@echo '==     make test'
	@echo ============================================
	@echo
	@echo ============================================
	@echo == To install qhull or show help
	@echo '==     make help'
	@echo '==     make install'
	@echo ============================================
	@echo

test: qtest
	@echo ==============================
	@echo ========= qconvex ============
	@echo ==============================
	-./rbox 10 | ./qconvex Tv 
	@echo
	@echo ==============================
	@echo ========= qdelaunay ==========
	@echo ==============================
	-./rbox 10 | ./qdelaunay Tv 
	@echo
	@echo ==============================
	@echo ========= qhalf ==============
	@echo ==============================
	-./rbox 10 | ./qconvex FQ FV n Tv | ./qhalf Tv
	@echo
	@echo ==============================
	@echo ========= qvoronoi ===========
	@echo ==============================
	-./rbox 10 | ./qvoronoi Tv
	@echo
	@echo ==============================
	@echo ========= user_eg ============
	@echo == w/o shared library ========
	@echo ==============================
	-./user_eg
	@echo
	@echo ==============================
	@echo ========= user_eg2 ===========
	@echo ==============================
	-./user_eg2
	@echo

# end of Makefile
qhull-2020.2/src/libqhull_r/mem_r.c0000644060175106010010000005225613661631132015371 0ustar  bbarber/*
  ---------------------------------

  mem_r.c
    memory management routines for qhull

  See libqhull/mem.c for a standalone program.

  To initialize memory:

    qh_meminit(qh, stderr);
    qh_meminitbuffers(qh, qh->IStracing, qh_MEMalign, 7, qh_MEMbufsize,qh_MEMinitbuf);
    qh_memsize(qh, (int)sizeof(facetT));
    qh_memsize(qh, (int)sizeof(facetT));
    ...
    qh_memsetup(qh);

  To free up all memory buffers:
    qh_memfreeshort(qh, &curlong, &totlong);

  if qh_NOmem,
    malloc/free is used instead of mem_r.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_r.htm and mem_r.h
    global_r.c (qh_initbuffers) for an example of using mem_r.c

  Copyright (c) 1993-2020 The Geometry Center.
  $Id: //main/2019/qhull/src/libqhull_r/mem_r.c#7 $$Change: 2953 $
  $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
*/

#include "libqhull_r.h"  /* includes user_r.h and mem_r.h */

#include 
#include 
#include 

#ifndef qh_NOmem

/*============= internal functions ==============*/

static int qh_intcompare(const void *i, const void *j);

/*========== functions in alphabetical order ======== */

/*---------------------------------

  qh_intcompare( i, j )
    used by qsort and bsearch to compare two integers
*/
static int qh_intcompare(const void *i, const void *j) {
  return(*((const int *)i) - *((const int *)j));
} /* intcompare */


/*----------------------------------

  qh_memalloc(qh, insize )
    returns object of insize bytes
    qhmem is the global memory structure

  returns:
    pointer to allocated memory
    errors if insufficient memory

  notes:
    use explicit type conversion to avoid type warnings on some compilers
    actual object may be larger than insize
    use qh_memalloc_() for inline code for quick allocations
    logs allocations if 'T5'
    caller is responsible for freeing the memory.
    short memory is freed on shutdown by qh_memfreeshort unless qh_NOmem

  design:
    if size < qh->qhmem.LASTsize
      if qh->qhmem.freelists[size] non-empty
        return first object on freelist
      else
        round up request to size of qh->qhmem.freelists[size]
        allocate new allocation buffer if necessary
        allocate object from allocation buffer
    else
      allocate object with qh_malloc() in user_r.c
*/
void *qh_memalloc(qhT *qh, int insize) {
  void **freelistp, *newbuffer;
  int idx, size, n;
  int outsize, bufsize;
  void *object;

  if (insize<0) {
      qh_fprintf(qh, qh->qhmem.ferr, 6235, "qhull error (qh_memalloc): negative request size (%d).  Did int overflow due to high-D?\n", insize); /* WARN64 */
      qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
  }
  if (insize>=0 && insize <= qh->qhmem.LASTsize) {
    idx= qh->qhmem.indextable[insize];
    outsize= qh->qhmem.sizetable[idx];
    qh->qhmem.totshort += outsize;
    freelistp= qh->qhmem.freelists+idx;
    if ((object= *freelistp)) {
      qh->qhmem.cntquick++;
      qh->qhmem.totfree -= outsize;
      *freelistp= *((void **)*freelistp);  /* replace freelist with next object */
#ifdef qh_TRACEshort
      n= qh->qhmem.cntshort+qh->qhmem.cntquick+qh->qhmem.freeshort;
      if (qh->qhmem.IStracing >= 5)
          qh_fprintf(qh, qh->qhmem.ferr, 8141, "qh_mem %p n %8d alloc quick: %d bytes (tot %d cnt %d)\n", object, n, outsize, qh->qhmem.totshort, qh->qhmem.cntshort+qh->qhmem.cntquick-qh->qhmem.freeshort);
#endif
      return(object);
    }else {
      qh->qhmem.cntshort++;
      if (outsize > qh->qhmem.freesize) {
        qh->qhmem.totdropped += qh->qhmem.freesize;
        if (!qh->qhmem.curbuffer)
          bufsize= qh->qhmem.BUFinit;
        else
          bufsize= qh->qhmem.BUFsize;
        if (!(newbuffer= qh_malloc((size_t)bufsize))) {
          qh_fprintf(qh, qh->qhmem.ferr, 6080, "qhull error (qh_memalloc): insufficient memory to allocate short memory buffer (%d bytes)\n", bufsize);
          qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
        }
        *((void **)newbuffer)= qh->qhmem.curbuffer;  /* prepend newbuffer to curbuffer
                                                    list.  newbuffer!=0 by QH6080 */
        qh->qhmem.curbuffer= newbuffer;
        size= ((int)sizeof(void **) + qh->qhmem.ALIGNmask) & ~qh->qhmem.ALIGNmask;
        qh->qhmem.freemem= (void *)((char *)newbuffer+size);
        qh->qhmem.freesize= bufsize - size;
        qh->qhmem.totbuffer += bufsize - size; /* easier to check */
        /* Periodically test totbuffer.  It matches at beginning and exit of every call */
        n= qh->qhmem.totshort + qh->qhmem.totfree + qh->qhmem.totdropped + qh->qhmem.freesize - outsize;
        if (qh->qhmem.totbuffer != n) {
            qh_fprintf(qh, qh->qhmem.ferr, 6212, "qhull internal error (qh_memalloc): short totbuffer %d != totshort+totfree... %d\n", qh->qhmem.totbuffer, n);
            qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
        }
      }
      object= qh->qhmem.freemem;
      qh->qhmem.freemem= (void *)((char *)qh->qhmem.freemem + outsize);
      qh->qhmem.freesize -= outsize;
      qh->qhmem.totunused += outsize - insize;
#ifdef qh_TRACEshort
      n= qh->qhmem.cntshort+qh->qhmem.cntquick+qh->qhmem.freeshort;
      if (qh->qhmem.IStracing >= 5)
          qh_fprintf(qh, qh->qhmem.ferr, 8140, "qh_mem %p n %8d alloc short: %d bytes (tot %d cnt %d)\n", object, n, outsize, qh->qhmem.totshort, qh->qhmem.cntshort+qh->qhmem.cntquick-qh->qhmem.freeshort);
#endif
      return object;
    }
  }else {                     /* long allocation */
    if (!qh->qhmem.indextable) {
      qh_fprintf(qh, qh->qhmem.ferr, 6081, "qhull internal error (qh_memalloc): qhmem has not been initialized.\n");
      qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
    }
    outsize= insize;
    qh->qhmem.cntlong++;
    qh->qhmem.totlong += outsize;
    if (qh->qhmem.maxlong < qh->qhmem.totlong)
      qh->qhmem.maxlong= qh->qhmem.totlong;
    if (!(object= qh_malloc((size_t)outsize))) {
      qh_fprintf(qh, qh->qhmem.ferr, 6082, "qhull error (qh_memalloc): insufficient memory to allocate %d bytes\n", outsize);
      qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
    }
    if (qh->qhmem.IStracing >= 5)
      qh_fprintf(qh, qh->qhmem.ferr, 8057, "qh_mem %p n %8d alloc long: %d bytes (tot %d cnt %d)\n", object, qh->qhmem.cntlong+qh->qhmem.freelong, outsize, qh->qhmem.totlong, qh->qhmem.cntlong-qh->qhmem.freelong);
  }
  return(object);
} /* memalloc */


/*----------------------------------

  qh_memcheck(qh)
*/
void qh_memcheck(qhT *qh) {
  int i, count, totfree= 0;
  void *object;

  if (!qh) {
    qh_fprintf_stderr(6243, "qhull internal error (qh_memcheck): qh is 0.  It does not point to a qhT\n");
    qh_exit(qhmem_ERRqhull);  /* can not use qh_errexit() */
  }
  if (qh->qhmem.ferr == 0 || qh->qhmem.IStracing < 0 || qh->qhmem.IStracing > 10 || (((qh->qhmem.ALIGNmask+1) & qh->qhmem.ALIGNmask) != 0)) {
    qh_fprintf_stderr(6244, "qhull internal error (qh_memcheck): either qh->qhmem is overwritten or qh->qhmem is not initialized.  Call qh_meminit or qh_new_qhull before calling qh_mem routines.  ferr 0x%x, IsTracing %d, ALIGNmask 0x%x\n", 
          qh->qhmem.ferr, qh->qhmem.IStracing, qh->qhmem.ALIGNmask);
    qh_exit(qhmem_ERRqhull);  /* can not use qh_errexit() */
  }
  if (qh->qhmem.IStracing != 0)
    qh_fprintf(qh, qh->qhmem.ferr, 8143, "qh_memcheck: check size of freelists on qh->qhmem\nqh_memcheck: A segmentation fault indicates an overwrite of qh->qhmem\n");
  for (i=0; i < qh->qhmem.TABLEsize; i++) {
    count=0;
    for (object= qh->qhmem.freelists[i]; object; object= *((void **)object))
      count++;
    totfree += qh->qhmem.sizetable[i] * count;
  }
  if (totfree != qh->qhmem.totfree) {
    qh_fprintf(qh, qh->qhmem.ferr, 6211, "qhull internal error (qh_memcheck): totfree %d not equal to freelist total %d\n", qh->qhmem.totfree, totfree);
    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
  }
  if (qh->qhmem.IStracing != 0)
    qh_fprintf(qh, qh->qhmem.ferr, 8144, "qh_memcheck: total size of freelists totfree is the same as qh->qhmem.totfree\n", totfree);
} /* memcheck */

/*----------------------------------

  qh_memfree(qh, object, insize )
    free up an object of size bytes
    size is insize from qh_memalloc

  notes:
    object may be NULL
    type checking warns if using (void **)object
    use qh_memfree_() for quick free's of small objects

  design:
    if size <= qh->qhmem.LASTsize
      append object to corresponding freelist
    else
      call qh_free(object)
*/
void qh_memfree(qhT *qh, void *object, int insize) {
  void **freelistp;
  int idx, outsize;

  if (!object)
    return;
  if (insize <= qh->qhmem.LASTsize) {
    qh->qhmem.freeshort++;
    idx= qh->qhmem.indextable[insize];
    outsize= qh->qhmem.sizetable[idx];
    qh->qhmem.totfree += outsize;
    qh->qhmem.totshort -= outsize;
    freelistp= qh->qhmem.freelists + idx;
    *((void **)object)= *freelistp;
    *freelistp= object;
#ifdef qh_TRACEshort
    idx= qh->qhmem.cntshort+qh->qhmem.cntquick+qh->qhmem.freeshort;
    if (qh->qhmem.IStracing >= 5)
        qh_fprintf(qh, qh->qhmem.ferr, 8142, "qh_mem %p n %8d free short: %d bytes (tot %d cnt %d)\n", object, idx, outsize, qh->qhmem.totshort, qh->qhmem.cntshort+qh->qhmem.cntquick-qh->qhmem.freeshort);
#endif
  }else {
    qh->qhmem.freelong++;
    qh->qhmem.totlong -= insize;
    if (qh->qhmem.IStracing >= 5)
      qh_fprintf(qh, qh->qhmem.ferr, 8058, "qh_mem %p n %8d free long: %d bytes (tot %d cnt %d)\n", object, qh->qhmem.cntlong+qh->qhmem.freelong, insize, qh->qhmem.totlong, qh->qhmem.cntlong-qh->qhmem.freelong);
    qh_free(object);
  }
} /* memfree */


/*---------------------------------

  qh_memfreeshort(qh, curlong, totlong )
    frees up all short and qhmem memory allocations

  returns:
    number and size of current long allocations

  notes:
    if qh_NOmem (qh_malloc() for all allocations),
       short objects (e.g., facetT) are not recovered.
       use qh_freeqhull(qh, qh_ALL) instead.

  see:
    qh_freeqhull(qh, allMem)
    qh_memtotal(qh, curlong, totlong, curshort, totshort, maxlong, totbuffer);
*/
void qh_memfreeshort(qhT *qh, int *curlong, int *totlong) {
  void *buffer, *nextbuffer;
  FILE *ferr;

  *curlong= qh->qhmem.cntlong - qh->qhmem.freelong;
  *totlong= qh->qhmem.totlong;
  for (buffer=qh->qhmem.curbuffer; buffer; buffer= nextbuffer) {
    nextbuffer= *((void **) buffer);
    qh_free(buffer);
  }
  qh->qhmem.curbuffer= NULL;
  if (qh->qhmem.LASTsize) {
    qh_free(qh->qhmem.indextable);
    qh_free(qh->qhmem.freelists);
    qh_free(qh->qhmem.sizetable);
  }
  ferr= qh->qhmem.ferr;
  memset((char *)&qh->qhmem, 0, sizeof(qh->qhmem));  /* every field is 0, FALSE, NULL */
  qh->qhmem.ferr= ferr;
} /* memfreeshort */


/*----------------------------------

  qh_meminit(qh, ferr )
    initialize qhmem and test sizeof(void *)
    Does not throw errors.  qh_exit on failure
*/
void qh_meminit(qhT *qh, FILE *ferr) {

  memset((char *)&qh->qhmem, 0, sizeof(qh->qhmem));  /* every field is 0, FALSE, NULL */
  if (ferr)
    qh->qhmem.ferr= ferr;
  else
    qh->qhmem.ferr= stderr;
  if (sizeof(void *) < sizeof(int)) {
    qh_fprintf(qh, qh->qhmem.ferr, 6083, "qhull internal error (qh_meminit): sizeof(void *) %d < sizeof(int) %d.  qset_r.c will not work\n", (int)sizeof(void*), (int)sizeof(int));
    qh_exit(qhmem_ERRqhull);  /* can not use qh_errexit() */
  }
  if (sizeof(void *) > sizeof(ptr_intT)) {
    qh_fprintf(qh, qh->qhmem.ferr, 6084, "qhull internal error (qh_meminit): sizeof(void *) %d > sizeof(ptr_intT) %d. Change ptr_intT in mem_r.h to 'long long'\n", (int)sizeof(void*), (int)sizeof(ptr_intT));
    qh_exit(qhmem_ERRqhull);  /* can not use qh_errexit() */
  }
  qh_memcheck(qh);
} /* meminit */

/*---------------------------------

  qh_meminitbuffers(qh, tracelevel, alignment, numsizes, bufsize, bufinit )
    initialize qhmem
    if tracelevel >= 5, trace memory allocations
    alignment= desired address alignment for memory allocations
    numsizes= number of freelists
    bufsize=  size of additional memory buffers for short allocations
    bufinit=  size of initial memory buffer for short allocations
*/
void qh_meminitbuffers(qhT *qh, int tracelevel, int alignment, int numsizes, int bufsize, int bufinit) {

  qh->qhmem.IStracing= tracelevel;
  qh->qhmem.NUMsizes= numsizes;
  qh->qhmem.BUFsize= bufsize;
  qh->qhmem.BUFinit= bufinit;
  qh->qhmem.ALIGNmask= alignment-1;
  if (qh->qhmem.ALIGNmask & ~qh->qhmem.ALIGNmask) {
    qh_fprintf(qh, qh->qhmem.ferr, 6085, "qhull internal error (qh_meminit): memory alignment %d is not a power of 2\n", alignment);
    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
  }
  qh->qhmem.sizetable= (int *) calloc((size_t)numsizes, sizeof(int));
  qh->qhmem.freelists= (void **) calloc((size_t)numsizes, sizeof(void *));
  if (!qh->qhmem.sizetable || !qh->qhmem.freelists) {
    qh_fprintf(qh, qh->qhmem.ferr, 6086, "qhull error (qh_meminit): insufficient memory\n");
    qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
  }
  if (qh->qhmem.IStracing >= 1)
    qh_fprintf(qh, qh->qhmem.ferr, 8059, "qh_meminitbuffers: memory initialized with alignment %d\n", alignment);
} /* meminitbuffers */

/*---------------------------------

  qh_memsetup(qh)
    set up memory after running memsize()
*/
void qh_memsetup(qhT *qh) {
  int k,i;

  qsort(qh->qhmem.sizetable, (size_t)qh->qhmem.TABLEsize, sizeof(int), qh_intcompare);
  qh->qhmem.LASTsize= qh->qhmem.sizetable[qh->qhmem.TABLEsize-1];
  if (qh->qhmem.LASTsize >= qh->qhmem.BUFsize || qh->qhmem.LASTsize >= qh->qhmem.BUFinit) {
    qh_fprintf(qh, qh->qhmem.ferr, 6087, "qhull error (qh_memsetup): largest mem size %d is >= buffer size %d or initial buffer size %d\n",
            qh->qhmem.LASTsize, qh->qhmem.BUFsize, qh->qhmem.BUFinit);
    qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
  }
  if (!(qh->qhmem.indextable= (int *)qh_malloc((size_t)(qh->qhmem.LASTsize+1) * sizeof(int)))) {
    qh_fprintf(qh, qh->qhmem.ferr, 6088, "qhull error (qh_memsetup): insufficient memory\n");
    qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
  }
  for (k=qh->qhmem.LASTsize+1; k--; )
    qh->qhmem.indextable[k]= k;
  i= 0;
  for (k=0; k <= qh->qhmem.LASTsize; k++) {
    if (qh->qhmem.indextable[k] <= qh->qhmem.sizetable[i])
      qh->qhmem.indextable[k]= i;
    else
      qh->qhmem.indextable[k]= ++i;
  }
} /* memsetup */

/*---------------------------------

  qh_memsize(qh, size )
    define a free list for this size
*/
void qh_memsize(qhT *qh, int size) {
  int k;

  if (qh->qhmem.LASTsize) {
    qh_fprintf(qh, qh->qhmem.ferr, 6089, "qhull internal error (qh_memsize): qh_memsize called after qh_memsetup\n");
    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
  }
  size= (size + qh->qhmem.ALIGNmask) & ~qh->qhmem.ALIGNmask;
  if (qh->qhmem.IStracing >= 3)
    qh_fprintf(qh, qh->qhmem.ferr, 3078, "qh_memsize: quick memory of %d bytes\n", size);
  for (k=qh->qhmem.TABLEsize; k--; ) {
    if (qh->qhmem.sizetable[k] == size)
      return;
  }
  if (qh->qhmem.TABLEsize < qh->qhmem.NUMsizes)
    qh->qhmem.sizetable[qh->qhmem.TABLEsize++]= size;
  else
    qh_fprintf(qh, qh->qhmem.ferr, 7060, "qhull warning (qh_memsize): free list table has room for only %d sizes\n", qh->qhmem.NUMsizes);
} /* memsize */


/*---------------------------------

  qh_memstatistics(qh, fp )
    print out memory statistics

    Verifies that qh->qhmem.totfree == sum of freelists
*/
void qh_memstatistics(qhT *qh, FILE *fp) {
  int i;
  int count;
  void *object;

  qh_memcheck(qh);
  qh_fprintf(qh, fp, 9278, "\nmemory statistics:\n\
%7d quick allocations\n\
%7d short allocations\n\
%7d long allocations\n\
%7d short frees\n\
%7d long frees\n\
%7d bytes of short memory in use\n\
%7d bytes of short memory in freelists\n\
%7d bytes of dropped short memory\n\
%7d bytes of unused short memory (estimated)\n\
%7d bytes of long memory allocated (max, except for input)\n\
%7d bytes of long memory in use (in %d pieces)\n\
%7d bytes of short memory buffers (minus links)\n\
%7d bytes per short memory buffer (initially %d bytes)\n",
           qh->qhmem.cntquick, qh->qhmem.cntshort, qh->qhmem.cntlong,
           qh->qhmem.freeshort, qh->qhmem.freelong,
           qh->qhmem.totshort, qh->qhmem.totfree,
           qh->qhmem.totdropped + qh->qhmem.freesize, qh->qhmem.totunused,
           qh->qhmem.maxlong, qh->qhmem.totlong, qh->qhmem.cntlong - qh->qhmem.freelong,
           qh->qhmem.totbuffer, qh->qhmem.BUFsize, qh->qhmem.BUFinit);
  if (qh->qhmem.cntlarger) {
    qh_fprintf(qh, fp, 9279, "%7d calls to qh_setlarger\n%7.2g     average copy size\n",
           qh->qhmem.cntlarger, ((double)qh->qhmem.totlarger)/(double)qh->qhmem.cntlarger);
    qh_fprintf(qh, fp, 9280, "  freelists(bytes->count):");
  }
  for (i=0; i < qh->qhmem.TABLEsize; i++) {
    count=0;
    for (object= qh->qhmem.freelists[i]; object; object= *((void **)object))
      count++;
    qh_fprintf(qh, fp, 9281, " %d->%d", qh->qhmem.sizetable[i], count);
  }
  qh_fprintf(qh, fp, 9282, "\n\n");
} /* memstatistics */


/*---------------------------------

  qh_NOmem
    turn off quick-fit memory allocation

  notes:
    uses qh_malloc() and qh_free() instead
*/
#else /* qh_NOmem */

void *qh_memalloc(qhT *qh, int insize) {
  void *object;

  if (!(object= qh_malloc((size_t)insize))) {
    qh_fprintf(qh, qh->qhmem.ferr, 6090, "qhull error (qh_memalloc): insufficient memory\n");
    qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
  }
  qh->qhmem.cntlong++;
  qh->qhmem.totlong += insize;
  if (qh->qhmem.maxlong < qh->qhmem.totlong)
      qh->qhmem.maxlong= qh->qhmem.totlong;
  if (qh->qhmem.IStracing >= 5)
    qh_fprintf(qh, qh->qhmem.ferr, 8060, "qh_mem %p n %8d alloc long: %d bytes (tot %d cnt %d)\n", object, qh->qhmem.cntlong+qh->qhmem.freelong, insize, qh->qhmem.totlong, qh->qhmem.cntlong-qh->qhmem.freelong);
  return object;
}

void qh_memcheck(qhT *qh) {
}

void qh_memfree(qhT *qh, void *object, int insize) {

  if (!object)
    return;
  qh_free(object);
  qh->qhmem.freelong++;
  qh->qhmem.totlong -= insize;
  if (qh->qhmem.IStracing >= 5)
    qh_fprintf(qh, qh->qhmem.ferr, 8061, "qh_mem %p n %8d free long: %d bytes (tot %d cnt %d)\n", object, qh->qhmem.cntlong+qh->qhmem.freelong, insize, qh->qhmem.totlong, qh->qhmem.cntlong-qh->qhmem.freelong);
}

void qh_memfreeshort(qhT *qh, int *curlong, int *totlong) {
  *totlong= qh->qhmem.totlong;
  *curlong= qh->qhmem.cntlong - qh->qhmem.freelong;
  memset((char *)&qh->qhmem, 0, sizeof(qh->qhmem));  /* every field is 0, FALSE, NULL */
}

void qh_meminit(qhT *qh, FILE *ferr) {

  memset((char *)&qh->qhmem, 0, sizeof(qh->qhmem));  /* every field is 0, FALSE, NULL */
  if (ferr)
      qh->qhmem.ferr= ferr;
  else
      qh->qhmem.ferr= stderr;
  if (sizeof(void *) < sizeof(int)) {
    qh_fprintf(qh, qh->qhmem.ferr, 6091, "qhull internal error (qh_meminit): sizeof(void *) %d < sizeof(int) %d.  qset_r.c will not work\n", (int)sizeof(void*), (int)sizeof(int));
    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
  }
}

void qh_meminitbuffers(qhT *qh, int tracelevel, int alignment, int numsizes, int bufsize, int bufinit) {

  qh->qhmem.IStracing= tracelevel;
}

void qh_memsetup(qhT *qh) {
}

void qh_memsize(qhT *qh, int size) {
}

void qh_memstatistics(qhT *qh, FILE *fp) {

  qh_fprintf(qh, fp, 9409, "\nmemory statistics:\n\
%7d long allocations\n\
%7d long frees\n\
%7d bytes of long memory allocated (max, except for input)\n\
%7d bytes of long memory in use (in %d pieces)\n",
           qh->qhmem.cntlong,
           qh->qhmem.freelong,
           qh->qhmem.maxlong, qh->qhmem.totlong, qh->qhmem.cntlong - qh->qhmem.freelong);
}

#endif /* qh_NOmem */

/*---------------------------------

  qh_memtotal(qh, totlong, curlong, totshort, curshort, maxlong, totbuffer )
    Return the total, allocated long and short memory

  returns:
    Returns the total current bytes of long and short allocations
    Returns the current count of long and short allocations
    Returns the maximum long memory and total short buffer (minus one link per buffer)
    Does not error (for deprecated UsingLibQhull.cpp in libqhullpcpp)
*/
void qh_memtotal(qhT *qh, int *totlong, int *curlong, int *totshort, int *curshort, int *maxlong, int *totbuffer) {
    *totlong= qh->qhmem.totlong;
    *curlong= qh->qhmem.cntlong - qh->qhmem.freelong;
    *totshort= qh->qhmem.totshort;
    *curshort= qh->qhmem.cntshort + qh->qhmem.cntquick - qh->qhmem.freeshort;
    *maxlong= qh->qhmem.maxlong;
    *totbuffer= qh->qhmem.totbuffer;
} /* memtotlong */

qhull-2020.2/src/libqhull_r/mem_r.h0000644060175106010010000002166613661631132015377 0ustar  bbarber/*
  ---------------------------------

   mem_r.h
     prototypes for memory management functions

   see qh-mem_r.htm, mem_r.c and qset_r.h

   for error handling, writes message and calls
     qh_errexit(qhT *qh, qhmem_ERRmem, NULL, NULL) if insufficient memory
       and
     qh_errexit(qhT *qh, qhmem_ERRqhull, NULL, NULL) otherwise

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull_r/mem_r.h#6 $$Change: 2953 $
   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
*/

#ifndef qhDEFmem
#define qhDEFmem 1

#include 

#ifndef DEFsetT
#define DEFsetT 1
typedef struct setT setT;          /* defined in qset_r.h */
#endif

#ifndef DEFqhT
#define DEFqhT 1
typedef struct qhT qhT;          /* defined in libqhull_r.h */
#endif

/*---------------------------------

  qh_NOmem
    turn off quick-fit memory allocation

  notes:
    mem_r.c implements Quickfit memory allocation for about 20% time
    savings.  If it fails on your machine, try to locate the
    problem, and send the answer to qhull@qhull.org.  If this can
    not be done, define qh_NOmem to use malloc/free instead.

    #define qh_NOmem
*/

/*---------------------------------

qh_TRACEshort
Trace short and quick memory allocations at T5

*/
#define qh_TRACEshort

/*-------------------------------------------
    to avoid bus errors, memory allocation must consider alignment requirements.
    malloc() automatically takes care of alignment.   Since mem_r.c manages
    its own memory, we need to explicitly specify alignment in
    qh_meminitbuffers().

    A safe choice is sizeof(double).  sizeof(float) may be used if doubles
    do not occur in data structures and pointers are the same size.  Be careful
    of machines (e.g., DEC Alpha) with large pointers.  If gcc is available,
    use __alignof__(double) or fmax_(__alignof__(float), __alignof__(void *)).

   see qh_MEMalign in user_r.h for qhull's alignment
*/

#define qhmem_ERRmem 4    /* matches qh_ERRmem in libqhull_r.h */
#define qhmem_ERRqhull 5  /* matches qh_ERRqhull in libqhull_r.h */

/*----------------------------------

  ptr_intT
    for casting a void * to an integer-type that holds a pointer
    Used for integer expressions (e.g., computing qh_gethash() in poly_r.c)

  notes:
    WARN64 -- these notes indicate 64-bit issues
    On 64-bit machines, a pointer may be larger than an 'int'.
    qh_meminit()/mem_r.c checks that 'ptr_intT' holds a 'void*'
    ptr_intT is typically a signed value, but not necessarily so
    size_t is typically unsigned, but should match the parameter type
    Qhull uses int instead of size_t except for system calls such as malloc, qsort, qh_malloc, etc.
    This matches Qt convention and is easier to work with.
*/
#if (defined(__MINGW64__)) && defined(_WIN64)
typedef long long ptr_intT;
#elif defined(_MSC_VER) && defined(_WIN64)
typedef long long ptr_intT;
#else
typedef long ptr_intT;
#endif

/*----------------------------------

  qhmemT
    global memory structure for mem_r.c

 notes:
   users should ignore qhmem except for writing extensions
   qhmem is allocated in mem_r.c

   qhmem could be swapable like qh and qhstat, but then
   multiple qh's and qhmem's would need to keep in synch.
   A swapable qhmem would also waste memory buffers.  As long
   as memory operations are atomic, there is no problem with
   multiple qh structures being active at the same time.
   If you need separate address spaces, you can swap the
   contents of qh->qhmem.
*/
typedef struct qhmemT qhmemT;

struct qhmemT {               /* global memory management variables */
  int      BUFsize;           /* size of memory allocation buffer */
  int      BUFinit;           /* initial size of memory allocation buffer */
  int      TABLEsize;         /* actual number of sizes in free list table */
  int      NUMsizes;          /* maximum number of sizes in free list table */
  int      LASTsize;          /* last size in free list table */
  int      ALIGNmask;         /* worst-case alignment, must be 2^n-1 */
  void   **freelists;          /* free list table, linked by offset 0 */
  int     *sizetable;         /* size of each freelist */
  int     *indextable;        /* size->index table */
  void    *curbuffer;         /* current buffer, linked by offset 0 */
  void    *freemem;           /*   free memory in curbuffer */
  int      freesize;          /*   size of freemem in bytes */
  setT    *tempstack;         /* stack of temporary memory, managed by users */
  FILE    *ferr;              /* file for reporting errors when 'qh' may be undefined */
  int      IStracing;         /* =5 if tracing memory allocations */
  int      cntquick;          /* count of quick allocations */
                              /* Note: removing statistics doesn't effect speed */
  int      cntshort;          /* count of short allocations */
  int      cntlong;           /* count of long allocations */
  int      freeshort;         /* count of short memfrees */
  int      freelong;          /* count of long memfrees */
  int      totbuffer;         /* total short memory buffers minus buffer links */
  int      totdropped;        /* total dropped memory at end of short memory buffers (e.g., freesize) */
  int      totfree;           /* total size of free, short memory on freelists */
  int      totlong;           /* total size of long memory in use */
  int      maxlong;           /*   maximum totlong */
  int      totshort;          /* total size of short memory in use */
  int      totunused;         /* total unused short memory (estimated, short size - request size of first allocations) */
  int      cntlarger;         /* count of setlarger's */
  int      totlarger;         /* total copied by setlarger */
};


/*==================== -macros ====================*/

/*----------------------------------

  qh_memalloc_(qh, insize, freelistp, object, type)
    returns object of size bytes
        assumes size<=qh->qhmem.LASTsize and void **freelistp is a temp
*/

#if defined qh_NOmem
#define qh_memalloc_(qh, insize, freelistp, object, type) {\
  (void)freelistp; /* Avoid warnings */ \
  object= (type *)qh_memalloc(qh, insize); }
#elif defined qh_TRACEshort
#define qh_memalloc_(qh, insize, freelistp, object, type) {\
  (void)freelistp; /* Avoid warnings */ \
  object= (type *)qh_memalloc(qh, insize); }
#else /* !qh_NOmem */

#define qh_memalloc_(qh, insize, freelistp, object, type) {\
  freelistp= qh->qhmem.freelists + qh->qhmem.indextable[insize];\
  if ((object= (type *)*freelistp)) {\
    qh->qhmem.totshort += qh->qhmem.sizetable[qh->qhmem.indextable[insize]]; \
    qh->qhmem.totfree -= qh->qhmem.sizetable[qh->qhmem.indextable[insize]]; \
    qh->qhmem.cntquick++;  \
    *freelistp= *((void **)*freelistp);\
  }else object= (type *)qh_memalloc(qh, insize);}
#endif

/*----------------------------------

  qh_memfree_(qh, object, insize, freelistp)
    free up an object

  notes:
    object may be NULL
    assumes size<=qh->qhmem.LASTsize and void **freelistp is a temp
*/
#if defined qh_NOmem
#define qh_memfree_(qh, object, insize, freelistp) {\
  (void)freelistp; /* Avoid warnings */ \
  qh_memfree(qh, object, insize); }
#elif defined qh_TRACEshort
#define qh_memfree_(qh, object, insize, freelistp) {\
  (void)freelistp; /* Avoid warnings */ \
  qh_memfree(qh, object, insize); }
#else /* !qh_NOmem */

#define qh_memfree_(qh, object, insize, freelistp) {\
  if (object) { \
    qh->qhmem.freeshort++;\
    freelistp= qh->qhmem.freelists + qh->qhmem.indextable[insize];\
    qh->qhmem.totshort -= qh->qhmem.sizetable[qh->qhmem.indextable[insize]]; \
    qh->qhmem.totfree += qh->qhmem.sizetable[qh->qhmem.indextable[insize]]; \
    *((void **)object)= *freelistp;\
    *freelistp= object;}}
#endif

/*=============== prototypes in alphabetical order ============*/

#ifdef __cplusplus
extern "C" {
#endif

void *qh_memalloc(qhT *qh, int insize);
void qh_memcheck(qhT *qh);
void qh_memfree(qhT *qh, void *object, int insize);
void qh_memfreeshort(qhT *qh, int *curlong, int *totlong);
void qh_meminit(qhT *qh, FILE *ferr);
void qh_meminitbuffers(qhT *qh, int tracelevel, int alignment, int numsizes,
                        int bufsize, int bufinit);
void qh_memsetup(qhT *qh);
void qh_memsize(qhT *qh, int size);
void qh_memstatistics(qhT *qh, FILE *fp);
void qh_memtotal(qhT *qh, int *totlong, int *curlong, int *totshort, int *curshort, int *maxlong, int *totbuffer);

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* qhDEFmem */
qhull-2020.2/src/libqhull_r/merge_r.c0000644060175106010010000065545613661631132015725 0ustar  bbarber/*
  ---------------------------------

   merge_r.c
   merges non-convex facets

   see qh-merge_r.htm and merge_r.h

   other modules call qh_premerge() and qh_postmerge()

   the user may call qh_postmerge() to perform additional merges.

   To remove deleted facets and vertices (qhull() in libqhull_r.c):
     qh_partitionvisible(qh, !qh_ALL, &numoutside);  // visible_list, newfacet_list
     qh_deletevisible();         // qh.visible_list
     qh_resetlists(qh, False, qh_RESETvisible);       // qh.visible_list newvertex_list newfacet_list

   assumes qh.CENTERtype= centrum

   merges occur in qh_mergefacet and in qh_mergecycle
   vertex->neighbors not set until the first merge occurs

   Copyright (c) 1993-2020 C.B. Barber.
   $Id: //main/2019/qhull/src/libqhull_r/merge_r.c#14 $$Change: 2953 $
   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
*/

#include "qhull_ra.h"

#ifndef qh_NOmerge

/* MRGnone, etc. */
const char *mergetypes[]= {
  "none",
  "coplanar",
  "anglecoplanar",
  "concave",
  "concavecoplanar",
  "twisted",
  "flip",
  "dupridge",
  "subridge",
  "vertices",
  "degen",
  "redundant",
  "mirror",
  "coplanarhorizon",
};

/*===== functions(alphabetical after premerge and postmerge) ======*/

/*---------------------------------

  qh_premerge(qh, apexpointid, maxcentrum )
    pre-merge nonconvex facets in qh.newfacet_list for apexpointid
    maxcentrum defines coplanar and concave (qh_test_appendmerge)

  returns:
    deleted facets added to qh.visible_list with facet->visible set

  notes:
    only called by qh_addpoint
    uses globals, qh.MERGEexact, qh.PREmerge

  design:
    mark dupridges in qh.newfacet_list
    merge facet cycles in qh.newfacet_list
    merge dupridges and concave facets in qh.newfacet_list
    check merged facet cycles for degenerate and redundant facets
    merge degenerate and redundant facets
    collect coplanar and concave facets
    merge concave, coplanar, degenerate, and redundant facets
*/
void qh_premerge(qhT *qh, int apexpointid, realT maxcentrum, realT maxangle /* qh.newfacet_list */) {
  boolT othermerge= False;

  if (qh->ZEROcentrum && qh_checkzero(qh, !qh_ALL))
    return;
  trace2((qh, qh->ferr, 2008, "qh_premerge: premerge centrum %2.2g angle %4.4g for apex p%d newfacet_list f%d\n",
            maxcentrum, maxangle, apexpointid, getid_(qh->newfacet_list)));
  if (qh->IStracing >= 4 && qh->num_facets < 100)
    qh_printlists(qh);
  qh->centrum_radius= maxcentrum;
  qh->cos_max= maxangle;
  if (qh->hull_dim >=3) {
    qh_mark_dupridges(qh, qh->newfacet_list, qh_ALL); /* facet_mergeset */
    qh_mergecycle_all(qh, qh->newfacet_list, &othermerge);
    qh_forcedmerges(qh, &othermerge /* qh.facet_mergeset */);
  }else /* qh.hull_dim == 2 */
    qh_mergecycle_all(qh, qh->newfacet_list, &othermerge);
  qh_flippedmerges(qh, qh->newfacet_list, &othermerge);
  if (!qh->MERGEexact || zzval_(Ztotmerge)) {
    zinc_(Zpremergetot);
    qh->POSTmerging= False;
    qh_getmergeset_initial(qh, qh->newfacet_list);
    qh_all_merges(qh, othermerge, False);
  }
} /* premerge */

/*---------------------------------

  qh_postmerge(qh, reason, maxcentrum, maxangle, vneighbors )
    post-merge nonconvex facets as defined by maxcentrum and maxangle
    'reason' is for reporting progress
    if vneighbors ('Qv'),
      calls qh_test_vneighbors at end of qh_all_merge from qh_postmerge

  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:
    called by qh_qhull after qh_buildhull
    called if a merge may be needed due to
      qh.MERGEexact ('Qx'), qh_DIMreduceBuild, POSTmerge (e.g., 'Cn'), or TESTvneighbors ('Qv')
    if firstmerge,
      calls qh_reducevertices before qh_getmergeset

  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 occurred
        set vertex->delridge {will retest the ridge}
        if qh.MERGEexact
          call qh_reducevertices()
      if no pre-merging
        merge flipped facets
    determine non-convex facets
    merge all non-convex facets
*/
void qh_postmerge(qhT *qh, const char *reason, realT maxcentrum, realT maxangle,
                      boolT vneighbors) {
  facetT *newfacet;
  boolT othermerges= False;
  vertexT *vertex;

  if (qh->REPORTfreq || qh->IStracing) {
    qh_buildtracing(qh, NULL, NULL);
    qh_printsummary(qh, qh->ferr);
    if (qh->PRINTstatistics)
      qh_printallstatistics(qh, qh->ferr, "reason");
    qh_fprintf(qh, qh->ferr, 8062, "\n%s with 'C%.2g' and 'A%.2g'\n",
        reason, maxcentrum, maxangle);
  }
  trace2((qh, qh->ferr, 2009, "qh_postmerge: postmerge.  test vneighbors? %d\n",
            vneighbors));
  qh->centrum_radius= maxcentrum;
  qh->cos_max= maxangle;
  qh->POSTmerging= True;
  if (qh->visible_list != qh->facet_list) {  /* first call due to qh_buildhull, multiple calls if qh.POSTmerge */
    qh->NEWfacets= True;
    qh->visible_list= qh->newfacet_list= qh->facet_list;
    FORALLnew_facets {              /* all facets are new facets for qh_postmerge */
      newfacet->newfacet= True;
       if (!newfacet->simplicial)
        newfacet->newmerge= True;   /* test f.vertices for 'delridge'.  'newmerge' was cleared at end of qh_all_merges */
     zinc_(Zpostfacets);
    }
    qh->newvertex_list= qh->vertex_list;
    FORALLvertices
      vertex->newfacet= True;
    if (qh->VERTEXneighbors) {  /* a merge has occurred */
      if (qh->MERGEexact && qh->hull_dim <= qh_DIMreduceBuild)
        qh_reducevertices(qh);  /* qh_all_merges did not call qh_reducevertices for v.delridge */
    }
    if (!qh->PREmerge && !qh->MERGEexact)
      qh_flippedmerges(qh, qh->newfacet_list, &othermerges);
  }
  qh_getmergeset_initial(qh, qh->newfacet_list);
  qh_all_merges(qh, False, vneighbors); /* calls qh_reducevertices before exiting */
  FORALLnew_facets
    newfacet->newmerge= False;   /* Was True if no vertex in f.vertices was 'delridge' */
} /* post_merge */

/*---------------------------------

  qh_all_merges(qh, othermerge, vneighbors )
    merge all non-convex facets

    set othermerge if already merged facets (calls qh_reducevertices)
    if vneighbors ('Qv' at qh.POSTmerge)
      tests vertex neighbors for convexity at end (qh_test_vneighbors)
    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 implicit argument since merges call qh_removefacet()
    [apr'19] restored qh_setdellast in place of qh_next_facetmerge.  Much faster for post-merge

  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 qh.POSTmerging
          periodically call qh_reducevertices to reduce extra vertices and redundant vertices
      after each pass, if qh.VERTEXneighbors
        if qh.POSTmerging or was a merge with qh.hull_dim<=5
          call qh_reducevertices
          update qh.facet_mergeset if degenredundant merges
      if 'Qv' and qh.POSTmerging
        test vertex neighbors for convexity
*/
void qh_all_merges(qhT *qh, boolT othermerge, boolT vneighbors) {
  facetT *facet1, *facet2, *newfacet;
  mergeT *merge;
  boolT wasmerge= False, isreduce;
  void **freelistp;  /* used if !qh_NOmem by qh_memfree_() */
  vertexT *vertex;
  realT angle, distance;
  mergeType mergetype;
  int numcoplanar=0, numconcave=0, numconcavecoplanar= 0, numdegenredun= 0, numnewmerges= 0, numtwisted= 0;

  trace2((qh, qh->ferr, 2010, "qh_all_merges: starting to merge %d facet and %d degenerate merges for new facets f%d, othermerge? %d\n",
            qh_setsize(qh, qh->facet_mergeset), qh_setsize(qh, qh->degen_mergeset), getid_(qh->newfacet_list), othermerge));

  while (True) {
    wasmerge= False;
    while (qh_setsize(qh, qh->facet_mergeset) > 0 || qh_setsize(qh, qh->degen_mergeset) > 0) {
      if (qh_setsize(qh, qh->degen_mergeset) > 0) {
        numdegenredun += qh_merge_degenredundant(qh);
        wasmerge= True;
      }
      while ((merge= (mergeT *)qh_setdellast(qh->facet_mergeset))) {
        facet1= merge->facet1;
        facet2= merge->facet2;
        vertex= merge->vertex1;  /* not used for qh.facet_mergeset*/
        mergetype= merge->mergetype;
        angle= merge->angle;
        distance= merge->distance;
        qh_memfree_(qh, merge, (int)sizeof(mergeT), freelistp);   /* 'merge' is invalid */
        if (facet1->visible || facet2->visible) {
          trace3((qh, qh->ferr, 3045, "qh_all_merges: drop merge of f%d (del? %d) into f%d (del? %d) mergetype %d, dist %4.4g, angle %4.4g.  One or both facets is deleted\n",
            facet1->id, facet1->visible, facet2->id, facet2->visible, mergetype, distance, angle));
          continue;
        }else if (mergetype == MRGcoplanar || mergetype == MRGanglecoplanar) {
          if (qh->MERGEindependent) {
            if ((!facet1->tested && facet1->newfacet)
            || (!facet2->tested && facet2->newfacet)) {
              trace3((qh, qh->ferr, 3064, "qh_all_merges: drop merge of f%d (tested? %d) into f%d (tested? %d) mergetype %d, dist %2.2g, angle %4.4g.  Merge independent sets of coplanar merges\n",
                facet1->id, facet1->visible, facet2->id, facet2->visible, mergetype, distance, angle));
              continue;
            }
          }
        }
        trace3((qh, qh->ferr, 3047, "qh_all_merges: merge f%d and f%d type %d dist %2.2g angle %4.4g\n",
          facet1->id, facet2->id, mergetype, distance, angle));
        if (mergetype == MRGtwisted)
          qh_merge_twisted(qh, facet1, facet2);
        else
          qh_merge_nonconvex(qh, facet1, facet2, mergetype);
        numnewmerges++;
        numdegenredun += qh_merge_degenredundant(qh);
        wasmerge= True;
        if (mergetype == MRGconcave)
          numconcave++;
        else if (mergetype == MRGconcavecoplanar)
          numconcavecoplanar++;
        else if (mergetype == MRGtwisted)
          numtwisted++;
        else if (mergetype == MRGcoplanar || mergetype == MRGanglecoplanar)
          numcoplanar++;
        else {
          qh_fprintf(qh, qh->ferr, 6394, "qhull internal error (qh_all_merges): expecting concave, coplanar, or twisted merge.  Got merge f%d f%d v%d mergetype %d\n",
            getid_(facet1), getid_(facet2), getid_(vertex), mergetype);
          qh_errexit2(qh, qh_ERRqhull, facet1, facet2);
        }
      } /* while qh_setdellast */
      if (qh->POSTmerging && qh->hull_dim <= qh_DIMreduceBuild
      && numnewmerges > qh_MAXnewmerges) {
        numnewmerges= 0;
        wasmerge= othermerge= False;
        qh_reducevertices(qh);  /* otherwise large post merges too slow */
      }
      qh_getmergeset(qh, qh->newfacet_list); /* qh.facet_mergeset */
    } /* while facet_mergeset or degen_mergeset */
    if (qh->VERTEXneighbors) {  /* at least one merge */
      isreduce= False;
      if (qh->POSTmerging && qh->hull_dim >= 4) {
        isreduce= True;
      }else if (qh->POSTmerging || !qh->MERGEexact) {
        if ((wasmerge || othermerge) && qh->hull_dim > 2 && qh->hull_dim <= qh_DIMreduceBuild)
          isreduce= True;
      }
      if (isreduce) {
        wasmerge= othermerge= False;
        if (qh_reducevertices(qh)) {
          qh_getmergeset(qh, qh->newfacet_list); /* facet_mergeset */
          continue;
        }
      }
    }
    if (vneighbors && qh_test_vneighbors(qh /* qh.newfacet_list */))
      continue;
    break;
  } /* while (True) */
  if (wasmerge || othermerge) {
    trace3((qh, qh->ferr, 3033, "qh_all_merges: skip qh_reducevertices due to post-merging, no qh.VERTEXneighbors (%d), or hull_dim %d ==2 or >%d\n", qh->VERTEXneighbors, qh->hull_dim, qh_DIMreduceBuild))
    FORALLnew_facets {
      newfacet->newmerge= False;
    }
  }
  if (qh->CHECKfrequently && !qh->MERGEexact) {
    qh->old_randomdist= qh->RANDOMdist;
    qh->RANDOMdist= False;
    qh_checkconvex(qh, qh->newfacet_list, qh_ALGORITHMfault);
    /* qh_checkconnect(qh); [this is slow and it changes the facet order] */
    qh->RANDOMdist= qh->old_randomdist;
  }
  trace1((qh, qh->ferr, 1009, "qh_all_merges: merged %d coplanar %d concave %d concavecoplanar %d twisted facets and %d degen or redundant facets.\n",
    numcoplanar, numconcave, numconcavecoplanar, numtwisted, numdegenredun));
  if (qh->IStracing >= 4 && qh->num_facets < 500)
    qh_printlists(qh);
} /* all_merges */

/*---------------------------------

  qh_all_vertexmerges(qh, apexpointid, facet, &retryfacet )
    merge vertices in qh.vertex_mergeset and subsequent merges

  returns:
    returns retryfacet for facet (if defined)
    updates qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices
    mergesets are empty
    if merges, resets facet lists

  notes:
    called from qh_qhull, qh_addpoint, and qh_buildcone_mergepinched
    vertex merges occur after facet merges and qh_resetlists

  design:
    while merges in vertex_mergeset (MRGvertices)
      merge a pair of pinched vertices
      update vertex neighbors
      merge non-convex and degenerate facets and check for ridges with duplicate vertices
      partition outside points of deleted, "visible" facets
*/
void qh_all_vertexmerges(qhT *qh, int apexpointid, facetT *facet, facetT **retryfacet) {
  int numpoints; /* ignore count of partitioned points.  Used by qh_addpoint for Zpbalance */

  if (retryfacet)
    *retryfacet= facet;
  while (qh_setsize(qh, qh->vertex_mergeset) > 0) {
    trace1((qh, qh->ferr, 1057, "qh_all_vertexmerges: starting to merge %d vertex merges for apex p%d facet f%d\n",
            qh_setsize(qh, qh->vertex_mergeset), apexpointid, getid_(facet)));
    if (qh->IStracing >= 4  && qh->num_facets < 1000)
      qh_printlists(qh);
    qh_merge_pinchedvertices(qh, apexpointid /* qh.vertex_mergeset, visible_list, newvertex_list, newfacet_list */);
    qh_update_vertexneighbors(qh); /* update neighbors of qh.newvertex_list from qh_newvertices for deleted facets on qh.visible_list */
                           /* test ridges and merge non-convex facets */
    qh_getmergeset(qh, qh->newfacet_list);
    qh_all_merges(qh, True, False); /* calls qh_reducevertices */
    if (qh->CHECKfrequently)
      qh_checkpolygon(qh, qh->facet_list);
    qh_partitionvisible(qh, !qh_ALL, &numpoints /* qh.visible_list qh.del_vertices*/);
    if (retryfacet)
      *retryfacet= qh_getreplacement(qh, *retryfacet);
    qh_deletevisible(qh /* qh.visible_list  qh.del_vertices*/);
    qh_resetlists(qh, False, qh_RESETvisible /* qh.visible_list newvertex_list qh.newfacet_list */);
    if (qh->IStracing >= 4  && qh->num_facets < 1000) {
      qh_printlists(qh);
      qh_checkpolygon(qh, qh->facet_list);
    }
  }
} /* all_vertexmerges */

/*---------------------------------

  qh_appendmergeset(qh, facet, vertex, neighbor, mergetype, dist, angle )
    appends an entry to qh.facet_mergeset or qh.degen_mergeset
    if 'dist' is unknown, set it to 0.0
        if 'angle' is unknown, set it to 1.0 (coplanar)

  returns:
    merge appended to facet_mergeset or degen_mergeset
      sets ->degenerate or ->redundant if degen_mergeset

  notes:
    caller collects statistics and/or caller of qh_mergefacet
    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 (merged last)
    else if redundant merge
      append to qh.degen_mergeset
*/
void qh_appendmergeset(qhT *qh, facetT *facet, facetT *neighbor, mergeType mergetype, coordT dist, realT angle) {
  mergeT *merge, *lastmerge;
  void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */
  const char *mergename;

  if ((facet->redundant && mergetype != MRGmirror) || neighbor->redundant) {
    trace3((qh, qh->ferr, 3051, "qh_appendmergeset: f%d is already redundant (%d) or f%d is already redundant (%d).  Ignore merge f%d and f%d type %d\n",
      facet->id, facet->redundant, neighbor->id, neighbor->redundant, facet->id, neighbor->id, mergetype));
    return;
  }
  if (facet->degenerate && mergetype == MRGdegen) {
    trace3((qh, qh->ferr, 3077, "qh_appendmergeset: f%d is already degenerate.  Ignore merge f%d type %d (MRGdegen)\n",
      facet->id, facet->id, mergetype));
    return;
  }
  if (!qh->facet_mergeset || !qh->degen_mergeset) {
    qh_fprintf(qh, qh->ferr, 6403, "qhull internal error (qh_appendmergeset): expecting temp set defined for qh.facet_mergeset (0x%x) and qh.degen_mergeset (0x%x).  Got NULL\n",
      qh->facet_mergeset, qh->degen_mergeset);
    /* otherwise qh_setappend creates a new set that is not freed by qh_freebuild() */
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  if (neighbor->flipped && !facet->flipped) {
    if (mergetype != MRGdupridge) {
      qh_fprintf(qh, qh->ferr, 6355, "qhull internal error (qh_appendmergeset): except for MRGdupridge, cannot merge a non-flipped facet f%d into flipped f%d, mergetype %d, dist %4.4g\n",
        facet->id, neighbor->id, mergetype, dist);
      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
    }else {
      trace2((qh, qh->ferr, 2106, "qh_appendmergeset: dupridge will merge a non-flipped facet f%d into flipped f%d, dist %4.4g\n",
        facet->id, neighbor->id, dist));
    }
  }
  qh_memalloc_(qh, (int)sizeof(mergeT), freelistp, merge, mergeT);
  merge->angle= angle;
  merge->distance= dist;
  merge->facet1= facet;
  merge->facet2= neighbor;
  merge->vertex1= NULL;
  merge->vertex2= NULL;
  merge->ridge1= NULL;
  merge->ridge2= NULL;
  merge->mergetype= mergetype;
  if(mergetype > 0 && mergetype < sizeof(mergetypes)/sizeof(char *))
    mergename= mergetypes[mergetype];
  else
    mergename= mergetypes[MRGnone];
  if (mergetype < MRGdegen)
    qh_setappend(qh, &(qh->facet_mergeset), merge);
  else if (mergetype == MRGdegen) {
    facet->degenerate= True;
    if (!(lastmerge= (mergeT *)qh_setlast(qh->degen_mergeset))
    || lastmerge->mergetype == MRGdegen)
      qh_setappend(qh, &(qh->degen_mergeset), merge);
    else
      qh_setaddnth(qh, &(qh->degen_mergeset), 0, merge);    /* merged last */
  }else if (mergetype == MRGredundant) {
    facet->redundant= True;
    qh_setappend(qh, &(qh->degen_mergeset), merge);
  }else /* mergetype == MRGmirror */ {
    if (facet->redundant || neighbor->redundant) {
      qh_fprintf(qh, qh->ferr, 6092, "qhull internal error (qh_appendmergeset): facet f%d or f%d is already a mirrored facet (i.e., 'redundant')\n",
           facet->id, neighbor->id);
      qh_errexit2(qh, qh_ERRqhull, facet, neighbor);
    }
    if (!qh_setequal(facet->vertices, neighbor->vertices)) {
      qh_fprintf(qh, qh->ferr, 6093, "qhull internal error (qh_appendmergeset): mirrored facets f%d and f%d do not have the same vertices\n",
           facet->id, neighbor->id);
      qh_errexit2(qh, qh_ERRqhull, facet, neighbor);
    }
    facet->redundant= True;
    neighbor->redundant= True;
    qh_setappend(qh, &(qh->degen_mergeset), merge);
  }
  if (merge->mergetype >= MRGdegen) {
    trace3((qh, qh->ferr, 3044, "qh_appendmergeset: append merge f%d and f%d type %d (%s) to qh.degen_mergeset (size %d)\n",
      merge->facet1->id, merge->facet2->id, merge->mergetype, mergename, qh_setsize(qh, qh->degen_mergeset)));
  }else {
    trace3((qh, qh->ferr, 3027, "qh_appendmergeset: append merge f%d and f%d type %d (%s) dist %2.2g angle %4.4g to qh.facet_mergeset (size %d)\n",
      merge->facet1->id, merge->facet2->id, merge->mergetype, mergename, merge->distance, merge->angle, qh_setsize(qh, qh->facet_mergeset)));
  }
} /* appendmergeset */


/*---------------------------------

  qh_appendvertexmerge(qh, vertex, vertex2, mergetype, distance, ridge1, ridge2 )
    appends a vertex merge to qh.vertex_mergeset
    MRGsubridge includes two ridges (from MRGdupridge)
    MRGvertices includes two ridges

  notes:
    called by qh_getpinchedmerges for MRGsubridge
    called by qh_maybe_duplicateridge and qh_maybe_duplicateridges for MRGvertices
    only way to add a vertex merge to qh.vertex_mergeset
    checked by qh_next_vertexmerge
*/
void qh_appendvertexmerge(qhT *qh, vertexT *vertex, vertexT *destination, mergeType mergetype, realT distance, ridgeT *ridge1, ridgeT *ridge2) {
  mergeT *merge;
  void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */
  const char *mergename;

  if (!qh->vertex_mergeset) {
    qh_fprintf(qh, qh->ferr, 6387, "qhull internal error (qh_appendvertexmerge): expecting temp set defined for qh.vertex_mergeset (0x%x).  Got NULL\n",
      qh->vertex_mergeset);
    /* otherwise qh_setappend creates a new set that is not freed by qh_freebuild() */
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  qh_memalloc_(qh, (int)sizeof(mergeT), freelistp, merge, mergeT);
  merge->angle= qh_ANGLEnone;
  merge->distance= distance;
  merge->facet1= NULL;
  merge->facet2= NULL;
  merge->vertex1= vertex;
  merge->vertex2= destination;
  merge->ridge1= ridge1;
  merge->ridge2= ridge2;
  merge->mergetype= mergetype;
  if(mergetype > 0 && mergetype < sizeof(mergetypes)/sizeof(char *))
    mergename= mergetypes[mergetype];
  else
    mergename= mergetypes[MRGnone];
  if (mergetype == MRGvertices) {
    if (!ridge1 || !ridge2 || ridge1 == ridge2) {
      qh_fprintf(qh, qh->ferr, 6106, "qhull internal error (qh_appendvertexmerge): expecting two distinct ridges for MRGvertices.  Got r%d r%d\n",
        getid_(ridge1), getid_(ridge2));
      qh_errexit(qh, qh_ERRqhull, NULL, ridge1);
    }
  }
  qh_setappend(qh, &(qh->vertex_mergeset), merge);
  trace3((qh, qh->ferr, 3034, "qh_appendvertexmerge: append merge v%d into v%d r%d r%d dist %2.2g type %d (%s)\n",
    vertex->id, destination->id, getid_(ridge1), getid_(ridge2), distance, merge->mergetype, mergename));
} /* appendvertexmerge */


/*---------------------------------

  qh_basevertices(qh, samecycle )
    return temporary set of base vertices for samecycle
    samecycle is first facet in the cycle
    assumes apex is SETfirst_( samecycle->vertices )

  returns:
    vertices(settemp)
    all ->seen are cleared

  notes:
    uses qh_vertex_visit;

  design:
    for each facet in samecycle
      for each unseen vertex in facet->vertices
        append to result
*/
setT *qh_basevertices(qhT *qh, facetT *samecycle) {
  facetT *same;
  vertexT *apex, *vertex, **vertexp;
  setT *vertices= qh_settemp(qh, qh->TEMPsize);

  apex= SETfirstt_(samecycle->vertices, vertexT);
  apex->visitid= ++qh->vertex_visit;
  FORALLsame_cycle_(samecycle) {
    if (same->mergeridge)
      continue;
    FOREACHvertex_(same->vertices) {
      if (vertex->visitid != qh->vertex_visit) {
        qh_setappend(qh, &vertices, vertex);
        vertex->visitid= qh->vertex_visit;
        vertex->seen= False;
      }
    }
  }
  trace4((qh, qh->ferr, 4019, "qh_basevertices: found %d vertices\n",
         qh_setsize(qh, vertices)));
  return vertices;
} /* basevertices */

/*---------------------------------

  qh_check_dupridge(qh, facet1, dist1, facet2, dist2 )
    Check dupridge between facet1 and facet2 for wide merge
    dist1 is the maximum distance of facet1's vertices to facet2
    dist2 is the maximum distance of facet2's vertices to facet1

  returns
    Level 1 log of the dupridge with the minimum distance between vertices
    Throws error if the merge will increase the maximum facet width by qh_WIDEduplicate (100x)

  notes:
    only called from qh_forcedmerges
*/
void qh_check_dupridge(qhT *qh, facetT *facet1, realT dist1, facetT *facet2, realT dist2) {
  vertexT *vertex, **vertexp, *vertexA, **vertexAp;
  realT dist, innerplane, mergedist, outerplane, prevdist, ratio, vertexratio;
  realT minvertex= REALmax;

  mergedist= fmin_(dist1, dist2);
  qh_outerinner(qh, NULL, &outerplane, &innerplane);  /* ratio from qh_printsummary */
  FOREACHvertex_(facet1->vertices) {     /* The dupridge is between facet1 and facet2, so either facet can be tested */
    FOREACHvertexA_(facet1->vertices) {
      if (vertex > vertexA){   /* Test each pair once */
        dist= qh_pointdist(vertex->point, vertexA->point, qh->hull_dim);
        minimize_(minvertex, dist);
        /* Not quite correct.  A facet may have a dupridge and another pair of nearly adjacent vertices. */
      }
    }
  }
  prevdist= fmax_(outerplane, innerplane);
  maximize_(prevdist, qh->ONEmerge + qh->DISTround);
  maximize_(prevdist, qh->MINoutside + qh->DISTround);
  ratio= mergedist/prevdist;
  vertexratio= minvertex/prevdist;
  trace0((qh, qh->ferr, 16, "qh_check_dupridge: dupridge between f%d and f%d (vertex dist %2.2g), dist %2.2g, reverse dist %2.2g, ratio %2.2g while processing p%d\n",
        facet1->id, facet2->id, minvertex, dist1, dist2, ratio, qh->furthest_id));
  if (ratio > qh_WIDEduplicate) {
    qh_fprintf(qh, qh->ferr, 6271, "qhull topology error (qh_check_dupridge): wide merge (%.1fx wider) due to dupridge between f%d and f%d (vertex dist %2.2g), merge dist %2.2g, while processing p%d\n- Allow error with option 'Q12'\n",
      ratio, facet1->id, facet2->id, minvertex, mergedist, qh->furthest_id);
    if (vertexratio < qh_WIDEpinched)
      qh_fprintf(qh, qh->ferr, 8145, "- Experimental option merge-pinched-vertices ('Q14') may avoid this error.  It merges nearly adjacent vertices.\n");
    if (qh->DELAUNAY)
      qh_fprintf(qh, qh->ferr, 8145, "- A bounding box for the input sites may alleviate this error.\n");
    if (!qh->ALLOWwide)
      qh_errexit2(qh, qh_ERRwide, facet1, facet2);
  }
} /* check_dupridge */

/*---------------------------------

  qh_checkconnect(qh)
    check that new facets are connected
    new facets are on qh.newfacet_list

  notes:
    this is slow and it changes the order of the facets
    uses qh.visit_id

  design:
    move first new facet to end of qh.facet_list
    for all newly appended facets
      append unvisited neighbors to end of qh.facet_list
    for all new facets
      report error if unvisited
*/
void qh_checkconnect(qhT *qh /* qh.newfacet_list */) {
  facetT *facet, *newfacet, *errfacet= NULL, *neighbor, **neighborp;

  facet= qh->newfacet_list;
  qh_removefacet(qh, facet);
  qh_appendfacet(qh, facet);
  facet->visitid= ++qh->visit_id;
  FORALLfacet_(facet) {
    FOREACHneighbor_(facet) {
      if (neighbor->visitid != qh->visit_id) {
        qh_removefacet(qh, neighbor);
        qh_appendfacet(qh, neighbor);
        neighbor->visitid= qh->visit_id;
      }
    }
  }
  FORALLnew_facets {
    if (newfacet->visitid == qh->visit_id)
      break;
    qh_fprintf(qh, qh->ferr, 6094, "qhull internal error (qh_checkconnect): f%d is not attached to the new facets\n",
         newfacet->id);
    errfacet= newfacet;
  }
  if (errfacet)
    qh_errexit(qh, qh_ERRqhull, errfacet, NULL);
} /* checkconnect */

/*---------------------------------

  qh_checkdelfacet(qh, facet, mergeset )
    check that mergeset does not reference facet

*/
void qh_checkdelfacet(qhT *qh, facetT *facet, setT *mergeset) {
  mergeT *merge, **mergep;

  FOREACHmerge_(mergeset) {
    if (merge->facet1 == facet || merge->facet2 == facet) {
      qh_fprintf(qh, qh->ferr, 6390, "qhull internal error (qh_checkdelfacet): cannot delete f%d.  It is referenced by merge f%d f%d mergetype %d\n",
        facet->id, merge->facet1->id, getid_(merge->facet2), merge->mergetype);
      qh_errexit2(qh, qh_ERRqhull, merge->facet1, merge->facet2);
    }
  }
} /* checkdelfacet */

/*---------------------------------

  qh_checkdelridge(qh)
    check that qh_delridge_merge is not needed for deleted ridges

    notes:
      called from qh_mergecycle, qh_makenewfacets, qh_attachnewfacets
      errors if qh.vertex_mergeset is non-empty
      errors if any visible or new facet has a ridge with r.nonconvex set
      assumes that vertex.delfacet is not needed
*/
void qh_checkdelridge(qhT *qh /* qh.visible_facets, vertex_mergeset */) {
  facetT *newfacet, *visible;
  ridgeT *ridge, **ridgep;

  if (!SETempty_(qh->vertex_mergeset)) {
    qh_fprintf(qh, qh->ferr, 6382, "qhull internal error (qh_checkdelridge): expecting empty qh.vertex_mergeset in order to avoid calling qh_delridge_merge.  Got %d merges\n", qh_setsize(qh, qh->vertex_mergeset));
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }

  FORALLnew_facets {
    FOREACHridge_(newfacet->ridges) {
      if (ridge->nonconvex) {
        qh_fprintf(qh, qh->ferr, 6313, "qhull internal error (qh_checkdelridge): unexpected 'nonconvex' flag for ridge r%d in newfacet f%d.  Otherwise need to call qh_delridge_merge\n",
           ridge->id, newfacet->id);
        qh_errexit(qh, qh_ERRqhull, newfacet, ridge);
      }
    }
  }

  FORALLvisible_facets {
    FOREACHridge_(visible->ridges) {
      if (ridge->nonconvex) {
        qh_fprintf(qh, qh->ferr, 6385, "qhull internal error (qh_checkdelridge): unexpected 'nonconvex' flag for ridge r%d in visible facet f%d.  Otherwise need to call qh_delridge_merge\n",
          ridge->id, visible->id);
        qh_errexit(qh, qh_ERRqhull, visible, ridge);
      }
    }
  }
} /* checkdelridge */


/*---------------------------------

  qh_checkzero(qh, testall )
    check that facets are clearly convex for qh.DISTround with qh.MERGEexact

    if testall,
      test all facets for qh.MERGEexact post-merging
    else
      test qh.newfacet_list

    if qh.MERGEexact,
      allows coplanar ridges
      skips convexity test while qh.ZEROall_ok

  returns:
    True if all facets !flipped, !dupridge, normal
         if all horizon facets are simplicial
         if all vertices are clearly below neighbor
         if all opposite vertices of horizon are below
    clears qh.ZEROall_ok if any problems or coplanar facets

  notes:
    called by qh_premerge (qh.CHECKzero, 'C-0') and qh_qhull ('Qx')
    uses qh.vertex_visit
    horizon facets may define multiple new facets

  design:
    for all facets in qh.newfacet_list or qh.facet_list
      check for flagged faults (flipped, etc.)
    for all facets in qh.newfacet_list or qh.facet_list
      for each neighbor of facet
        skip horizon facets for qh.newfacet_list
        test the opposite vertex
      if qh.newfacet_list
        test the other vertices in the facet's horizon facet
*/
boolT qh_checkzero(qhT *qh, boolT testall) {
  facetT *facet, *neighbor;
  facetT *horizon, *facetlist;
  int neighbor_i, neighbor_n;
  vertexT *vertex, **vertexp;
  realT dist;

  if (testall)
    facetlist= qh->facet_list;
  else {
    facetlist= qh->newfacet_list;
    FORALLfacet_(facetlist) {
      horizon= SETfirstt_(facet->neighbors, facetT);
      if (!horizon->simplicial)
        goto LABELproblem;
      if (facet->flipped || facet->dupridge || !facet->normal)
        goto LABELproblem;
    }
    if (qh->MERGEexact && qh->ZEROall_ok) {
      trace2((qh, qh->ferr, 2011, "qh_checkzero: skip convexity check until first pre-merge\n"));
      return True;
    }
  }
  FORALLfacet_(facetlist) {
    qh->vertex_visit++;
    horizon= NULL;
    FOREACHneighbor_i_(qh, facet) {
      if (!neighbor_i && !testall) {
        horizon= neighbor;
        continue; /* horizon facet tested in qh_findhorizon */
      }
      vertex= SETelemt_(facet->vertices, neighbor_i, vertexT);
      vertex->visitid= qh->vertex_visit;
      zzinc_(Zdistzero);
      qh_distplane(qh, vertex->point, neighbor, &dist);
      if (dist >= -2 * qh->DISTround) {  /* need 2x for qh_distround and 'Rn' for qh_checkconvex, same as qh.premerge_centrum */
        qh->ZEROall_ok= False;
        if (!qh->MERGEexact || testall || dist > qh->DISTround)
          goto LABELnonconvex;
      }
    }
    if (!testall && horizon) {
      FOREACHvertex_(horizon->vertices) {
        if (vertex->visitid != qh->vertex_visit) {
          zzinc_(Zdistzero);
          qh_distplane(qh, vertex->point, facet, &dist);
          if (dist >= -2 * qh->DISTround) {
            qh->ZEROall_ok= False;
            if (!qh->MERGEexact || dist > qh->DISTround)
              goto LABELnonconvexhorizon;
          }
          break;
        }
      }
    }
  }
  trace2((qh, qh->ferr, 2012, "qh_checkzero: testall %d, facets are %s\n", testall,
        (qh->MERGEexact && !testall) ?
           "not concave, flipped, or dupridge" : "clearly convex"));
  return True;

 LABELproblem:
  qh->ZEROall_ok= False;
  trace2((qh, qh->ferr, 2013, "qh_checkzero: qh_premerge is needed.  New facet f%d or its horizon f%d is non-simplicial, flipped, dupridge, or mergehorizon\n",
       facet->id, horizon->id));
  return False;

 LABELnonconvex:
  trace2((qh, qh->ferr, 2014, "qh_checkzero: facet f%d and f%d are not clearly convex.  v%d dist %.2g\n",
         facet->id, neighbor->id, vertex->id, dist));
  return False;

 LABELnonconvexhorizon:
  trace2((qh, qh->ferr, 2060, "qh_checkzero: facet f%d and horizon f%d are not clearly convex.  v%d dist %.2g\n",
      facet->id, horizon->id, vertex->id, dist));
  return False;
} /* checkzero */

/*---------------------------------

  qh_compare_anglemerge( mergeA, mergeB )
    used by qsort() to order qh.facet_mergeset by mergetype and angle (qh.ANGLEmerge, 'Q1')
    lower numbered mergetypes done first (MRGcoplanar before MRGconcave)

  notes:
    qh_all_merges processes qh.facet_mergeset by qh_setdellast
    [mar'19] evaluated various options with eg/q_benchmark and merging of pinched vertices (Q14)
*/
int qh_compare_anglemerge(const void *p1, const void *p2) {
  const mergeT *a= *((mergeT *const*)p1), *b= *((mergeT *const*)p2);

  if (a->mergetype != b->mergetype)
    return (a->mergetype < b->mergetype ? 1 : -1); /* select MRGcoplanar (1) before MRGconcave (3) */
  else
    return (a->angle > b->angle ? 1 : -1);         /* select coplanar merge (1.0) before sharp merge (-0.5) */
} /* compare_anglemerge */

/*---------------------------------

  qh_compare_facetmerge( mergeA, mergeB )
    used by qsort() to order merges by mergetype, first merge, first
    lower numbered mergetypes done first (MRGcoplanar before MRGconcave)
    if same merge type, flat merges are first

  notes:
    qh_all_merges processes qh.facet_mergeset by qh_setdellast
    [mar'19] evaluated various options with eg/q_benchmark and merging of pinched vertices (Q14)
*/
int qh_compare_facetmerge(const void *p1, const void *p2) {
  const mergeT *a= *((mergeT *const*)p1), *b= *((mergeT *const*)p2);

  if (a->mergetype != b->mergetype)
    return (a->mergetype < b->mergetype ? 1 : -1); /* select MRGcoplanar (1) before MRGconcave (3) */
  else if (a->mergetype == MRGanglecoplanar)
    return (a->angle > b->angle ? 1 : -1);         /* if MRGanglecoplanar, select coplanar merge (1.0) before sharp merge (-0.5) */
  else
    return (a->distance < b->distance ? 1 : -1);   /* select flat (0.0) merge before wide (1e-10) merge */
} /* compare_facetmerge */

/*---------------------------------

  qh_comparevisit( vertexA, vertexB )
    used by qsort() to order vertices by their visitid

  notes:
    only called by qh_find_newvertex
*/
int qh_comparevisit(const void *p1, const void *p2) {
  const vertexT *a= *((vertexT *const*)p1), *b= *((vertexT *const*)p2);

  if (a->visitid > b->visitid)
    return 1;
  return -1;
} /* comparevisit */

/*---------------------------------

  qh_copynonconvex(qh, atridge )
    set non-convex flag on other ridges (if any) between same neighbors

  notes:
    may be faster if use smaller ridge set

  design:
    for each ridge of atridge's top facet
      if ridge shares the same neighbor
        set nonconvex flag
*/
void qh_copynonconvex(qhT *qh, ridgeT *atridge) {
  facetT *facet, *otherfacet;
  ridgeT *ridge, **ridgep;

  facet= atridge->top;
  otherfacet= atridge->bottom;
  atridge->nonconvex= False;
  FOREACHridge_(facet->ridges) {
    if (otherfacet == ridge->top || otherfacet == ridge->bottom) {
      if (ridge != atridge) {
        ridge->nonconvex= True;
        trace4((qh, qh->ferr, 4020, "qh_copynonconvex: moved nonconvex flag from r%d to r%d between f%d and f%d\n",
                atridge->id, ridge->id, facet->id, otherfacet->id));
        break;
      }
    }
  }
} /* copynonconvex */

/*---------------------------------

  qh_degen_redundant_facet(qh, facet )
    check for a degenerate (too few neighbors) or redundant (subset of vertices) facet

  notes:
    called at end of qh_mergefacet, qh_renamevertex, and qh_reducevertices
    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_test_redundant_neighbors, qh_maydropneighbor

  design:
    test for redundant neighbor
    test for degenerate facet
*/
void qh_degen_redundant_facet(qhT *qh, facetT *facet) {
  vertexT *vertex, **vertexp;
  facetT *neighbor, **neighborp;

  trace3((qh, qh->ferr, 3028, "qh_degen_redundant_facet: test facet f%d for degen/redundant\n",
          facet->id));
  if (facet->flipped) {
    trace2((qh, qh->ferr, 3074, "qh_degen_redundant_facet: f%d is flipped, will merge later\n", facet->id));
    return;
  }
  FOREACHneighbor_(facet) {
    if (neighbor->flipped) /* disallow merge of non-flipped into flipped, neighbor will be merged later */
      continue;
    if (neighbor->visible) {
      qh_fprintf(qh, qh->ferr, 6357, "qhull internal error (qh_degen_redundant_facet): facet f%d has deleted neighbor f%d (qh.visible_list)\n",
        facet->id, neighbor->id);
      qh_errexit2(qh, qh_ERRqhull, facet, neighbor);
    }
    qh->vertex_visit++;
    FOREACHvertex_(neighbor->vertices)
      vertex->visitid= qh->vertex_visit;
    FOREACHvertex_(facet->vertices) {
      if (vertex->visitid != qh->vertex_visit)
        break;
    }
    if (!vertex) {
      trace2((qh, qh->ferr, 2015, "qh_degen_redundant_facet: f%d is contained in f%d.  merge\n", facet->id, neighbor->id));
      qh_appendmergeset(qh, facet, neighbor, MRGredundant, 0.0, 1.0);
      return;
    }
  }
  if (qh_setsize(qh, facet->neighbors) < qh->hull_dim) {
    qh_appendmergeset(qh, facet, facet, MRGdegen, 0.0, 1.0);
    trace2((qh, qh->ferr, 2016, "qh_degen_redundant_facet: f%d is degenerate.\n", facet->id));
  }
} /* degen_redundant_facet */


/*---------------------------------

  qh_delridge_merge(qh, ridge )
    delete ridge due to a merge

  notes:
    only called by merge_r.c (qh_mergeridges, qh_renameridgevertex)
    ridges also freed in qh_freeqhull and qh_mergecycle_ridges

  design:
    if needed, moves ridge.nonconvex to another ridge
    sets vertex.delridge for qh_reducevertices
    deletes ridge from qh.vertex_mergeset
    deletes ridge from its neighboring facets
    frees up its memory
*/
void qh_delridge_merge(qhT *qh, ridgeT *ridge) {
  vertexT *vertex, **vertexp;
  mergeT *merge;
  int merge_i, merge_n;

  trace3((qh, qh->ferr, 3036, "qh_delridge_merge: delete ridge r%d between f%d and f%d\n",
    ridge->id, ridge->top->id, ridge->bottom->id));
  if (ridge->nonconvex)
    qh_copynonconvex(qh, ridge);
  FOREACHvertex_(ridge->vertices)
    vertex->delridge= True;
  FOREACHmerge_i_(qh, qh->vertex_mergeset) {
    if (merge->ridge1 == ridge || merge->ridge2 == ridge) {
      trace3((qh, qh->ferr, 3029, "qh_delridge_merge: drop merge of v%d into v%d (dist %2.2g r%d r%d) due to deleted, duplicated ridge r%d\n",
        merge->vertex1->id, merge->vertex2->id, merge->distance, merge->ridge1->id, merge->ridge2->id, ridge->id));
      if (merge->ridge1 == ridge)
        merge->ridge2->mergevertex= False;
      else
        merge->ridge1->mergevertex= False;
      qh_setdelnth(qh, qh->vertex_mergeset, merge_i);
      merge_i--; merge_n--; /* next merge after deleted */
    }
  }
  qh_setdel(ridge->top->ridges, ridge);
  qh_setdel(ridge->bottom->ridges, ridge);
  qh_delridge(qh, ridge);
} /* delridge_merge */


/*---------------------------------

  qh_drop_mergevertex(qh, merge )

  clear mergevertex flags for ridges of a vertex merge
*/
void qh_drop_mergevertex(qhT *qh, mergeT *merge)
{
  if (merge->mergetype == MRGvertices) {
    merge->ridge1->mergevertex= False;
    merge->ridge1->mergevertex2= True;
    merge->ridge2->mergevertex= False;
    merge->ridge2->mergevertex2= True;
    trace3((qh, qh->ferr, 3032, "qh_drop_mergevertex: unset mergevertex for r%d and r%d due to dropped vertex merge v%d to v%d.  Sets mergevertex2\n",
      merge->ridge1->id, merge->ridge2->id, merge->vertex1->id, merge->vertex2->id));
  }
} /* drop_mergevertex */

/*---------------------------------

  qh_find_newvertex(qh, oldvertex, vertices, ridges )
    locate new vertex for renaming old vertex
    vertices is a set of possible new vertices
      vertices sorted by number of deleted ridges

  returns:
    newvertex or NULL
      each ridge includes both newvertex and oldvertex
    vertices without oldvertex sorted by number of deleted ridges
    qh.vertex_visit updated
    sets v.seen

  notes:
    called by qh_redundant_vertex due to vertex->delridge and qh_rename_sharedvertex
    sets vertex->visitid to 0..setsize() for vertices
    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 ridges
    remove unvisited vertices
    set qh.vertex_visit above all possible values
    sort vertices by number of ridges (minimize ridges that need renaming
    add each ridge to qh.hash_table
    for each vertex in vertices
      find the first vertex that would not cause a duplicate ridge after a rename
*/
vertexT *qh_find_newvertex(qhT *qh, vertexT *oldvertex, setT *vertices, setT *ridges) {
  vertexT *vertex, **vertexp;
  setT *newridges;
  ridgeT *ridge, **ridgep;
  int size, hashsize;
  int hash;
  unsigned int maxvisit;

#ifndef qh_NOtrace
  if (qh->IStracing >= 4) {
    qh_fprintf(qh, qh->ferr, 8063, "qh_find_newvertex: find new vertex for v%d from ",
             oldvertex->id);
    FOREACHvertex_(vertices)
      qh_fprintf(qh, qh->ferr, 8064, "v%d ", vertex->id);
    FOREACHridge_(ridges)
      qh_fprintf(qh, qh->ferr, 8065, "r%d ", ridge->id);
    qh_fprintf(qh, qh->ferr, 8066, "\n");
  }
#endif
  FOREACHridge_(ridges) {
    FOREACHvertex_(ridge->vertices)
      vertex->seen= False;
  }
  FOREACHvertex_(vertices) {
    vertex->visitid= 0;  /* v.visitid will be number of ridges */
    vertex->seen= True;
  }
  FOREACHridge_(ridges) {
    FOREACHvertex_(ridge->vertices) {
      if (vertex->seen)
        vertex->visitid++;
    }
  }
  FOREACHvertex_(vertices) {
    if (!vertex->visitid) {
      qh_setdelnth(qh, vertices, SETindex_(vertices,vertex));
      vertexp--; /* repeat since deleted this vertex */
    }
  }
  maxvisit= (unsigned int)qh_setsize(qh, ridges);
  maximize_(qh->vertex_visit, maxvisit);
  if (!qh_setsize(qh, vertices)) {
    trace4((qh, qh->ferr, 4023, "qh_find_newvertex: vertices not in ridges for v%d\n",
            oldvertex->id));
    return NULL;
  }
  qsort(SETaddr_(vertices, vertexT), (size_t)qh_setsize(qh, vertices),
                sizeof(vertexT *), qh_comparevisit);
  /* can now use qh->vertex_visit */
  if (qh->PRINTstatistics) {
    size= qh_setsize(qh, vertices);
    zinc_(Zintersect);
    zadd_(Zintersecttot, size);
    zmax_(Zintersectmax, size);
  }
  hashsize= qh_newhashtable(qh, qh_setsize(qh, ridges));
  FOREACHridge_(ridges)
    qh_hashridge(qh, qh->hash_table, hashsize, ridge, oldvertex);
  FOREACHvertex_(vertices) {
    newridges= qh_vertexridges(qh, vertex, !qh_ALL);
    FOREACHridge_(newridges) {
      if (qh_hashridge_find(qh, qh->hash_table, hashsize, ridge, vertex, oldvertex, &hash)) {
        zinc_(Zvertexridge);
        break;
      }
    }
    qh_settempfree(qh, &newridges);
    if (!ridge)
      break;  /* found a rename */
  }
  if (vertex) {
    /* counted in qh_renamevertex */
    trace2((qh, qh->ferr, 2020, "qh_find_newvertex: found v%d for old v%d from %d vertices and %d ridges.\n",
      vertex->id, oldvertex->id, qh_setsize(qh, vertices), qh_setsize(qh, ridges)));
  }else {
    zinc_(Zfindfail);
    trace0((qh, qh->ferr, 14, "qh_find_newvertex: no vertex for renaming v%d (all duplicated ridges) during p%d\n",
      oldvertex->id, qh->furthest_id));
  }
  qh_setfree(qh, &qh->hash_table);
  return vertex;
} /* find_newvertex */

/*---------------------------------

  qh_findbest_pinchedvertex(qh, merge, apex, nearestp, distp )
    Determine the best pinched vertex to rename as its nearest neighboring vertex
    Renaming will remove a duplicate MRGdupridge in newfacet_list

  returns:
    pinched vertex (either apex or subridge), nearest vertex (subridge or neighbor vertex), and the distance between them

  notes:
    only called by qh_getpinchedmerges
    assumes qh.VERTEXneighbors
    see qh_findbest_ridgevertex

  design:
    if the facets have the same vertices
      return the nearest vertex pair
    else
      the subridge is the intersection of the two new facets minus the apex
      the subridge consists of qh.hull_dim-2 horizon vertices
      the subridge is also a matched ridge for the new facets (its duplicate)
      determine the nearest vertex to the apex
      determine the nearest pair of subridge vertices
      for each vertex in the subridge
        determine the nearest neighbor vertex (not in the subridge)
*/
vertexT *qh_findbest_pinchedvertex(qhT *qh, mergeT *merge, vertexT *apex, vertexT **nearestp, coordT *distp /* qh.newfacet_list */) {
  vertexT *vertex, **vertexp, *vertexA, **vertexAp;
  vertexT *bestvertex= NULL, *bestpinched= NULL;
  setT *subridge, *maybepinched;
  coordT dist, bestdist= REALmax;
  coordT pincheddist= (qh->ONEmerge+qh->DISTround)*qh_RATIOpinchedsubridge;

  if (!merge->facet1->simplicial || !merge->facet2->simplicial) {
    qh_fprintf(qh, qh->ferr, 6351, "qhull internal error (qh_findbest_pinchedvertex): expecting merge of adjacent, simplicial new facets.  f%d or f%d is not simplicial\n",
      merge->facet1->id, merge->facet2->id);
    qh_errexit2(qh, qh_ERRqhull, merge->facet1, merge->facet2);
  }
  subridge= qh_vertexintersect_new(qh, merge->facet1->vertices, merge->facet2->vertices); /* new setT.  No error_exit() */
  if (qh_setsize(qh, subridge) == qh->hull_dim) { /* duplicate vertices */
    bestdist= qh_vertex_bestdist2(qh, subridge, &bestvertex, &bestpinched);
    if(bestvertex == apex) {
      bestvertex= bestpinched;
      bestpinched= apex;
    }
  }else {
    qh_setdel(subridge, apex);
    if (qh_setsize(qh, subridge) != qh->hull_dim - 2) {
      qh_fprintf(qh, qh->ferr, 6409, "qhull internal error (qh_findbest_pinchedvertex): expecting subridge of qh.hull_dim-2 vertices for the intersection of new facets f%d and f%d minus their apex.  Got %d vertices\n",
          merge->facet1->id, merge->facet2->id, qh_setsize(qh, subridge));
      qh_errexit2(qh, qh_ERRqhull, merge->facet1, merge->facet2);
    }
    FOREACHvertex_(subridge) {
      dist= qh_pointdist(vertex->point, apex->point, qh->hull_dim);
      if (dist < bestdist) {
        bestpinched= apex;
        bestvertex= vertex;
        bestdist= dist;
      }
    }
    if (bestdist > pincheddist) {
      FOREACHvertex_(subridge) {
        FOREACHvertexA_(subridge) {
          if (vertexA->id > vertex->id) { /* once per vertex pair, do not compare addresses */
            dist= qh_pointdist(vertexA->point, vertex->point, qh->hull_dim);
            if (dist < bestdist) {
              bestpinched= vertexA;
              bestvertex= vertex;
              bestdist= dist;
            }
          }
        }
      }
    }
    if (bestdist > pincheddist) {
      FOREACHvertexA_(subridge) {
        maybepinched= qh_neighbor_vertices(qh, vertexA, subridge); /* subridge and apex tested above */
        FOREACHvertex_(maybepinched) {
          dist= qh_pointdist(vertex->point, vertexA->point, qh->hull_dim);
          if (dist < bestdist) {
            bestvertex= vertex;
            bestpinched= vertexA;
            bestdist= dist;
          }
        }
        qh_settempfree(qh, &maybepinched);
      }
    }
  }
  *distp= bestdist;
  qh_setfree(qh, &subridge); /* qh_err_exit not called since allocated */
  if (!bestvertex) {  /* should never happen if qh.hull_dim > 2 */
    qh_fprintf(qh, qh->ferr, 6274, "qhull internal error (qh_findbest_pinchedvertex): did not find best vertex for subridge of dupridge between f%d and f%d, while processing p%d\n", merge->facet1->id, merge->facet2->id, qh->furthest_id);
    qh_errexit2(qh, qh_ERRqhull, merge->facet1, merge->facet2);
  }
  *nearestp= bestvertex;
  trace2((qh, qh->ferr, 2061, "qh_findbest_pinchedvertex: best pinched p%d(v%d) and vertex p%d(v%d) are closest (%2.2g) for duplicate subridge between f%d and f%d\n",
      qh_pointid(qh, bestpinched->point), bestpinched->id, qh_pointid(qh, bestvertex->point), bestvertex->id, bestdist, merge->facet1->id, merge->facet2->id));
  return bestpinched;
} /* findbest_pinchedvertex */

/*---------------------------------

  qh_findbest_ridgevertex(qh, ridge, pinchedp, distp )
    Determine the best vertex/pinched-vertex to merge for ridges with the same vertices

  returns:
    vertex, pinched vertex, and the distance between them

  notes:
    assumes qh.hull_dim>=3
    see qh_findbest_pinchedvertex

*/
vertexT *qh_findbest_ridgevertex(qhT *qh, ridgeT *ridge, vertexT **pinchedp, coordT *distp) {
  vertexT *bestvertex;

  *distp= qh_vertex_bestdist2(qh, ridge->vertices, &bestvertex, pinchedp);
  trace4((qh, qh->ferr, 4069, "qh_findbest_ridgevertex: best pinched p%d(v%d) and vertex p%d(v%d) are closest (%2.2g) for duplicated ridge r%d (same vertices) between f%d and f%d\n",
      qh_pointid(qh, (*pinchedp)->point), (*pinchedp)->id, qh_pointid(qh, bestvertex->point), bestvertex->id, *distp, ridge->id, ridge->top->id, ridge->bottom->id));
  return bestvertex;
} /* findbest_ridgevertex */

/*---------------------------------

  qh_findbest_test(qh, testcentrum, facet, neighbor, &bestfacet, &dist, &mindist, &maxdist )
    test neighbor of facet for qh_findbestneighbor()
    if testcentrum,
      tests centrum (assumes it is defined)
    else
      tests vertices
    initially *bestfacet==NULL and *dist==REALmax

  returns:
    if a better facet (i.e., vertices/centrum of facet closer to neighbor)
      updates bestfacet, dist, mindist, and maxdist

  notes:
    called by qh_findbestneighbor
    ignores pairs of flipped facets, unless that's all there is
*/
void qh_findbest_test(qhT *qh, boolT testcentrum, facetT *facet, facetT *neighbor,
      facetT **bestfacet, realT *distp, realT *mindistp, realT *maxdistp) {
  realT dist, mindist, maxdist;

  if (facet->flipped && neighbor->flipped && *bestfacet && !(*bestfacet)->flipped)
    return; /* do not merge flipped into flipped facets */
  if (testcentrum) {
    zzinc_(Zbestdist);
    qh_distplane(qh, facet->center, neighbor, &dist);
    dist *= qh->hull_dim; /* estimate furthest vertex */
    if (dist < 0) {
      maxdist= 0;
      mindist= dist;
      dist= -dist;
    }else {
      mindist= 0;
      maxdist= dist;
    }
  }else
    dist= qh_getdistance(qh, facet, neighbor, &mindist, &maxdist);
  if (dist < *distp) {
    *bestfacet= neighbor;
    *mindistp= mindist;
    *maxdistp= maxdist;
    *distp= dist;
  }
} /* findbest_test */

/*---------------------------------

  qh_findbestneighbor(qh, facet, dist, mindist, maxdist )
    finds best neighbor (least dist) of a facet for merging

  returns:
    returns min and max distances and their max absolute value

  notes:
    error if qh_ASvoronoi
    avoids merging old into new
    assumes ridge->nonconvex only set on one ridge between a pair of facets
    could use an early out predicate but not worth it

  design:
    if a large facet
      will test centrum
    else
      will test vertices
    if a large facet
      test nonconvex neighbors for best merge
    else
      test all neighbors for the best merge
    if testing centrum
      get distance information
*/
facetT *qh_findbestneighbor(qhT *qh, facetT *facet, realT *distp, realT *mindistp, realT *maxdistp) {
  facetT *neighbor, **neighborp, *bestfacet= NULL;
  ridgeT *ridge, **ridgep;
  boolT nonconvex= True, testcentrum= False;
  int size= qh_setsize(qh, facet->vertices);

  if(qh->CENTERtype==qh_ASvoronoi){
    qh_fprintf(qh, qh->ferr, 6272, "qhull internal error: cannot call qh_findbestneighor for f%d while qh.CENTERtype is qh_ASvoronoi\n", facet->id);
    qh_errexit(qh, qh_ERRqhull, facet, NULL);
  }
  *distp= REALmax;
  if (size > qh_BESTcentrum2 * qh->hull_dim + qh_BESTcentrum) {
    testcentrum= True;
    zinc_(Zbestcentrum);
    if (!facet->center)
       facet->center= qh_getcentrum(qh, facet);
  }
  if (size > qh->hull_dim + qh_BESTnonconvex) {
    FOREACHridge_(facet->ridges) {
      if (ridge->nonconvex) {
        neighbor= otherfacet_(ridge, facet);
        qh_findbest_test(qh, testcentrum, facet, neighbor,
                          &bestfacet, distp, mindistp, maxdistp);
      }
    }
  }
  if (!bestfacet) {
    nonconvex= False;
    FOREACHneighbor_(facet)
      qh_findbest_test(qh, testcentrum, facet, neighbor,
                        &bestfacet, distp, mindistp, maxdistp);
  }
  if (!bestfacet) {
    qh_fprintf(qh, qh->ferr, 6095, "qhull internal error (qh_findbestneighbor): no neighbors for f%d\n", facet->id);
    qh_errexit(qh, qh_ERRqhull, facet, NULL);
  }
  if (testcentrum)
    qh_getdistance(qh, facet, bestfacet, mindistp, maxdistp);
  trace3((qh, qh->ferr, 3002, "qh_findbestneighbor: f%d is best neighbor for f%d testcentrum? %d nonconvex? %d dist %2.2g min %2.2g max %2.2g\n",
     bestfacet->id, facet->id, testcentrum, nonconvex, *distp, *mindistp, *maxdistp));
  return(bestfacet);
} /* findbestneighbor */


/*---------------------------------

  qh_flippedmerges(qh, facetlist, wasmerge )
    merge flipped facets into best neighbor
    assumes qh.facet_mergeset at top of temporary stack

  returns:
    no flipped facets on facetlist
    sets wasmerge if merge occurred
    degen/redundant merges passed through

  notes:
    othermerges not needed since qh.facet_mergeset is empty before & after
      keep it in case of change

  design:
    append flipped facets to qh.facetmergeset
    for each flipped merge
      find best neighbor
      merge facet into neighbor
      merge degenerate and redundant facets
    remove flipped merges from qh.facet_mergeset
*/
void qh_flippedmerges(qhT *qh, facetT *facetlist, boolT *wasmerge) {
  facetT *facet, *neighbor, *facet1;
  realT dist, mindist, maxdist;
  mergeT *merge, **mergep;
  setT *othermerges;
  int nummerge= 0, numdegen= 0;

  trace4((qh, qh->ferr, 4024, "qh_flippedmerges: begin\n"));
  FORALLfacet_(facetlist) {
    if (facet->flipped && !facet->visible)
      qh_appendmergeset(qh, facet, facet, MRGflip, 0.0, 1.0);
  }
  othermerges= qh_settemppop(qh);
  if(othermerges != qh->facet_mergeset) {
    qh_fprintf(qh, qh->ferr, 6392, "qhull internal error (qh_flippedmerges): facet_mergeset (%d merges) not at top of tempstack (%d merges)\n",
        qh_setsize(qh, qh->facet_mergeset), qh_setsize(qh, othermerges));
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  qh->facet_mergeset= qh_settemp(qh, qh->TEMPsize);
  qh_settemppush(qh, othermerges);
  FOREACHmerge_(othermerges) {
    facet1= merge->facet1;
    if (merge->mergetype != MRGflip || facet1->visible)
      continue;
    if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
      qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
    neighbor= qh_findbestneighbor(qh, facet1, &dist, &mindist, &maxdist);
    trace0((qh, qh->ferr, 15, "qh_flippedmerges: merge flipped f%d into f%d dist %2.2g during p%d\n",
      facet1->id, neighbor->id, dist, qh->furthest_id));
    qh_mergefacet(qh, facet1, neighbor, merge->mergetype, &mindist, &maxdist, !qh_MERGEapex);
    nummerge++;
    if (qh->PRINTstatistics) {
      zinc_(Zflipped);
      wadd_(Wflippedtot, dist);
      wmax_(Wflippedmax, dist);
    }
  }
  FOREACHmerge_(othermerges) {
    if (merge->facet1->visible || merge->facet2->visible)
      qh_memfree(qh, merge, (int)sizeof(mergeT)); /* invalidates merge and othermerges */
    else
      qh_setappend(qh, &qh->facet_mergeset, merge);
  }
  qh_settempfree(qh, &othermerges);
  numdegen += qh_merge_degenredundant(qh); /* somewhat better here than after each flipped merge -- qtest.sh 10 '500 C1,2e-13 D4' 'd Qbb' */
  if (nummerge)
    *wasmerge= True;
  trace1((qh, qh->ferr, 1010, "qh_flippedmerges: merged %d flipped and %d degenredundant facets into a good neighbor\n",
    nummerge, numdegen));
} /* flippedmerges */


/*---------------------------------

  qh_forcedmerges(qh, wasmerge )
    merge dupridges
    calls qh_check_dupridge to report an error on wide merges
    assumes qh_settemppop is qh.facet_mergeset

  returns:
    removes all dupridges 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:
    called by qh_premerge
    dupridges 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 dupridge
      find current facets by chasing f.replace links
      check for wide merge due to dupridge
      determine best direction for facet
      merge one facet into the other
      remove dupridges from qh.facet_mergeset
*/
void qh_forcedmerges(qhT *qh, boolT *wasmerge) {
  facetT *facet1, *facet2, *merging, *merged, *newfacet;
  mergeT *merge, **mergep;
  realT dist, mindist, maxdist, dist2, mindist2, maxdist2;
  setT *othermerges;
  int nummerge=0, numflip=0, numdegen= 0;
  boolT wasdupridge= False;

  if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
    qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
  trace3((qh, qh->ferr, 3054, "qh_forcedmerges: merge dupridges\n"));
  othermerges= qh_settemppop(qh); /* was facet_mergeset */
  if (qh->facet_mergeset != othermerges ) {
      qh_fprintf(qh, qh->ferr, 6279, "qhull internal error (qh_forcedmerges): qh_settemppop (size %d) is not qh->facet_mergeset (size %d)\n",
          qh_setsize(qh, othermerges), qh_setsize(qh, qh->facet_mergeset));
      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  qh->facet_mergeset= qh_settemp(qh, qh->TEMPsize);
  qh_settemppush(qh, othermerges);
  FOREACHmerge_(othermerges) {
    if (merge->mergetype != MRGdupridge)
        continue;
    wasdupridge= True;
    if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
        qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
    facet1= qh_getreplacement(qh, merge->facet1);  /* must exist, no qh_merge_degenredunant */
    facet2= qh_getreplacement(qh, merge->facet2);  /* previously merged facet, if any */
    if (facet1 == facet2)
      continue;
    if (!qh_setin(facet2->neighbors, facet1)) {
      qh_fprintf(qh, qh->ferr, 6096, "qhull internal error (qh_forcedmerges): f%d and f%d had a dupridge but as f%d and f%d they are no longer neighbors\n",
               merge->facet1->id, merge->facet2->id, facet1->id, facet2->id);
      qh_errexit2(qh, qh_ERRqhull, facet1, facet2);
    }
    dist= qh_getdistance(qh, facet1, facet2, &mindist, &maxdist);
    dist2= qh_getdistance(qh, facet2, facet1, &mindist2, &maxdist2);
    qh_check_dupridge(qh, facet1, dist, facet2, dist2);
    if (dist < dist2) {
      if (facet2->flipped && !facet1->flipped && dist2 < qh_WIDEdupridge*(qh->ONEmerge+qh->DISTround)) { /* prefer merge of flipped facet */
        merging= facet2;
        merged= facet1;
        dist= dist2;
        mindist= mindist2;
        maxdist= maxdist2;
      }else {
        merging= facet1;
        merged= facet2;
      }
    }else {
      if (facet1->flipped && !facet2->flipped && dist < qh_WIDEdupridge*(qh->ONEmerge+qh->DISTround)) { /* prefer merge of flipped facet */
        merging= facet1;
        merged= facet2;
      }else {
        merging= facet2;
        merged= facet1;
        dist= dist2;
        mindist= mindist2;
        maxdist= maxdist2;
      }
    }
    qh_mergefacet(qh, merging, merged, merge->mergetype, &mindist, &maxdist, !qh_MERGEapex);
    numdegen += qh_merge_degenredundant(qh); /* better here than at end -- qtest.sh 10 '500 C1,2e-13 D4' 'd Qbb' */
    if (facet1->flipped) {
      zinc_(Zmergeflipdup);
      numflip++;
    }else
      nummerge++;
    if (qh->PRINTstatistics) {
      zinc_(Zduplicate);
      wadd_(Wduplicatetot, dist);
      wmax_(Wduplicatemax, dist);
    }
  }
  FOREACHmerge_(othermerges) {
    if (merge->mergetype == MRGdupridge)
      qh_memfree(qh, merge, (int)sizeof(mergeT)); /* invalidates merge and othermerges */
    else
      qh_setappend(qh, &qh->facet_mergeset, merge);
  }
  qh_settempfree(qh, &othermerges);
  if (wasdupridge) {
    FORALLnew_facets {
      if (newfacet->dupridge) {
        newfacet->dupridge= False;
        newfacet->mergeridge= False;
        newfacet->mergeridge2= False;
        if (qh_setsize(qh, newfacet->neighbors) < qh->hull_dim) { /* not tested for MRGdupridge */
          qh_appendmergeset(qh, newfacet, newfacet, MRGdegen, 0.0, 1.0);
          trace2((qh, qh->ferr, 2107, "qh_forcedmerges: dupridge f%d is degenerate with fewer than %d neighbors\n",
                      newfacet->id, qh->hull_dim));
        }
      }
    }
    numdegen += qh_merge_degenredundant(qh);
  }
  if (nummerge || numflip) {
    *wasmerge= True;
    trace1((qh, qh->ferr, 1011, "qh_forcedmerges: merged %d facets, %d flipped facets, and %d degenredundant facets across dupridges\n",
                  nummerge, numflip, numdegen));
  }
} /* forcedmerges */


/*---------------------------------

  qh_freemergesets(qh )
    free the merge sets

  notes:
    matches qh_initmergesets
*/
void qh_freemergesets(qhT *qh) {

  if (!qh->facet_mergeset || !qh->degen_mergeset || !qh->vertex_mergeset) {
    qh_fprintf(qh, qh->ferr, 6388, "qhull internal error (qh_freemergesets): expecting mergesets.  Got a NULL mergeset, qh.facet_mergeset (0x%x), qh.degen_mergeset (0x%x), qh.vertex_mergeset (0x%x)\n",
      qh->facet_mergeset, qh->degen_mergeset, qh->vertex_mergeset);
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  if (!SETempty_(qh->facet_mergeset) || !SETempty_(qh->degen_mergeset) || !SETempty_(qh->vertex_mergeset)) {
    qh_fprintf(qh, qh->ferr, 6389, "qhull internal error (qh_freemergesets): expecting empty mergesets.  Got qh.facet_mergeset (%d merges), qh.degen_mergeset (%d merges), qh.vertex_mergeset (%d merges)\n",
      qh_setsize(qh, qh->facet_mergeset), qh_setsize(qh, qh->degen_mergeset), qh_setsize(qh, qh->vertex_mergeset));
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  qh_settempfree(qh, &qh->facet_mergeset);
  qh_settempfree(qh, &qh->vertex_mergeset);
  qh_settempfree(qh, &qh->degen_mergeset);
} /* freemergesets */

/*---------------------------------

  qh_getmergeset(qh, facetlist )
    determines nonconvex facets on facetlist
    tests !tested ridges and nonconvex ridges of !tested facets

  returns:
    returns sorted qh.facet_mergeset of facet-neighbor pairs to be merged
    all ridges tested

  notes:
    facetlist is qh.facet_newlist, use qh_getmergeset_initial for all facets
    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

  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 mergetype and angle or distance
*/
void qh_getmergeset(qhT *qh, facetT *facetlist) {
  facetT *facet, *neighbor, **neighborp;
  ridgeT *ridge, **ridgep;
  int nummerges;
  boolT simplicial;

  nummerges= qh_setsize(qh, qh->facet_mergeset);
  trace4((qh, qh->ferr, 4026, "qh_getmergeset: started.\n"));
  qh->visit_id++;
  FORALLfacet_(facetlist) {
    if (facet->tested)
      continue;
    facet->visitid= qh->visit_id;
    FOREACHneighbor_(facet)
      neighbor->seen= False;
    /* facet must be non-simplicial due to merge to qh.facet_newlist */
    FOREACHridge_(facet->ridges) {
      if (ridge->tested && !ridge->nonconvex)
        continue;
      /* if r.tested & r.nonconvex, need to retest and append merge */
      neighbor= otherfacet_(ridge, facet);
      if (neighbor->seen) { /* another ridge for this facet-neighbor pair was already tested in this loop */
        ridge->tested= True;
        ridge->nonconvex= False;   /* only one ridge is marked nonconvex per facet-neighbor pair */
      }else if (neighbor->visitid != qh->visit_id) {
        neighbor->seen= True;
        ridge->nonconvex= False;
        simplicial= False;
        if (ridge->simplicialbot && ridge->simplicialtop)
          simplicial= True;
        if (qh_test_appendmerge(qh, facet, neighbor, simplicial))
          ridge->nonconvex= True;
        ridge->tested= True;
      }
    }
    facet->tested= True;
  }
  nummerges= qh_setsize(qh, qh->facet_mergeset);
  if (qh->ANGLEmerge)
    qsort(SETaddr_(qh->facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_compare_anglemerge);
  else
    qsort(SETaddr_(qh->facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_compare_facetmerge);
  nummerges += qh_setsize(qh, qh->degen_mergeset);
  if (qh->POSTmerging) {
    zadd_(Zmergesettot2, nummerges);
  }else {
    zadd_(Zmergesettot, nummerges);
    zmax_(Zmergesetmax, nummerges);
  }
  trace2((qh, qh->ferr, 2021, "qh_getmergeset: %d merges found\n", nummerges));
} /* getmergeset */


/*---------------------------------

  qh_getmergeset_initial(qh, facetlist )
    determine initial qh.facet_mergeset for facets
    tests all facet/neighbor pairs on facetlist

  returns:
    sorted qh.facet_mergeset with nonconvex ridges
    sets facet->tested, ridge->tested, and ridge->nonconvex

  notes:
    uses visit_id, assumes ridge->nonconvex is False
    see qh_getmergeset

  design:
    for each facet on facetlist
      for each untested neighbor of facet
        test facet and neighbor for convexity
        if non-convex
          append merge to qh.facet_mergeset
          mark one of the ridges as nonconvex
    sort qh.facet_mergeset by mergetype and angle or distance
*/
void qh_getmergeset_initial(qhT *qh, facetT *facetlist) {
  facetT *facet, *neighbor, **neighborp;
  ridgeT *ridge, **ridgep;
  int nummerges;
  boolT simplicial;

  qh->visit_id++;
  FORALLfacet_(facetlist) {
    facet->visitid= qh->visit_id;
    FOREACHneighbor_(facet) {
      if (neighbor->visitid != qh->visit_id) {
        simplicial= False; /* ignores r.simplicialtop/simplicialbot.  Need to test horizon facets */
        if (facet->simplicial && neighbor->simplicial)
          simplicial= True;
        if (qh_test_appendmerge(qh, facet, neighbor, simplicial)) {
          FOREACHridge_(neighbor->ridges) {
            if (facet == otherfacet_(ridge, neighbor)) {
              ridge->nonconvex= True;
              break;    /* only one ridge is marked nonconvex */
            }
          }
        }
      }
    }
    facet->tested= True;
    FOREACHridge_(facet->ridges)
      ridge->tested= True;
  }
  nummerges= qh_setsize(qh, qh->facet_mergeset);
  if (qh->ANGLEmerge)
    qsort(SETaddr_(qh->facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_compare_anglemerge);
  else
    qsort(SETaddr_(qh->facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_compare_facetmerge);
  nummerges += qh_setsize(qh, qh->degen_mergeset);
  if (qh->POSTmerging) {
    zadd_(Zmergeinittot2, nummerges);
  }else {
    zadd_(Zmergeinittot, nummerges);
    zmax_(Zmergeinitmax, nummerges);
  }
  trace2((qh, qh->ferr, 2022, "qh_getmergeset_initial: %d merges found\n", nummerges));
} /* getmergeset_initial */

/*---------------------------------

  qh_getpinchedmerges(qh, apex, maxdist, iscoplanar )
    get pinched merges for dupridges in qh.facet_mergeset
    qh.NEWtentative==True
      qh.newfacet_list with apex
      qh.horizon_list is attached to qh.visible_list instead of qh.newfacet_list
      maxdist for vertex-facet of a dupridge
    qh.facet_mergeset is empty
    qh.vertex_mergeset is a temporary set

  returns:
    False if nearest vertex would increase facet width by more than maxdist or qh_WIDEpinched
    True and iscoplanar, if the pinched vertex is the apex (i.e., make the apex a coplanar point)
    True and !iscoplanar, if should merge a pinched vertex of a dupridge
      qh.vertex_mergeset contains one or more MRGsubridge with a pinched vertex and a nearby, neighboring vertex
    qh.facet_mergeset is empty

  notes:
    called by qh_buildcone_mergepinched
    hull_dim >= 3
    a pinched vertex is in a dupridge and the horizon
    selects the pinched vertex that is closest to its neighbor

  design:
    for each dupridge
        determine the best pinched vertex to be merged into a neighboring vertex
        if merging the pinched vertex would produce a wide merge (qh_WIDEpinched)
           ignore pinched vertex with a warning, and use qh_merge_degenredundant instead
        else
           append the pinched vertex to vertex_mergeset for merging
*/
boolT qh_getpinchedmerges(qhT *qh, vertexT *apex, coordT maxdupdist, boolT *iscoplanar /* qh.newfacet_list, qh.vertex_mergeset */) {
  mergeT *merge, **mergep, *bestmerge= NULL;
  vertexT *nearest, *pinched, *bestvertex= NULL, *bestpinched= NULL;
  boolT result;
  coordT dist, prevdist, bestdist= REALmax/(qh_RATIOcoplanarapex+1.0); /* allow *3.0 */
  realT ratio;

  trace2((qh, qh->ferr, 2062, "qh_getpinchedmerges: try to merge pinched vertices for dupridges in new facets with apex p%d(v%d) max dupdist %2.2g\n",
      qh_pointid(qh, apex->point), apex->id, maxdupdist));
  *iscoplanar= False;
  prevdist= fmax_(qh->ONEmerge + qh->DISTround, qh->MINoutside + qh->DISTround);
  maximize_(prevdist, qh->max_outside);
  maximize_(prevdist, -qh->min_vertex);
  qh_mark_dupridges(qh, qh->newfacet_list, !qh_ALL); /* qh.facet_mergeset, creates ridges */
  /* qh_mark_dupridges is called a second time in qh_premerge */
  FOREACHmerge_(qh->facet_mergeset) {  /* read-only */
    if (merge->mergetype != MRGdupridge) {
      qh_fprintf(qh, qh->ferr, 6393, "qhull internal error (qh_getpinchedmerges): expecting MRGdupridge from qh_mark_dupridges.  Got merge f%d f%d type %d\n",
        getid_(merge->facet1), getid_(merge->facet2), merge->mergetype);
      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
    }
    /* dist is distance between vertices */
    pinched= qh_findbest_pinchedvertex(qh, merge, apex, &nearest, &dist /* qh.newfacet_list */);
    if (pinched == apex && dist < qh_RATIOcoplanarapex*bestdist) { /* prefer coplanar apex since it always works */
      bestdist= dist/qh_RATIOcoplanarapex;
      bestmerge= merge;
      bestpinched= pinched;
      bestvertex= nearest;
    }else if (dist < bestdist) {
      bestdist= dist;
      bestmerge= merge;
      bestpinched= pinched;
      bestvertex= nearest;
    }
  }
  result= False;
  if (bestmerge && bestdist < maxdupdist) {
    ratio= bestdist / prevdist;
    if (ratio > qh_WIDEpinched) {
      if (bestmerge->facet1->mergehorizon || bestmerge->facet2->mergehorizon) { /* e.g., rbox 175 C3,2e-13 t1539182828 | qhull d */
        trace1((qh, qh->ferr, 1051, "qh_getpinchedmerges: dupridge (MRGdupridge) of coplanar horizon would produce a wide merge (%.0fx) due to pinched vertices v%d and v%d (dist %2.2g) for f%d and f%d.  qh_mergecycle_all will merge one or both facets\n",
          ratio, bestpinched->id, bestvertex->id, bestdist, bestmerge->facet1->id, bestmerge->facet2->id));
      }else {
        qh_fprintf(qh, qh->ferr, 7081, "qhull precision warning (qh_getpinchedmerges): pinched vertices v%d and v%d (dist %2.2g, %.0fx) would produce a wide merge for f%d and f%d.  Will merge dupridge instead\n",
          bestpinched->id, bestvertex->id, bestdist, ratio, bestmerge->facet1->id, bestmerge->facet2->id);
      }
    }else {
      if (bestpinched == apex) {
        trace2((qh, qh->ferr, 2063, "qh_getpinchedmerges: will make the apex a coplanar point.  apex p%d(v%d) is the nearest vertex to v%d on dupridge.  Dist %2.2g\n",
          qh_pointid(qh, apex->point), apex->id, bestvertex->id, bestdist*qh_RATIOcoplanarapex));
        qh->coplanar_apex= apex->point;
        *iscoplanar= True;
        result= True;
      }else if (qh_setin(bestmerge->facet1->vertices, bestpinched) != qh_setin(bestmerge->facet2->vertices, bestpinched)) { /* pinched in one facet but not the other facet */
        trace2((qh, qh->ferr, 2064, "qh_getpinchedmerges: will merge new facets to resolve dupridge between f%d and f%d with pinched v%d and v%d\n",
          bestmerge->facet1->id, bestmerge->facet2->id, bestpinched->id, bestvertex->id));
        qh_appendvertexmerge(qh, bestpinched, bestvertex, MRGsubridge, bestdist, NULL, NULL);
        result= True;
      }else {
        trace2((qh, qh->ferr, 2065, "qh_getpinchedmerges: will merge pinched v%d into v%d to resolve dupridge between f%d and f%d\n",
          bestpinched->id, bestvertex->id, bestmerge->facet1->id, bestmerge->facet2->id));
        qh_appendvertexmerge(qh, bestpinched, bestvertex, MRGsubridge, bestdist, NULL, NULL);
        result= True;
      }
    }
  }
  /* delete MRGdupridge, qh_mark_dupridges is called a second time in qh_premerge */
  while ((merge= (mergeT *)qh_setdellast(qh->facet_mergeset)))
    qh_memfree(qh, merge, (int)sizeof(mergeT));
  return result;
}/* getpinchedmerges */

/*---------------------------------

  qh_hasmerge( mergeset, mergetype, facetA, facetB )
    True if mergeset has mergetype for facetA and facetB
*/
boolT   qh_hasmerge(setT *mergeset, mergeType type, facetT *facetA, facetT *facetB) {
  mergeT *merge, **mergep;

  FOREACHmerge_(mergeset) {
    if (merge->mergetype == type) {
      if (merge->facet1 == facetA && merge->facet2 == facetB)
        return True;
      if (merge->facet1 == facetB && merge->facet2 == facetA)
        return True;
    }
  }
  return False;
}/* hasmerge */

/*---------------------------------

  qh_hashridge(qh, hashtable, hashsize, ridge, oldvertex )
    add ridge to hashtable without oldvertex

  notes:
    assumes hashtable is large enough

  design:
    determine hash value for ridge without oldvertex
    find next empty slot for ridge
*/
void qh_hashridge(qhT *qh, setT *hashtable, int hashsize, ridgeT *ridge, vertexT *oldvertex) {
  int hash;
  ridgeT *ridgeA;

  hash= qh_gethash(qh, hashsize, ridge->vertices, qh->hull_dim-1, 0, oldvertex);
  while (True) {
    if (!(ridgeA= SETelemt_(hashtable, hash, ridgeT))) {
      SETelem_(hashtable, hash)= ridge;
      break;
    }else if (ridgeA == ridge)
      break;
    if (++hash == hashsize)
      hash= 0;
  }
} /* hashridge */


/*---------------------------------

  qh_hashridge_find(qh, hashtable, hashsize, ridge, vertex, oldvertex, hashslot )
    returns matching ridge without oldvertex in hashtable
      for ridge without vertex
    if oldvertex is NULL
      matches with any one skip

  returns:
    matching ridge or NULL
    if no match,
      if ridge already in   table
        hashslot= -1
      else
        hashslot= next NULL index

  notes:
    assumes hashtable is large enough
    can't match ridge to itself

  design:
    get hash value for ridge without vertex
    for each hashslot
      return match if ridge matches ridgeA without oldvertex
*/
ridgeT *qh_hashridge_find(qhT *qh, setT *hashtable, int hashsize, ridgeT *ridge,
              vertexT *vertex, vertexT *oldvertex, int *hashslot) {
  int hash;
  ridgeT *ridgeA;

  *hashslot= 0;
  zinc_(Zhashridge);
  hash= qh_gethash(qh, hashsize, ridge->vertices, qh->hull_dim-1, 0, vertex);
  while ((ridgeA= SETelemt_(hashtable, hash, ridgeT))) {
    if (ridgeA == ridge)
      *hashslot= -1;
    else {
      zinc_(Zhashridgetest);
      if (qh_setequal_except(ridge->vertices, vertex, ridgeA->vertices, oldvertex))
        return ridgeA;
    }
    if (++hash == hashsize)
      hash= 0;
  }
  if (!*hashslot)
    *hashslot= hash;
  return NULL;
} /* hashridge_find */


/*---------------------------------

  qh_initmergesets(qh )
    initialize the merge sets
    if 'all', include qh.degen_mergeset

  notes:
    matches qh_freemergesets
*/
void qh_initmergesets(qhT *qh /* qh.facet_mergeset,degen_mergeset,vertex_mergeset */) {

  if (qh->facet_mergeset || qh->degen_mergeset || qh->vertex_mergeset) {
    qh_fprintf(qh, qh->ferr, 6386, "qhull internal error (qh_initmergesets): expecting NULL mergesets.  Got qh.facet_mergeset (0x%x), qh.degen_mergeset (0x%x), qh.vertex_mergeset (0x%x)\n",
      qh->facet_mergeset, qh->degen_mergeset, qh->vertex_mergeset);
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  qh->degen_mergeset= qh_settemp(qh, qh->TEMPsize);
  qh->vertex_mergeset= qh_settemp(qh, qh->TEMPsize);
  qh->facet_mergeset= qh_settemp(qh, qh->TEMPsize); /* last temporary set for qh_forcedmerges */
} /* initmergesets */

/*---------------------------------

  qh_makeridges(qh, facet )
    creates explicit ridges between simplicial facets

  returns:
    facet with ridges and without qh_MERGEridge
    ->simplicial is False
    if facet was tested, new ridges are tested

  notes:
    allows qh_MERGEridge flag
    uses existing ridges
    duplicate neighbors ok if ridges already exist (qh_mergecycle_ridges)

  see:
    qh_mergecycle_ridges()
    qh_rename_adjacentvertex for qh_merge_pinchedvertices

  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 (previously processed by qh_mark_dupridges)
*/
void qh_makeridges(qhT *qh, facetT *facet) {
  facetT *neighbor, **neighborp;
  ridgeT *ridge, **ridgep;
  int neighbor_i, neighbor_n;
  boolT toporient, mergeridge= False;

  if (!facet->simplicial)
    return;
  trace4((qh, qh->ferr, 4027, "qh_makeridges: make ridges for f%d\n", facet->id));
  facet->simplicial= False;
  FOREACHneighbor_(facet) {
    if (neighbor == qh_MERGEridge)
      mergeridge= True;
    else
      neighbor->seen= False;
  }
  FOREACHridge_(facet->ridges)
    otherfacet_(ridge, facet)->seen= True;
  FOREACHneighbor_i_(qh, facet) {
    if (neighbor == qh_MERGEridge)
      continue;  /* fixed by qh_mark_dupridges */
    else if (!neighbor->seen) {  /* no current ridges */
      ridge= qh_newridge(qh);
      ridge->vertices= qh_setnew_delnthsorted(qh, facet->vertices, qh->hull_dim,
                                                          neighbor_i, 0);
      toporient= (boolT)(facet->toporient ^ (neighbor_i & 0x1));
      if (toporient) {
        ridge->top= facet;
        ridge->bottom= neighbor;
        ridge->simplicialtop= True;
        ridge->simplicialbot= neighbor->simplicial;
      }else {
        ridge->top= neighbor;
        ridge->bottom= facet;
        ridge->simplicialtop= neighbor->simplicial;
        ridge->simplicialbot= True;
      }
      if (facet->tested && !mergeridge)
        ridge->tested= True;
#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;
        ridge->simplicialtop= True;
        ridge->simplicialbot= neighbor->simplicial;
      }else {
        ridge->top= facet;
        ridge->bottom= neighbor;
        ridge->simplicialtop= neighbor->simplicial;
        ridge->simplicialbot= True;
      }
#endif
      qh_setappend(qh, &(facet->ridges), ridge);
      trace5((qh, qh->ferr, 5005, "makeridges: appended r%d to ridges for f%d.  Next is ridges for neighbor f%d\n",
            ridge->id, facet->id, neighbor->id));
      qh_setappend(qh, &(neighbor->ridges), ridge);
      if (qh->ridge_id == qh->traceridge_id)
        qh->traceridge= ridge;
    }
  }
  if (mergeridge) {
    while (qh_setdel(facet->neighbors, qh_MERGEridge))
      ; /* delete each one */
  }
} /* makeridges */


/*---------------------------------

  qh_mark_dupridges(qh, facetlist, allmerges )
    add duplicated ridges to qh.facet_mergeset
    facet-dupridge is true if it contains a subridge shared by more than one new facet
    for each such facet, one has a neighbor marked qh_MERGEridge
    allmerges is true if merging dupridges
    allmerges is false if merging pinched vertices followed by retry addpoint
      qh_mark_dupridges will be called again if pinched vertices not found

  returns:
    dupridges on qh.facet_mergeset (MRGdupridge)
    f.mergeridge and f.mergeridge2 set for facet
    f.mergeridge set for neighbor
    if allmerges is true
      make ridges for facets with dupridges as marked by qh_MERGEridge and both sides facet->dupridge
      removes qh_MERGEridge from neighbor sets

  notes:
    called by qh_premerge and qh_getpinchedmerges
    dupridges are due to duplicate subridges
        i.e. a subridge occurs in more than two horizon ridges.
        i.e., a ridge has more than two neighboring facets
    dupridges occur in at least two cases
    1) a pinched horizon with nearly adjacent vertices -> merge the vertices (qh_getpinchedmerges)
    2) more than one newfacet for a horizon face -> merge coplanar facets (qh_premerge)
    qh_matchdupridge previously identified the furthest apart pair of facets to retain
       they must have a matching subridge and the same orientation
    only way to set facet->mergeridge and mergeridge2
    uses qh.visit_id

  design:
    for all facets on facetlist
      if facet contains a dupridge
        for each neighbor of facet
          if neighbor marked qh_MERGEridge (one side of the merge)
            set facet->mergeridge
          else
            if neighbor contains a dupridge
            and the back link is qh_MERGEridge
              append dupridge to qh.facet_mergeset
   exit if !allmerges for repeating qh_mark_dupridges later
   for each dupridge
     make ridge sets in preparation for merging
     remove qh_MERGEridge from neighbor set
   for each dupridge
     restore the missing neighbor from the neighbor set that was qh_MERGEridge
     add the missing ridge for this neighbor
*/
void qh_mark_dupridges(qhT *qh, facetT *facetlist, boolT allmerges) {
  facetT *facet, *neighbor, **neighborp;
  int nummerge=0;
  mergeT *merge, **mergep;

  trace4((qh, qh->ferr, 4028, "qh_mark_dupridges: identify dupridges in facetlist f%d, allmerges? %d\n",
    facetlist->id, allmerges));
  FORALLfacet_(facetlist) {  /* not necessary for first call */
    facet->mergeridge2= False;
    facet->mergeridge= False;
  }
  FORALLfacet_(facetlist) {
    if (facet->dupridge) {
      FOREACHneighbor_(facet) {
        if (neighbor == qh_MERGEridge) {
          facet->mergeridge= True;
          continue;
        }
        if (neighbor->dupridge) {
          if (!qh_setin(neighbor->neighbors, facet)) { /* i.e., it is qh_MERGEridge, neighbors are distinct */
            qh_appendmergeset(qh, facet, neighbor, MRGdupridge, 0.0, 1.0);
            facet->mergeridge2= True;
            facet->mergeridge= True;
            nummerge++;
          }else if (qh_setequal(facet->vertices, neighbor->vertices)) { /* neighbors are the same except for horizon and qh_MERGEridge, see QH7085 */
            trace3((qh, qh->ferr, 3043, "qh_mark_dupridges): dupridge due to duplicate vertices for subridges f%d and f%d\n",
                 facet->id, neighbor->id));
            qh_appendmergeset(qh, facet, neighbor, MRGdupridge, 0.0, 1.0);
            facet->mergeridge2= True;
            facet->mergeridge= True;
            nummerge++;
            break; /* same for all neighbors */
          }
        }
      }
    }
  }
  if (!nummerge)
    return;
  if (!allmerges) {
    trace1((qh, qh->ferr, 1012, "qh_mark_dupridges: found %d duplicated ridges (MRGdupridge) for qh_getpinchedmerges\n", nummerge));
    return;
  }
  trace1((qh, qh->ferr, 1048, "qh_mark_dupridges: found %d duplicated ridges (MRGdupridge) for qh_premerge.  Prepare facets for merging\n", nummerge));
  /* make ridges in preparation for merging */
  FORALLfacet_(facetlist) {
    if (facet->mergeridge && !facet->mergeridge2)
      qh_makeridges(qh, facet);
  }
  trace3((qh, qh->ferr, 3075, "qh_mark_dupridges: restore missing neighbors and ridges due to qh_MERGEridge\n"));
  FOREACHmerge_(qh->facet_mergeset) {   /* restore the missing neighbors */
    if (merge->mergetype == MRGdupridge) { /* only between simplicial facets */
      if (merge->facet2->mergeridge2 && qh_setin(merge->facet2->neighbors, merge->facet1)) {
        /* Due to duplicate or multiple subridges, e.g., ../eg/qtest.sh t712682 '200 s W1e-13  C1,1e-13 D5' 'd'
            merge->facet1:    - neighboring facets: f27779 f59186 f59186 f59186 MERGEridge f59186
            merge->facet2:    - neighboring facets: f27779 f59100 f59100 f59100 f59100 f59100
           or, ../eg/qtest.sh 100 '500 s W1e-13 C1,1e-13 D4' 'd'
           both facets will be degenerate after merge, consider for special case handling
        */
        qh_fprintf(qh, qh->ferr, 6361, "qhull topological error (qh_mark_dupridges): multiple dupridges for f%d and f%d, including reverse\n",
          merge->facet1->id, merge->facet2->id);
        qh_errexit2(qh, qh_ERRtopology, merge->facet1, merge->facet2);
      }else
        qh_setappend(qh, &merge->facet2->neighbors, merge->facet1);
      qh_makeridges(qh, merge->facet1);   /* and the missing ridges */
    }
  }
} /* mark_dupridges */

/*---------------------------------

  qh_maybe_duplicateridge(qh, ridge )
    add MRGvertices if neighboring facet has another ridge with the same vertices

  returns:
    adds rename requests to qh.vertex_mergeset

  notes:
    called by qh_renamevertex
    nop if 2-D
    expensive test
    Duplicate ridges may lead to new facets with same vertex set (QH7084), will try merging vertices
    same as qh_maybe_duplicateridges

  design:
    for the two neighbors
      if non-simplicial
        for each ridge with the same first and last vertices (max id and min id)
          if the remaining vertices are the same
            get the closest pair of vertices
            add to vertex_mergeset for merging
*/
void qh_maybe_duplicateridge(qhT *qh, ridgeT *ridgeA) {
  ridgeT *ridge, **ridgep;
  vertexT *vertex, *pinched;
  facetT *neighbor;
  coordT dist;
  int i, k, last= qh->hull_dim-2;

  if (qh->hull_dim < 3 )
    return;

  for (neighbor= ridgeA->top, i=0; i<2; neighbor= ridgeA->bottom, i++) {
    if (!neighbor->simplicial && neighbor->nummerge > 0) { /* skip degenerate neighbors with both new and old vertices that will be merged */
      FOREACHridge_(neighbor->ridges) {
        if (ridge != ridgeA && SETfirst_(ridge->vertices) == SETfirst_(ridgeA->vertices)) {
          if (SETelem_(ridge->vertices, last) == SETelem_(ridgeA->vertices, last)) {
            for (k=1; kvertices, k) != SETelem_(ridgeA->vertices, k))
                break;
            }
            if (k == last) {
              vertex= qh_findbest_ridgevertex(qh, ridge, &pinched, &dist);
              trace2((qh, qh->ferr, 2069, "qh_maybe_duplicateridge: will merge v%d into v%d (dist %2.2g) due to duplicate ridges r%d/r%d with the same vertices.  mergevertex set\n",
                pinched->id, vertex->id, dist, ridgeA->id, ridge->id, ridgeA->top->id, ridgeA->bottom->id, ridge->top->id, ridge->bottom->id));
              qh_appendvertexmerge(qh, pinched, vertex, MRGvertices, dist, ridgeA, ridge);
              ridge->mergevertex= True; /* disables check for duplicate vertices in qh_checkfacet */
              ridgeA->mergevertex= True;
            }
          }
        }
      }
    }
  }
} /* maybe_duplicateridge */

/*---------------------------------

  qh_maybe_duplicateridges(qh, facet )
    if Q15, add MRGvertices if facet has ridges with the same vertices

  returns:
    adds rename requests to qh.vertex_mergeset

  notes:
    called at end of qh_mergefacet and qh_mergecycle_all
    only enabled if qh.CHECKduplicates ('Q15') and 3-D or more
    expensive test, not worth it
    same as qh_maybe_duplicateridge

  design:
    for all ridge pairs in facet
        if the same first and last vertices (max id and min id)
          if the remaining vertices are the same
            get the closest pair of vertices
            add to vertex_mergeset for merging
*/
void qh_maybe_duplicateridges(qhT *qh, facetT *facet) {
  facetT *otherfacet;
  ridgeT *ridge, *ridge2;
  vertexT *vertex, *pinched;
  coordT dist;
  int ridge_i, ridge_n, i, k, last_v= qh->hull_dim-2;

  if (qh->hull_dim < 3 || !qh->CHECKduplicates)
    return;

  FOREACHridge_i_(qh, facet->ridges) {
    otherfacet= otherfacet_(ridge, facet);
    if (otherfacet->degenerate || otherfacet->redundant || otherfacet->dupridge || otherfacet->flipped) /* will merge */
      continue;
    for (i=ridge_i+1; i < ridge_n; i++) {
      ridge2= SETelemt_(facet->ridges, i, ridgeT);
      otherfacet= otherfacet_(ridge2, facet);
      if (otherfacet->degenerate || otherfacet->redundant || otherfacet->dupridge || otherfacet->flipped) /* will merge */
        continue;
      /* optimize qh_setequal(ridge->vertices, ridge2->vertices) */
      if (SETelem_(ridge->vertices, last_v) == SETelem_(ridge2->vertices, last_v)) { /* SETfirst is likely to be the same */
        if (SETfirst_(ridge->vertices) == SETfirst_(ridge2->vertices)) {
          for (k=1; kvertices, k) != SETelem_(ridge2->vertices, k))
              break;
          }
          if (k == last_v) {
            vertex= qh_findbest_ridgevertex(qh, ridge, &pinched, &dist);
            if (ridge->top == ridge2->bottom && ridge->bottom == ridge2->top) {
              /* proof that ridges may have opposite orientation */
              trace2((qh, qh->ferr, 2088, "qh_maybe_duplicateridges: will merge v%d into v%d (dist %2.2g) due to opposite oriented ridges r%d/r%d for f%d and f%d\n",
                pinched->id, vertex->id, dist, ridge->id, ridge2->id, ridge->top->id, ridge->bottom->id));
            }else {
              trace2((qh, qh->ferr, 2083, "qh_maybe_duplicateridges: will merge v%d into v%d (dist %2.2g) due to duplicate ridges with the same vertices r%d/r%d in merged facet f%d\n",
                pinched->id, vertex->id, dist, ridge->id, ridge2->id, facet->id));
            }
            qh_appendvertexmerge(qh, pinched, vertex, MRGvertices, dist, ridge, ridge2);
            ridge->mergevertex= True; /* disables check for duplicate vertices in qh_checkfacet */
            ridge2->mergevertex= True;
          }
        }
      }
    }
  }
} /* maybe_duplicateridges */

/*---------------------------------

  qh_maydropneighbor(qh, facet )
    drop neighbor relationship if ridge was deleted between a non-simplicial facet and its neighbors

  returns:
    for deleted ridges
      ridges made for simplicial neighbors
      neighbor sets updated
      appends degenerate facets to qh.facet_mergeset

  notes:
    called by qh_renamevertex
    assumes neighbors do not include qh_MERGEridge (qh_makeridges)
    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 non-simplicial neighbor sets
      if neighbor becomes degenerate
        append neighbor to qh.degen_mergeset
    if facet is degenerate
      append facet to qh.degen_mergeset
*/
void qh_maydropneighbor(qhT *qh, facetT *facet) {
  ridgeT *ridge, **ridgep;
  facetT *neighbor, **neighborp;

  qh->visit_id++;
  trace4((qh, qh->ferr, 4029, "qh_maydropneighbor: test f%d for no ridges to a neighbor\n",
          facet->id));
  if (facet->simplicial) {
    qh_fprintf(qh, qh->ferr, 6278, "qhull internal error (qh_maydropneighbor): not valid for simplicial f%d while adding furthest p%d\n",
      facet->id, qh->furthest_id);
    qh_errexit(qh, qh_ERRqhull, facet, NULL);
  }
  FOREACHridge_(facet->ridges) {
    ridge->top->visitid= qh->visit_id;
    ridge->bottom->visitid= qh->visit_id;
  }
  FOREACHneighbor_(facet) {
    if (neighbor->visible) {
      qh_fprintf(qh, qh->ferr, 6358, "qhull internal error (qh_maydropneighbor): facet f%d has deleted neighbor f%d (qh.visible_list)\n",
            facet->id, neighbor->id);
      qh_errexit2(qh, qh_ERRqhull, facet, neighbor);
    }
    if (neighbor->visitid != qh->visit_id) {
      trace2((qh, qh->ferr, 2104, "qh_maydropneighbor: facets f%d and f%d are no longer neighbors while adding furthest p%d\n",
            facet->id, neighbor->id, qh->furthest_id));
      if (neighbor->simplicial) {
        qh_fprintf(qh, qh->ferr, 6280, "qhull internal error (qh_maydropneighbor): not valid for simplicial neighbor f%d of f%d while adding furthest p%d\n",
            neighbor->id, facet->id, qh->furthest_id);
        qh_errexit2(qh, qh_ERRqhull, neighbor, facet);
      }
      zinc_(Zdropneighbor);
      qh_setdel(neighbor->neighbors, facet);
      if (qh_setsize(qh, neighbor->neighbors) < qh->hull_dim) {
        zinc_(Zdropdegen);
        qh_appendmergeset(qh, neighbor, neighbor, MRGdegen, 0.0, qh_ANGLEnone);
        trace2((qh, qh->ferr, 2023, "qh_maydropneighbors: f%d is degenerate.\n", neighbor->id));
      }
      qh_setdel(facet->neighbors, neighbor);
      neighborp--;  /* repeat, deleted a neighbor */
    }
  }
  if (qh_setsize(qh, facet->neighbors) < qh->hull_dim) {
    zinc_(Zdropdegen);
    qh_appendmergeset(qh, facet, facet, MRGdegen, 0.0, qh_ANGLEnone);
    trace2((qh, qh->ferr, 2024, "qh_maydropneighbors: f%d is degenerate.\n", facet->id));
  }
} /* maydropneighbor */


/*---------------------------------

  qh_merge_degenredundant(qh)
    merge all degenerate and redundant facets
    qh.degen_mergeset contains merges from  qh_test_degen_neighbors, qh_test_redundant_neighbors, and qh_degen_redundant_facet

  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
    check for coplanar and convex neighbors afterwards

  design:
    for each merge on qh.degen_mergeset
      if redundant merge
        if non-redundant facet merged into redundant facet
          recheck facet for redundancy
        else
          merge redundant facet into other facet
*/
int qh_merge_degenredundant(qhT *qh) {
  int size;
  mergeT *merge;
  facetT *bestneighbor, *facet1, *facet2, *facet3;
  realT dist, mindist, maxdist;
  vertexT *vertex, **vertexp;
  int nummerges= 0;
  mergeType mergetype;
  setT *mergedfacets;

  trace2((qh, qh->ferr, 2095, "qh_merge_degenredundant: merge %d degenerate, redundant, and mirror facets\n",
    qh_setsize(qh, qh->degen_mergeset)));
  mergedfacets= qh_settemp(qh, qh->TEMPsize);
  while ((merge= (mergeT *)qh_setdellast(qh->degen_mergeset))) {
    facet1= merge->facet1;
    facet2= merge->facet2;
    mergetype= merge->mergetype;
    qh_memfree(qh, merge, (int)sizeof(mergeT)); /* 'merge' is invalidated */
    if (facet1->visible)
      continue;
    facet1->degenerate= False;
    facet1->redundant= False;
    if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
      qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
    if (mergetype == MRGredundant) {
      zinc_(Zredundant);
      facet3= qh_getreplacement(qh, facet2); /* the same facet if !facet2.visible */
      if (!facet3) {
          qh_fprintf(qh, qh->ferr, 6097, "qhull internal error (qh_merge_degenredunant): f%d is redundant but visible f%d has no replacement\n",
               facet1->id, getid_(facet2));
          qh_errexit2(qh, qh_ERRqhull, facet1, facet2);
      }
      qh_setunique(qh, &mergedfacets, facet3);
      if (facet1 == facet3) {
        continue;
      }
      trace2((qh, qh->ferr, 2025, "qh_merge_degenredundant: merge redundant f%d into f%d (arg f%d)\n",
            facet1->id, facet3->id, facet2->id));
      qh_mergefacet(qh, facet1, facet3, mergetype, NULL, NULL, !qh_MERGEapex);
      /* merge distance is already accounted for */
      nummerges++;
    }else {  /* mergetype == MRGdegen or MRGmirror, other merges may have fixed */
      if (!(size= qh_setsize(qh, facet1->neighbors))) {
        zinc_(Zdelfacetdup);
        trace2((qh, qh->ferr, 2026, "qh_merge_degenredundant: facet f%d has no neighbors.  Deleted\n", facet1->id));
        qh_willdelete(qh, facet1, NULL);
        FOREACHvertex_(facet1->vertices) {
          qh_setdel(vertex->neighbors, facet1);
          if (!SETfirst_(vertex->neighbors)) {
            zinc_(Zdegenvertex);
            trace2((qh, qh->ferr, 2027, "qh_merge_degenredundant: deleted v%d because f%d has no neighbors\n",
                 vertex->id, facet1->id));
            vertex->deleted= True;
            qh_setappend(qh, &qh->del_vertices, vertex);
          }
        }
        nummerges++;
      }else if (size < qh->hull_dim) {
        bestneighbor= qh_findbestneighbor(qh, facet1, &dist, &mindist, &maxdist);
        trace2((qh, qh->ferr, 2028, "qh_merge_degenredundant: facet f%d has %d neighbors, merge into f%d dist %2.2g\n",
              facet1->id, size, bestneighbor->id, dist));
        qh_mergefacet(qh, facet1, bestneighbor, mergetype, &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 */
    }
  }
  qh_settempfree(qh, &mergedfacets);
  return nummerges;
} /* merge_degenredundant */

/*---------------------------------

  qh_merge_nonconvex(qh, facet1, facet2, mergetype )
    remove non-convex ridge between facet1 into facet2
    mergetype gives why the facet's are non-convex

  returns:
    merges one of the facets into the best neighbor

  notes:
    mergetype is MRGcoplanar..MRGconvex

  design:
    if one of the facets is a new facet
      prefer merging new facet into old facet
    find best neighbors for both facets
    merge the nearest facet into its best neighbor
    update the statistics
*/
void qh_merge_nonconvex(qhT *qh, facetT *facet1, facetT *facet2, mergeType mergetype) {
  facetT *bestfacet, *bestneighbor, *neighbor, *merging, *merged;
  realT dist, dist2, mindist, mindist2, maxdist, maxdist2;

  if (mergetype < MRGcoplanar || mergetype > MRGconcavecoplanar) {
    qh_fprintf(qh, qh->ferr, 6398, "qhull internal error (qh_merge_nonconvex): expecting mergetype MRGcoplanar..MRGconcavecoplanar.  Got merge f%d and f%d type %d\n",
      facet1->id, facet2->id, mergetype);
    qh_errexit2(qh, qh_ERRqhull, facet1, facet2);
  }
  if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
    qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
  trace3((qh, qh->ferr, 3003, "qh_merge_nonconvex: merge #%d for f%d and f%d type %d\n",
      zzval_(Ztotmerge) + 1, facet1->id, facet2->id, mergetype));
  /* concave or coplanar */
  if (!facet1->newfacet) {
    bestfacet= facet2;   /* avoid merging old facet if new is ok */
    facet2= facet1;
    facet1= bestfacet;
  }else
    bestfacet= facet1;
  bestneighbor= qh_findbestneighbor(qh, bestfacet, &dist, &mindist, &maxdist);
  neighbor= qh_findbestneighbor(qh, facet2, &dist2, &mindist2, &maxdist2);
  if (dist < dist2) {
    merging= bestfacet;
    merged= bestneighbor;
  }else if (qh->AVOIDold && !facet2->newfacet
  && ((mindist >= -qh->MAXcoplanar && maxdist <= qh->max_outside)
       || dist * 1.5 < dist2)) {
    zinc_(Zavoidold);
    wadd_(Wavoidoldtot, dist);
    wmax_(Wavoidoldmax, dist);
    trace2((qh, qh->ferr, 2029, "qh_merge_nonconvex: avoid merging old facet f%d dist %2.2g.  Use f%d dist %2.2g instead\n",
           facet2->id, dist2, facet1->id, dist2));
    merging= bestfacet;
    merged= bestneighbor;
  }else {
    merging= facet2;
    merged= neighbor;
    dist= dist2;
    mindist= mindist2;
    maxdist= maxdist2;
  }
  qh_mergefacet(qh, merging, merged, mergetype, &mindist, &maxdist, !qh_MERGEapex);
  /* caller merges qh_degenredundant */
  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 if (mergetype == MRGconcavecoplanar) {
      zinc_(Zconcavecoplanar);
      wadd_(Wconcavecoplanartot, dist);
      wmax_(Wconcavecoplanarmax, dist);
    }else { /* MRGcoplanar */
      zinc_(Zcoplanar);
      wadd_(Wcoplanartot, dist);
      wmax_(Wcoplanarmax, dist);
    }
  }
} /* merge_nonconvex */

/*---------------------------------

  qh_merge_pinchedvertices(qh, apex )
    merge pinched vertices in qh.vertex_mergeset to avoid qh_forcedmerges of dupridges

  notes:
    only called by qh_all_vertexmerges
    hull_dim >= 3

  design:
    make vertex neighbors if necessary
    for each pinched vertex
      determine the ridges for the pinched vertex (make ridges as needed)
      merge the pinched vertex into the horizon vertex
      merge the degenerate and redundant facets that result
    check and resolve new dupridges
*/
void qh_merge_pinchedvertices(qhT *qh, int apexpointid /* qh.newfacet_list */) {
  mergeT *merge, *mergeA, **mergeAp;
  vertexT *vertex, *vertex2;
  realT dist;
  boolT firstmerge= True;

  qh_vertexneighbors(qh);
  if (qh->visible_list || qh->newfacet_list || qh->newvertex_list) {
    qh_fprintf(qh, qh->ferr, 6402, "qhull internal error (qh_merge_pinchedvertices): qh.visible_list (f%d), newfacet_list (f%d), or newvertex_list (v%d) not empty\n",
      getid_(qh->visible_list), getid_(qh->newfacet_list), getid_(qh->newvertex_list));
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  qh->visible_list= qh->newfacet_list= qh->facet_tail;
  qh->newvertex_list= qh->vertex_tail;
  qh->isRenameVertex= True; /* disable duplicate ridge vertices check in qh_checkfacet */
  while ((merge= qh_next_vertexmerge(qh /* qh.vertex_mergeset */))) { /* only one at a time from qh_getpinchedmerges */
    if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
      qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
    if (merge->mergetype == MRGsubridge) {
      zzinc_(Zpinchedvertex);
      trace1((qh, qh->ferr, 1050, "qh_merge_pinchedvertices: merge one of %d pinched vertices before adding apex p%d.  Try to resolve duplicate ridges in newfacets\n",
        qh_setsize(qh, qh->vertex_mergeset)+1, apexpointid));
      qh_remove_mergetype(qh, qh->vertex_mergeset, MRGsubridge);
    }else {
      zzinc_(Zpinchduplicate);
      if (firstmerge)
        trace1((qh, qh->ferr, 1056, "qh_merge_pinchedvertices: merge %d pinched vertices from dupridges in merged facets, apex p%d\n",
           qh_setsize(qh, qh->vertex_mergeset)+1, apexpointid));
      firstmerge= False;
    }
    vertex= merge->vertex1;
    vertex2= merge->vertex2;
    dist= merge->distance;
    qh_memfree(qh, merge, (int)sizeof(mergeT)); /* merge is invalidated */
    qh_rename_adjacentvertex(qh, vertex, vertex2, dist);
#ifndef qh_NOtrace
    if (qh->IStracing >= 2) {
      FOREACHmergeA_(qh->degen_mergeset) {
        if (mergeA->mergetype== MRGdegen) {
          qh_fprintf(qh, qh->ferr, 2072, "qh_merge_pinchedvertices: merge degenerate f%d into an adjacent facet\n", mergeA->facet1->id);
        }else {
          qh_fprintf(qh, qh->ferr, 2084, "qh_merge_pinchedvertices: merge f%d into f%d mergeType %d\n", mergeA->facet1->id, mergeA->facet2->id, mergeA->mergetype);
        }
      }
    }
#endif
    qh_merge_degenredundant(qh); /* simplicial facets with both old and new vertices */
  }
  qh->isRenameVertex= False;
}/* merge_pinchedvertices */

/*---------------------------------

  qh_merge_twisted(qh, facet1, facet2 )
    remove twisted ridge between facet1 into facet2 or report error

  returns:
    merges one of the facets into the best neighbor

  notes:
    a twisted ridge has opposite vertices that are convex and concave

  design:
    find best neighbors for both facets
    error if wide merge
    merge the nearest facet into its best neighbor
    update statistics
*/
void qh_merge_twisted(qhT *qh, facetT *facet1, facetT *facet2) {
  facetT *neighbor2, *neighbor, *merging, *merged;
  vertexT *bestvertex, *bestpinched;
  realT dist, dist2, mindist, mindist2, maxdist, maxdist2, mintwisted, bestdist;

  if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
    qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
  trace3((qh, qh->ferr, 3050, "qh_merge_twisted: merge #%d for twisted f%d and f%d\n",
      zzval_(Ztotmerge) + 1, facet1->id, facet2->id));
  /* twisted */
  neighbor= qh_findbestneighbor(qh, facet1, &dist, &mindist, &maxdist);
  neighbor2= qh_findbestneighbor(qh, facet2, &dist2, &mindist2, &maxdist2);
  mintwisted= qh_RATIOtwisted * qh->ONEmerge;
  maximize_(mintwisted, facet1->maxoutside);
  maximize_(mintwisted, facet2->maxoutside);
  if (dist > mintwisted && dist2 > mintwisted) {
    bestdist= qh_vertex_bestdist2(qh, facet1->vertices, &bestvertex, &bestpinched);
    if (bestdist > mintwisted) {
      qh_fprintf(qh, qh->ferr, 6417, "qhull precision error (qh_merge_twisted): twisted facet f%d does not contain pinched vertices.  Too wide to merge into neighbor.  mindist %2.2g maxdist %2.2g vertexdist %2.2g maxpinched %2.2g neighbor f%d mindist %2.2g maxdist %2.2g\n",
        facet1->id, mindist, maxdist, bestdist, mintwisted, facet2->id, mindist2, maxdist2);
    }else {
      qh_fprintf(qh, qh->ferr, 6418, "qhull precision error (qh_merge_twisted): twisted facet f%d with pinched vertices.  Could merge vertices, but too wide to merge into neighbor.   mindist %2.2g maxdist %2.2g vertexdist %2.2g neighbor f%d mindist %2.2g maxdist %2.2g\n",
        facet1->id, mindist, maxdist, bestdist, facet2->id, mindist2, maxdist2);
    }
    qh_errexit2(qh, qh_ERRwide, facet1, facet2);
  }
  if (dist < dist2) {
    merging= facet1;
    merged= neighbor;
  }else {
    /* ignores qh.AVOIDold ('Q4') */
    merging= facet2;
    merged= neighbor2;
    dist= dist2;
    mindist= mindist2;
    maxdist= maxdist2;
  }
  qh_mergefacet(qh, merging, merged, MRGtwisted, &mindist, &maxdist, !qh_MERGEapex);
  /* caller merges qh_degenredundant */
  zinc_(Ztwisted);
  wadd_(Wtwistedtot, dist);
  wmax_(Wtwistedmax, dist);
} /* merge_twisted */

/*---------------------------------

  qh_mergecycle(qh, samecycle, newfacet )
    merge a cycle of facets starting at samecycle into a newfacet
    newfacet is a horizon facet with ->normal
    samecycle facets are simplicial from an apex

  returns:
    initializes vertex neighbors on first merge
    samecycle deleted (placed on qh.visible_list)
    newfacet at end of qh.facet_list
    deleted vertices on qh.del_vertices

  notes:
    only called by qh_mergecycle_all for multiple, same cycle facets
    see qh_mergefacet

  design:
    make vertex neighbors if necessary
    make ridges for newfacet
    merge neighbor sets of samecycle into newfacet
    merge ridges of samecycle into newfacet
    merge vertex neighbors of samecycle into newfacet
    make apex of samecycle the apex of newfacet
    if newfacet wasn't a new facet
      add its vertices to qh.newvertex_list
    delete samecycle facets a make newfacet a newfacet
*/
void qh_mergecycle(qhT *qh, facetT *samecycle, facetT *newfacet) {
  int traceonce= False, tracerestore= 0;
  vertexT *apex;
#ifndef qh_NOtrace
  facetT *same;
#endif

  zzinc_(Ztotmerge);
  if (qh->REPORTfreq2 && qh->POSTmerging) {
    if (zzval_(Ztotmerge) > qh->mergereport + qh->REPORTfreq2)
      qh_tracemerging(qh);
  }
#ifndef qh_NOtrace
  if (qh->TRACEmerge == zzval_(Ztotmerge))
    qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
  trace2((qh, qh->ferr, 2030, "qh_mergecycle: merge #%d for facets from cycle f%d into coplanar horizon f%d\n",
        zzval_(Ztotmerge), samecycle->id, newfacet->id));
  if (newfacet == qh->tracefacet) {
    tracerestore= qh->IStracing;
    qh->IStracing= 4;
    qh_fprintf(qh, qh->ferr, 8068, "qh_mergecycle: ========= trace merge %d of samecycle %d into trace f%d, furthest is p%d\n",
               zzval_(Ztotmerge), samecycle->id, newfacet->id,  qh->furthest_id);
    traceonce= True;
  }
  if (qh->IStracing >=4) {
    qh_fprintf(qh, qh->ferr, 8069, "  same cycle:");
    FORALLsame_cycle_(samecycle)
      qh_fprintf(qh, qh->ferr, 8070, " f%d", same->id);
    qh_fprintf(qh, qh->ferr, 8071, "\n");
  }
  if (qh->IStracing >=4)
    qh_errprint(qh, "MERGING CYCLE", samecycle, newfacet, NULL, NULL);
#endif /* !qh_NOtrace */
  if (newfacet->tricoplanar) {
    if (!qh->TRInormals) {
      qh_fprintf(qh, qh->ferr, 6224, "qhull internal error (qh_mergecycle): does not work for tricoplanar facets.  Use option 'Q11'\n");
      qh_errexit(qh, qh_ERRqhull, newfacet, NULL);
    }
    newfacet->tricoplanar= False;
    newfacet->keepcentrum= False;
  }
  if (qh->CHECKfrequently)
    qh_checkdelridge(qh);
  if (!qh->VERTEXneighbors)
    qh_vertexneighbors(qh);
  apex= SETfirstt_(samecycle->vertices, vertexT);
  qh_makeridges(qh, newfacet);
  qh_mergecycle_neighbors(qh, samecycle, newfacet);
  qh_mergecycle_ridges(qh, samecycle, newfacet);
  qh_mergecycle_vneighbors(qh, samecycle, newfacet);
  if (SETfirstt_(newfacet->vertices, vertexT) != apex)
    qh_setaddnth(qh, &newfacet->vertices, 0, apex);  /* apex has last id */
  if (!newfacet->newfacet)
    qh_newvertices(qh, newfacet->vertices);
  qh_mergecycle_facets(qh, samecycle, newfacet);
  qh_tracemerge(qh, samecycle, newfacet, MRGcoplanarhorizon);
  /* check for degen_redundant_neighbors after qh_forcedmerges() */
  if (traceonce) {
    qh_fprintf(qh, qh->ferr, 8072, "qh_mergecycle: end of trace facet\n");
    qh->IStracing= tracerestore;
  }
} /* mergecycle */

/*---------------------------------

  qh_mergecycle_all(qh, facetlist, wasmerge )
    merge all samecycles of coplanar facets into horizon
    don't merge facets with ->mergeridge (these already have ->normal)
    all facets are simplicial from apex
    all facet->cycledone == False

  returns:
    all newfacets merged into coplanar horizon facets
    deleted vertices on  qh.del_vertices
    sets wasmerge if any merge

  notes:
    called by qh_premerge
    calls qh_mergecycle for multiple, same cycle facets

  design:
    for each facet on facetlist
      skip facets with dupridges 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 dupridges from samecycle
        merge samecycle into horizon (deletes facets from facetlist)
*/
void qh_mergecycle_all(qhT *qh, facetT *facetlist, boolT *wasmerge) {
  facetT *facet, *same, *prev, *horizon, *newfacet;
  facetT *samecycle= NULL, *nextfacet, *nextsame;
  vertexT *apex, *vertex, **vertexp;
  int cycles=0, total=0, facets, nummerge, numdegen= 0;

  trace2((qh, qh->ferr, 2031, "qh_mergecycle_all: merge new facets into coplanar horizon facets.  Bulk merge a cycle of facets with the same horizon facet\n"));
  for (facet=facetlist; facet && (nextfacet= facet->next); facet= nextfacet) {
    if (facet->normal)
      continue;
    if (!facet->mergehorizon) {
      qh_fprintf(qh, qh->ferr, 6225, "qhull internal error (qh_mergecycle_all): f%d without normal\n", facet->id);
      qh_errexit(qh, qh_ERRqhull, facet, NULL);
    }
    horizon= SETfirstt_(facet->neighbors, facetT);
    if (facet->f.samecycle == facet) {
      if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
        qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
      zinc_(Zonehorizon);
      /* merge distance done in qh_findhorizon */
      apex= SETfirstt_(facet->vertices, vertexT);
      FOREACHvertex_(facet->vertices) {
        if (vertex != apex)
          vertex->delridge= True;
      }
      horizon->f.newcycle= NULL;
      qh_mergefacet(qh, facet, horizon, MRGcoplanarhorizon, NULL, NULL, qh_MERGEapex);
    }else {
      samecycle= facet;
      facets= 0;
      prev= facet;
      for (same= facet->f.samecycle; same;  /* FORALLsame_cycle_(facet) */
           same= (same == facet ? NULL :nextsame)) { /* ends at facet */
        nextsame= same->f.samecycle;
        if (same->cycledone || same->visible)
          qh_infiniteloop(qh, same);
        same->cycledone= True;
        if (same->normal) {
          prev->f.samecycle= same->f.samecycle; /* unlink ->mergeridge */
          same->f.samecycle= NULL;
        }else {
          prev= same;
          facets++;
        }
      }
      while (nextfacet && nextfacet->cycledone)  /* will delete samecycle */
        nextfacet= nextfacet->next;
      horizon->f.newcycle= NULL;
      qh_mergecycle(qh, samecycle, horizon);
      nummerge= horizon->nummerge + facets;
      if (nummerge > qh_MAXnummerge)
        horizon->nummerge= qh_MAXnummerge;
      else
        horizon->nummerge= (short unsigned int)nummerge; /* limited to 9 bits by qh_MAXnummerge, -Wconversion */
      zzinc_(Zcyclehorizon);
      total += facets;
      zzadd_(Zcyclefacettot, facets);
      zmax_(Zcyclefacetmax, facets);
    }
    cycles++;
  }
  if (cycles) {
    FORALLnew_facets {
      /* qh_maybe_duplicateridges postponed since qh_mergecycle_ridges deletes ridges without calling qh_delridge_merge */
      if (newfacet->coplanarhorizon) {
        qh_test_redundant_neighbors(qh, newfacet);
        qh_maybe_duplicateridges(qh, newfacet);
        newfacet->coplanarhorizon= False;
      }
    }
    numdegen += qh_merge_degenredundant(qh);
    *wasmerge= True;
    trace1((qh, qh->ferr, 1013, "qh_mergecycle_all: merged %d same cycles or facets into coplanar horizons and %d degenredundant facets\n",
      cycles, numdegen));
  }
} /* mergecycle_all */

/*---------------------------------

  qh_mergecycle_facets(qh, samecycle, newfacet )
    finish merge of samecycle into newfacet

  returns:
    samecycle prepended to visible_list for later deletion and partitioning
      each facet->f.replace == newfacet

    newfacet moved to end of qh.facet_list
      makes newfacet a newfacet (get's facet1->id if it was old)
      sets newfacet->newmerge
      clears newfacet->center (unless merging into a large facet)
      clears newfacet->tested and ridge->tested for facet1

    adds neighboring facets to facet_mergeset if redundant or degenerate

  design:
    make newfacet a new facet and set its flags
    move samecycle facets to qh.visible_list for later deletion
    unless newfacet is large
      remove its centrum
*/
void qh_mergecycle_facets(qhT *qh, facetT *samecycle, facetT *newfacet) {
  facetT *same, *next;

  trace4((qh, qh->ferr, 4030, "qh_mergecycle_facets: make newfacet new and samecycle deleted\n"));
  qh_removefacet(qh, newfacet);  /* append as a newfacet to end of qh->facet_list */
  qh_appendfacet(qh, newfacet);
  newfacet->newfacet= True;
  newfacet->simplicial= False;
  newfacet->newmerge= True;

  for (same= samecycle->f.samecycle; same; same= (same == samecycle ?  NULL : next)) {
    next= same->f.samecycle;  /* reused by willdelete */
    qh_willdelete(qh, same, newfacet);
  }
  if (newfacet->center
      && qh_setsize(qh, newfacet->vertices) <= qh->hull_dim + qh_MAXnewcentrum) {
    qh_memfree(qh, newfacet->center, qh->normal_size);
    newfacet->center= NULL;
  }
  trace3((qh, qh->ferr, 3004, "qh_mergecycle_facets: merged facets from cycle f%d into f%d\n",
             samecycle->id, newfacet->id));
} /* mergecycle_facets */

/*---------------------------------

  qh_mergecycle_neighbors(qh, samecycle, newfacet )
    add neighbors for samecycle facets to newfacet

  returns:
    newfacet with updated neighbors and vice-versa
    newfacet has ridges
    all neighbors of newfacet marked with qh.visit_id
    samecycle facets marked with qh.visit_id-1
    ridges updated for simplicial neighbors of samecycle with a ridge

  notes:
    assumes newfacet not in samecycle
    usually, samecycle facets are new, simplicial facets without internal ridges
      not so if horizon facet is coplanar to two different samecycles

  see:
    qh_mergeneighbors()

  design:
    check samecycle
    delete neighbors from newfacet that are also in samecycle
    for each neighbor of a facet in samecycle
      if neighbor is simplicial
        if first visit
          move the neighbor relation to newfacet
          update facet links for its ridges
        else
          make ridges for neighbor
          remove samecycle reference
      else
        update neighbor sets
*/
void qh_mergecycle_neighbors(qhT *qh, facetT *samecycle, facetT *newfacet) {
  facetT *same, *neighbor, **neighborp;
  int delneighbors= 0, newneighbors= 0;
  unsigned int samevisitid;
  ridgeT *ridge, **ridgep;

  samevisitid= ++qh->visit_id;
  FORALLsame_cycle_(samecycle) {
    if (same->visitid == samevisitid || same->visible)
      qh_infiniteloop(qh, samecycle);
    same->visitid= samevisitid;
  }
  newfacet->visitid= ++qh->visit_id;
  trace4((qh, qh->ferr, 4031, "qh_mergecycle_neighbors: delete shared neighbors from newfacet\n"));
  FOREACHneighbor_(newfacet) {
    if (neighbor->visitid == samevisitid) {
      SETref_(neighbor)= NULL;  /* samecycle neighbors deleted */
      delneighbors++;
    }else
      neighbor->visitid= qh->visit_id;
  }
  qh_setcompact(qh, newfacet->neighbors);

  trace4((qh, qh->ferr, 4032, "qh_mergecycle_neighbors: update neighbors\n"));
  FORALLsame_cycle_(samecycle) {
    FOREACHneighbor_(same) {
      if (neighbor->visitid == samevisitid)
        continue;
      if (neighbor->simplicial) {
        if (neighbor->visitid != qh->visit_id) {
          qh_setappend(qh, &newfacet->neighbors, neighbor);
          qh_setreplace(qh, neighbor->neighbors, same, newfacet);
          newneighbors++;
          neighbor->visitid= qh->visit_id;
          FOREACHridge_(neighbor->ridges) { /* update ridge in case of qh_makeridges */
            if (ridge->top == same) {
              ridge->top= newfacet;
              break;
            }else if (ridge->bottom == same) {
              ridge->bottom= newfacet;
              break;
            }
          }
        }else {
          qh_makeridges(qh, neighbor);
          qh_setdel(neighbor->neighbors, same);
          /* same can't be horizon facet for neighbor */
        }
      }else { /* non-simplicial neighbor */
        qh_setdel(neighbor->neighbors, same);
        if (neighbor->visitid != qh->visit_id) {
          qh_setappend(qh, &neighbor->neighbors, newfacet);
          qh_setappend(qh, &newfacet->neighbors, neighbor);
          neighbor->visitid= qh->visit_id;
          newneighbors++;
        }
      }
    }
  }
  trace2((qh, qh->ferr, 2032, "qh_mergecycle_neighbors: deleted %d neighbors and added %d\n",
             delneighbors, newneighbors));
} /* mergecycle_neighbors */

/*---------------------------------

  qh_mergecycle_ridges(qh, samecycle, newfacet )
    add ridges/neighbors for facets in samecycle to newfacet
    all new/old neighbors of newfacet marked with qh.visit_id
    facets in samecycle marked with qh.visit_id-1
    newfacet marked with qh.visit_id

  returns:
    newfacet has merged ridges

  notes:
    ridge already updated for simplicial neighbors of samecycle with a ridge
    qh_checkdelridge called by qh_mergecycle

  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 simplicial facet
        for each neighbor of facet
          if simplicial facet
          and not samecycle facet or newfacet
            make ridge between neighbor and newfacet
*/
void qh_mergecycle_ridges(qhT *qh, facetT *samecycle, facetT *newfacet) {
  facetT *same, *neighbor= NULL;
  int numold=0, numnew=0;
  int neighbor_i, neighbor_n;
  unsigned int samevisitid;
  ridgeT *ridge, **ridgep;
  boolT toporient;
  void **freelistp; /* used if !qh_NOmem by qh_memfree_() */

  trace4((qh, qh->ferr, 4033, "qh_mergecycle_ridges: delete shared ridges from newfacet\n"));
  samevisitid= qh->visit_id -1;
  FOREACHridge_(newfacet->ridges) {
    neighbor= otherfacet_(ridge, newfacet);
    if (neighbor->visitid == samevisitid)
      SETref_(ridge)= NULL; /* ridge free'd below */
  }
  qh_setcompact(qh, newfacet->ridges);

  trace4((qh, qh->ferr, 4034, "qh_mergecycle_ridges: add ridges to newfacet\n"));
  FORALLsame_cycle_(samecycle) {
    FOREACHridge_(same->ridges) {
      if (ridge->top == same) {
        ridge->top= newfacet;
        neighbor= ridge->bottom;
      }else if (ridge->bottom == same) {
        ridge->bottom= newfacet;
        neighbor= ridge->top;
      }else if (ridge->top == newfacet || ridge->bottom == newfacet) {
        qh_setappend(qh, &newfacet->ridges, ridge);
        numold++;  /* already set by qh_mergecycle_neighbors */
        continue;
      }else {
        qh_fprintf(qh, qh->ferr, 6098, "qhull internal error (qh_mergecycle_ridges): bad ridge r%d\n", ridge->id);
        qh_errexit(qh, qh_ERRqhull, NULL, ridge);
      }
      if (neighbor == newfacet) {
        if (qh->traceridge == ridge)
          qh->traceridge= NULL;
        qh_setfree(qh, &(ridge->vertices));
        qh_memfree_(qh, ridge, (int)sizeof(ridgeT), freelistp);
        numold++;
      }else if (neighbor->visitid == samevisitid) {
        qh_setdel(neighbor->ridges, ridge);
        if (qh->traceridge == ridge)
          qh->traceridge= NULL;
        qh_setfree(qh, &(ridge->vertices));
        qh_memfree_(qh, ridge, (int)sizeof(ridgeT), freelistp);
        numold++;
      }else {
        qh_setappend(qh, &newfacet->ridges, ridge);
        numold++;
      }
    }
    if (same->ridges)
      qh_settruncate(qh, same->ridges, 0);
    if (!same->simplicial)
      continue;
    FOREACHneighbor_i_(qh, same) {       /* note: !newfact->simplicial */
      if (neighbor->visitid != samevisitid && neighbor->simplicial) {
        ridge= qh_newridge(qh);
        ridge->vertices= qh_setnew_delnthsorted(qh, same->vertices, qh->hull_dim,
                                                          neighbor_i, 0);
        toporient= (boolT)(same->toporient ^ (neighbor_i & 0x1));
        if (toporient) {
          ridge->top= newfacet;
          ridge->bottom= neighbor;
          ridge->simplicialbot= True;
        }else {
          ridge->top= neighbor;
          ridge->bottom= newfacet;
          ridge->simplicialtop= True;
        }
        qh_setappend(qh, &(newfacet->ridges), ridge);
        qh_setappend(qh, &(neighbor->ridges), ridge);
        if (qh->ridge_id == qh->traceridge_id)
          qh->traceridge= ridge;
        numnew++;
      }
    }
  }

  trace2((qh, qh->ferr, 2033, "qh_mergecycle_ridges: found %d old ridges and %d new ones\n",
             numold, numnew));
} /* mergecycle_ridges */

/*---------------------------------

  qh_mergecycle_vneighbors(qh, samecycle, newfacet )
    create vertex neighbors for newfacet from vertices of facets in samecycle
    samecycle marked with visitid == qh.visit_id - 1

  returns:
    newfacet vertices with updated neighbors
    marks newfacet with qh.visit_id-1
    deletes vertices that are merged away
    sets delridge on all vertices (faster here than in mergecycle_ridges)

  see:
    qh_mergevertex_neighbors()

  design:
    for each vertex of samecycle facet
      set vertex->delridge
      delete samecycle facets from vertex neighbors
      append newfacet to vertex neighbors
      if vertex only in newfacet
        delete it from newfacet
        add it to qh.del_vertices for later deletion
*/
void qh_mergecycle_vneighbors(qhT *qh, facetT *samecycle, facetT *newfacet) {
  facetT *neighbor, **neighborp;
  unsigned int mergeid;
  vertexT *vertex, **vertexp, *apex;
  setT *vertices;

  trace4((qh, qh->ferr, 4035, "qh_mergecycle_vneighbors: update vertex neighbors for newfacet\n"));
  mergeid= qh->visit_id - 1;
  newfacet->visitid= mergeid;
  vertices= qh_basevertices(qh, samecycle); /* temp */
  apex= SETfirstt_(samecycle->vertices, vertexT);
  qh_setappend(qh, &vertices, apex);
  FOREACHvertex_(vertices) {
    vertex->delridge= True;
    FOREACHneighbor_(vertex) {
      if (neighbor->visitid == mergeid)
        SETref_(neighbor)= NULL;
    }
    qh_setcompact(qh, vertex->neighbors);
    qh_setappend(qh, &vertex->neighbors, newfacet);
    if (!SETsecond_(vertex->neighbors)) {
      zinc_(Zcyclevertex);
      trace2((qh, qh->ferr, 2034, "qh_mergecycle_vneighbors: deleted v%d when merging cycle f%d into f%d\n",
        vertex->id, samecycle->id, newfacet->id));
      qh_setdelsorted(newfacet->vertices, vertex);
      vertex->deleted= True;
      qh_setappend(qh, &qh->del_vertices, vertex);
    }
  }
  qh_settempfree(qh, &vertices);
  trace3((qh, qh->ferr, 3005, "qh_mergecycle_vneighbors: merged vertices from cycle f%d into f%d\n",
             samecycle->id, newfacet->id));
} /* mergecycle_vneighbors */

/*---------------------------------

  qh_mergefacet(qh, facet1, facet2, mergetype, mindist, maxdist, mergeapex )
    merges facet1 into facet2
    mergeapex==qh_MERGEapex if merging new facet into coplanar horizon (optimizes qh_mergesimplex)

  returns:
    qh.max_outside and qh.min_vertex updated
    initializes vertex neighbors on first merge

  note:
    mergetype only used for logging and error reporting

  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:
    when done, tests facet1 and facet2 for degenerate or redundant neighbors and dupridges
    mindist/maxdist may be NULL (only if both NULL)
    traces merge if fmax_(maxdist,-mindist) > TRACEdist

  see:
    qh_mergecycle()

  design:
    trace merge and check for degenerate simplex
    make ridges for both facets
    update qh.max_outside, qh.max_vertex, qh.min_vertex
    update facet2->maxoutside and keepcentrum
    update facet2->nummerge
    update tested flags for facet2
    if facet1 is simplicial
      merge facet1 into facet2
    else
      merge facet1's neighbors into facet2
      merge facet1's ridges into facet2
      merge facet1's vertices into facet2
      merge facet1's vertex neighbors into facet2
      add facet2's vertices to qh.new_vertexlist
    move facet2 to end of qh.newfacet_list
    unless MRGcoplanarhorizon
      test facet2 for redundant neighbors
      test facet1 for degenerate neighbors
      test for redundant facet2
      maybe test for duplicate ridges ('Q15')
    move facet1 to qh.visible_list for later deletion
*/
void qh_mergefacet(qhT *qh, facetT *facet1, facetT *facet2, mergeType mergetype, realT *mindist, realT *maxdist, boolT mergeapex) {
  boolT traceonce= False;
  vertexT *vertex, **vertexp;
  realT mintwisted, vertexdist;
  realT onemerge;
  int tracerestore=0, nummerge;
  const char *mergename;

  if(mergetype > 0 && mergetype < sizeof(mergetypes)/sizeof(char *))
    mergename= mergetypes[mergetype];
  else
    mergename= mergetypes[MRGnone];
  if (facet1->tricoplanar || facet2->tricoplanar) {
    if (!qh->TRInormals) {
      qh_fprintf(qh, qh->ferr, 6226, "qhull internal error (qh_mergefacet): merge f%d into f%d for mergetype %d (%s) does not work for tricoplanar facets.  Use option 'Q11'\n",
        facet1->id, facet2->id, mergetype, mergename);
      qh_errexit2(qh, qh_ERRqhull, facet1, facet2);
    }
    if (facet2->tricoplanar) {
      facet2->tricoplanar= False;
      facet2->keepcentrum= False;
    }
  }
  zzinc_(Ztotmerge);
  if (qh->REPORTfreq2 && qh->POSTmerging) {
    if (zzval_(Ztotmerge) > qh->mergereport + qh->REPORTfreq2)
      qh_tracemerging(qh);
  }
#ifndef qh_NOtrace
  if (qh->build_cnt >= qh->RERUN) {
    if (mindist && (-*mindist > qh->TRACEdist || *maxdist > qh->TRACEdist)) {
      tracerestore= 0;
      qh->IStracing= qh->TRACElevel;
      traceonce= True;
      qh_fprintf(qh, qh->ferr, 8075, "qh_mergefacet: ========= trace wide merge #%d(%2.2g) for f%d into f%d for mergetype %d (%s), last point was p%d\n",
          zzval_(Ztotmerge), fmax_(-*mindist, *maxdist), facet1->id, facet2->id, mergetype, mergename, qh->furthest_id);
    }else if (facet1 == qh->tracefacet || facet2 == qh->tracefacet) {
      tracerestore= qh->IStracing;
      qh->IStracing= 4;
      traceonce= True;
      qh_fprintf(qh, qh->ferr, 8076, "qh_mergefacet: ========= trace merge #%d for f%d into f%d for mergetype %d (%s), furthest is p%d\n",
                 zzval_(Ztotmerge), facet1->id, facet2->id, mergetype, mergename, qh->furthest_id);
    }
  }
  if (qh->IStracing >= 2) {
    realT mergemin= -2;
    realT mergemax= -2;

    if (mindist) {
      mergemin= *mindist;
      mergemax= *maxdist;
    }
    qh_fprintf(qh, qh->ferr, 2081, "qh_mergefacet: #%d merge f%d into f%d for merge for mergetype %d (%s), mindist= %2.2g, maxdist= %2.2g, max_outside %2.2g\n",
    zzval_(Ztotmerge), facet1->id, facet2->id, mergetype, mergename, mergemin, mergemax, qh->max_outside);
  }
#endif /* !qh_NOtrace */
  if(!qh->ALLOWwide && mindist) {
    mintwisted= qh_WIDEmaxoutside * qh->ONEmerge;  /* same as qh_merge_twisted and qh_check_maxout (poly2) */
    maximize_(mintwisted, facet1->maxoutside);
    maximize_(mintwisted, facet2->maxoutside);
    if (*maxdist > mintwisted || -*mindist > mintwisted) {
      vertexdist= qh_vertex_bestdist(qh, facet1->vertices);
      onemerge= qh->ONEmerge + qh->DISTround;
      if (vertexdist > mintwisted) {
        qh_fprintf(qh, qh->ferr, 6347, "qhull precision error (qh_mergefacet): wide merge for facet f%d into f%d for mergetype %d (%s).  maxdist %2.2g (%.1fx) mindist %2.2g (%.1fx) vertexdist %2.2g  Allow with 'Q12' (allow-wide)\n",
          facet1->id, facet2->id, mergetype, mergename, *maxdist, *maxdist/onemerge, *mindist, -*mindist/onemerge, vertexdist);
      }else {
        qh_fprintf(qh, qh->ferr, 6348, "qhull precision error (qh_mergefacet): wide merge for pinched facet f%d into f%d for mergetype %d (%s).  maxdist %2.2g (%.fx) mindist %2.2g (%.1fx) vertexdist %2.2g  Allow with 'Q12' (allow-wide)\n",
          facet1->id, facet2->id, mergetype, mergename, *maxdist, *maxdist/onemerge, *mindist, -*mindist/onemerge, vertexdist);
      }
      qh_errexit2(qh, qh_ERRwide, facet1, facet2);
    }
  }
  if (facet1 == facet2 || facet1->visible || facet2->visible) {
    qh_fprintf(qh, qh->ferr, 6099, "qhull internal error (qh_mergefacet): either f%d and f%d are the same or one is a visible facet, mergetype %d (%s)\n",
             facet1->id, facet2->id, mergetype, mergename);
    qh_errexit2(qh, qh_ERRqhull, facet1, facet2);
  }
  if (qh->num_facets - qh->num_visible <= qh->hull_dim + 1) {
    qh_fprintf(qh, qh->ferr, 6227, "qhull topology error: Only %d facets remain.  The input is too degenerate or the convexity constraints are too strong.\n", 
          qh->hull_dim+1);
    if (qh->hull_dim >= 5 && !qh->MERGEexact)
      qh_fprintf(qh, qh->ferr, 8079, "    Option 'Qx' may avoid this problem.\n");
    qh_errexit(qh, qh_ERRtopology, NULL, NULL);
  }
  if (!qh->VERTEXneighbors)
    qh_vertexneighbors(qh);
  qh_makeridges(qh, facet1);
  qh_makeridges(qh, facet2);
  if (qh->IStracing >=4)
    qh_errprint(qh, "MERGING", facet1, facet2, NULL, NULL);
  if (mindist) {
    maximize_(qh->max_outside, *maxdist);
    maximize_(qh->max_vertex, *maxdist);
#if qh_MAXoutside
    maximize_(facet2->maxoutside, *maxdist);
#endif
    minimize_(qh->min_vertex, *mindist);
    if (!facet2->keepcentrum
    && (*maxdist > qh->WIDEfacet || *mindist < -qh->WIDEfacet)) {
      facet2->keepcentrum= True;
      zinc_(Zwidefacet);
    }
  }
  nummerge= facet1->nummerge + facet2->nummerge + 1;
  if (nummerge >= qh_MAXnummerge)
    facet2->nummerge= qh_MAXnummerge;
  else
    facet2->nummerge= (short unsigned int)nummerge; /* limited to 9 bits by qh_MAXnummerge, -Wconversion */
  facet2->newmerge= True;
  facet2->dupridge= False;
  qh_updatetested(qh, facet1, facet2);
  if (qh->hull_dim > 2 && qh_setsize(qh, facet1->vertices) == qh->hull_dim)
    qh_mergesimplex(qh, facet1, facet2, mergeapex);
  else {
    qh->vertex_visit++;
    FOREACHvertex_(facet2->vertices)
      vertex->visitid= qh->vertex_visit;
    if (qh->hull_dim == 2)
      qh_mergefacet2d(qh, facet1, facet2);
    else {
      qh_mergeneighbors(qh, facet1, facet2);
      qh_mergevertices(qh, facet1->vertices, &facet2->vertices);
    }
    qh_mergeridges(qh, facet1, facet2);
    qh_mergevertex_neighbors(qh, facet1, facet2);
    if (!facet2->newfacet)
      qh_newvertices(qh, facet2->vertices);
  }
  if (facet2->coplanarhorizon) {
    zinc_(Zmergeintocoplanar);
  }else if (!facet2->newfacet) {
    zinc_(Zmergeintohorizon);
  }else if (!facet1->newfacet && facet2->newfacet) {
    zinc_(Zmergehorizon);
  }else {
    zinc_(Zmergenew);
  }
  qh_removefacet(qh, facet2);  /* append as a newfacet to end of qh->facet_list */
  qh_appendfacet(qh, facet2);
  facet2->newfacet= True;
  facet2->tested= False;
  qh_tracemerge(qh, facet1, facet2, mergetype);
  if (traceonce) {
    qh_fprintf(qh, qh->ferr, 8080, "qh_mergefacet: end of wide tracing\n");
    qh->IStracing= tracerestore;
  }
  if (mergetype != MRGcoplanarhorizon) {
    trace3((qh, qh->ferr, 3076, "qh_mergefacet: check f%d and f%d for redundant and degenerate neighbors\n",
        facet1->id, facet2->id));
    qh_test_redundant_neighbors(qh, facet2);
    qh_test_degen_neighbors(qh, facet1);  /* after qh_test_redundant_neighbors since MRGdegen more difficult than MRGredundant
                                             and before qh_willdelete which clears facet1.neighbors */
    qh_degen_redundant_facet(qh, facet2); /* may occur in qh_merge_pinchedvertices, e.g., rbox 175 C3,2e-13 D4 t1545228104 | qhull d */
    qh_maybe_duplicateridges(qh, facet2);
  }
  qh_willdelete(qh, facet1, facet2);
} /* mergefacet */


/*---------------------------------

  qh_mergefacet2d(qh, facet1, facet2 )
    in 2d, merges neighbors and vertices of facet1 into facet2

  returns:
    build ridges for neighbors if necessary
    facet2 looks like a simplicial facet except for centrum, ridges
      neighbors are opposite the corresponding vertex
      maintains orientation of facet2

  notes:
    qh_mergefacet() retains non-simplicial structures
      they are not needed in 2d, but later routines may use them
    preserves qh.vertex_visit for qh_mergevertex_neighbors()

  design:
    get vertices and neighbors
    determine new vertices and neighbors
    set new vertices and neighbors and adjust orientation
    make ridges for new neighbor if needed
*/
void qh_mergefacet2d(qhT *qh, facetT *facet1, facetT *facet2) {
  vertexT *vertex1A, *vertex1B, *vertex2A, *vertex2B, *vertexA, *vertexB;
  facetT *neighbor1A, *neighbor1B, *neighbor2A, *neighbor2B, *neighborA, *neighborB;

  vertex1A= SETfirstt_(facet1->vertices, vertexT);
  vertex1B= SETsecondt_(facet1->vertices, vertexT);
  vertex2A= SETfirstt_(facet2->vertices, vertexT);
  vertex2B= SETsecondt_(facet2->vertices, vertexT);
  neighbor1A= SETfirstt_(facet1->neighbors, facetT);
  neighbor1B= SETsecondt_(facet1->neighbors, facetT);
  neighbor2A= SETfirstt_(facet2->neighbors, facetT);
  neighbor2B= SETsecondt_(facet2->neighbors, facetT);
  if (vertex1A == vertex2A) {
    vertexA= vertex1B;
    vertexB= vertex2B;
    neighborA= neighbor2A;
    neighborB= neighbor1A;
  }else if (vertex1A == vertex2B) {
    vertexA= vertex1B;
    vertexB= vertex2A;
    neighborA= neighbor2B;
    neighborB= neighbor1A;
  }else if (vertex1B == vertex2A) {
    vertexA= vertex1A;
    vertexB= vertex2B;
    neighborA= neighbor2A;
    neighborB= neighbor1B;
  }else { /* 1B == 2B */
    vertexA= vertex1A;
    vertexB= vertex2A;
    neighborA= neighbor2B;
    neighborB= neighbor1B;
  }
  /* vertexB always from facet2, neighborB always from facet1 */
  if (vertexA->id > vertexB->id) {
    SETfirst_(facet2->vertices)= vertexA;
    SETsecond_(facet2->vertices)= vertexB;
    if (vertexB == vertex2A)
      facet2->toporient= !facet2->toporient;
    SETfirst_(facet2->neighbors)= neighborA;
    SETsecond_(facet2->neighbors)= neighborB;
  }else {
    SETfirst_(facet2->vertices)= vertexB;
    SETsecond_(facet2->vertices)= vertexA;
    if (vertexB == vertex2B)
      facet2->toporient= !facet2->toporient;
    SETfirst_(facet2->neighbors)= neighborB;
    SETsecond_(facet2->neighbors)= neighborA;
  }
  /* qh_makeridges not needed since neighborB is not degenerate */
  qh_setreplace(qh, neighborB->neighbors, facet1, facet2);
  trace4((qh, qh->ferr, 4036, "qh_mergefacet2d: merged v%d and neighbor f%d of f%d into f%d\n",
       vertexA->id, neighborB->id, facet1->id, facet2->id));
} /* mergefacet2d */


/*---------------------------------

  qh_mergeneighbors(qh, facet1, facet2 )
    merges the neighbors of facet1 into facet2

  notes:
    only called by qh_mergefacet
    qh.hull_dim >= 3
    see qh_mergecycle_neighbors

  design:
    for each neighbor of facet1
      if neighbor is also a neighbor of facet2
        if neighbor is simplicial
          make ridges for later deletion as a degenerate facet
        update its neighbor set
      else
        move the neighbor relation to facet2
    remove the neighbor relation for facet1 and facet2
*/
void qh_mergeneighbors(qhT *qh, facetT *facet1, facetT *facet2) {
  facetT *neighbor, **neighborp;

  trace4((qh, qh->ferr, 4037, "qh_mergeneighbors: merge neighbors of f%d and f%d\n",
          facet1->id, facet2->id));
  qh->visit_id++;
  FOREACHneighbor_(facet2) {
    neighbor->visitid= qh->visit_id;
  }
  FOREACHneighbor_(facet1) {
    if (neighbor->visitid == qh->visit_id) {
      if (neighbor->simplicial)    /* is degen, needs ridges */
        qh_makeridges(qh, neighbor);
      if (SETfirstt_(neighbor->neighbors, facetT) != facet1) /*keep newfacet->horizon*/
        qh_setdel(neighbor->neighbors, facet1);
      else {
        qh_setdel(neighbor->neighbors, facet2);
        qh_setreplace(qh, neighbor->neighbors, facet1, facet2);
      }
    }else if (neighbor != facet2) {
      qh_setappend(qh, &(facet2->neighbors), neighbor);
      qh_setreplace(qh, neighbor->neighbors, facet1, facet2);
    }
  }
  qh_setdel(facet1->neighbors, facet2);  /* here for makeridges */
  qh_setdel(facet2->neighbors, facet1);
} /* mergeneighbors */


/*---------------------------------

  qh_mergeridges(qh, facet1, facet2 )
    merges the ridge set of facet1 into facet2

  returns:
    may delete all ridges for a vertex
    sets vertex->delridge on deleted ridges

  see:
    qh_mergecycle_ridges()

  design:
    delete ridges between facet1 and facet2
      mark (delridge) vertices on these ridges for later testing
    for each remaining ridge
      rename facet1 to facet2
*/
void qh_mergeridges(qhT *qh, facetT *facet1, facetT *facet2) {
  ridgeT *ridge, **ridgep;

  trace4((qh, qh->ferr, 4038, "qh_mergeridges: merge ridges of f%d into f%d\n",
          facet1->id, facet2->id));
  FOREACHridge_(facet2->ridges) {
    if ((ridge->top == facet1) || (ridge->bottom == facet1)) {
      /* ridge.nonconvex is irrelevant due to merge */
      qh_delridge_merge(qh, ridge);  /* expensive in high-d, could rebuild */
      ridgep--; /* deleted this ridge, repeat with next ridge*/
    }
  }
  FOREACHridge_(facet1->ridges) {
    if (ridge->top == facet1) {
      ridge->top= facet2;
      ridge->simplicialtop= False;
    }else { /* ridge.bottom is facet1 */
      ridge->bottom= facet2;
      ridge->simplicialbot= False;
    }
    qh_setappend(qh, &(facet2->ridges), ridge);
  }
} /* mergeridges */


/*---------------------------------

  qh_mergesimplex(qh, facet1, facet2, mergeapex )
    merge simplicial facet1 into facet2
    mergeapex==qh_MERGEapex if merging samecycle into horizon facet
      vertex id is latest (most recently created)
    facet1 may be contained in facet2
    ridges exist for both facets

  returns:
    facet2 with updated vertices, ridges, neighbors
    updated neighbors for facet1's vertices
    facet1 not deleted
    sets vertex->delridge on deleted ridges

  notes:
    special case code since this is the most common merge
    called from qh_mergefacet()

  design:
    if qh_MERGEapex
      add vertices of facet2 to qh.new_vertexlist if necessary
      add apex to facet2
    else
      for each ridge between facet1 and facet2
        set vertex->delridge
      determine the apex for facet1 (i.e., vertex to be merged)
      unless apex already in facet2
        insert apex into vertices for facet2
      add vertices of facet2 to qh.new_vertexlist if necessary
      add apex to qh.new_vertexlist if necessary
      for each vertex of facet1
        if apex
          rename facet1 to facet2 in its vertex neighbors
        else
          delete facet1 from vertex neighbors
          if only in facet2
            add vertex to qh.del_vertices for later deletion
      for each ridge of facet1
        delete ridges between facet1 and facet2
        append other ridges to facet2 after renaming facet to facet2
*/
void qh_mergesimplex(qhT *qh, facetT *facet1, facetT *facet2, boolT mergeapex) {
  vertexT *vertex, **vertexp, *opposite;
  ridgeT *ridge, **ridgep;
  boolT isnew= False;
  facetT *neighbor, **neighborp, *otherfacet;

  if (mergeapex) {
    opposite= SETfirstt_(facet1->vertices, vertexT); /* apex is opposite facet2.  It has the last vertex id */
    trace4((qh, qh->ferr, 4086, "qh_mergesimplex: merge apex v%d of f%d into facet f%d\n",
      opposite->id, facet1->id, facet2->id));
    if (!facet2->newfacet)
      qh_newvertices(qh, facet2->vertices);  /* apex, the first vertex, is already new */
    if (SETfirstt_(facet2->vertices, vertexT) != opposite) {
      qh_setaddnth(qh, &facet2->vertices, 0, opposite);
      isnew= 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 */
    }
    opposite= vertex;
    trace4((qh, qh->ferr, 4039, "qh_mergesimplex: merge opposite v%d of f%d into facet f%d\n",
          opposite->id, facet1->id, facet2->id));
    isnew= qh_addfacetvertex(qh, facet2, opposite);
    if (!facet2->newfacet)
      qh_newvertices(qh, facet2->vertices);
    else if (!opposite->newfacet) {
      qh_removevertex(qh, opposite);
      qh_appendvertex(qh, opposite);
    }
  }
  trace4((qh, qh->ferr, 4040, "qh_mergesimplex: update vertex neighbors of f%d\n",
          facet1->id));
  FOREACHvertex_(facet1->vertices) {
    if (vertex == opposite && isnew)
      qh_setreplace(qh, vertex->neighbors, facet1, facet2);
    else {
      qh_setdel(vertex->neighbors, facet1);
      if (!SETsecond_(vertex->neighbors))
        qh_mergevertex_del(qh, vertex, facet1, facet2);
    }
  }
  trace4((qh, qh->ferr, 4041, "qh_mergesimplex: merge ridges and neighbors of f%d into f%d\n",
          facet1->id, facet2->id));
  qh->visit_id++;
  FOREACHneighbor_(facet2)
    neighbor->visitid= qh->visit_id;
  FOREACHridge_(facet1->ridges) {
    otherfacet= otherfacet_(ridge, facet1);
    if (otherfacet == facet2) {
      /* ridge.nonconvex is irrelevant due to merge */
      qh_delridge_merge(qh, ridge);  /* expensive in high-d, could rebuild */
      ridgep--; /* deleted this ridge, repeat with next ridge*/
      qh_setdel(facet2->neighbors, facet1); /* a simplicial facet may have duplicate neighbors, need to delete each one */
    }else if (otherfacet->dupridge && !qh_setin(otherfacet->neighbors, facet1)) {
      qh_fprintf(qh, qh->ferr, 6356, "qhull topology error (qh_mergesimplex): f%d is a dupridge of f%d, cannot merge f%d into f%d\n",
        facet1->id, otherfacet->id, facet1->id, facet2->id);
      qh_errexit2(qh, qh_ERRqhull, facet1, otherfacet);
    }else {
      trace4((qh, qh->ferr, 4059, "qh_mergesimplex: move r%d with f%d to f%d, new neighbor? %d, maybe horizon? %d\n",
        ridge->id, otherfacet->id, facet2->id, (otherfacet->visitid != qh->visit_id), (SETfirstt_(otherfacet->neighbors, facetT) == facet1)));
      qh_setappend(qh, &facet2->ridges, ridge);
      if (otherfacet->visitid != qh->visit_id) {
        qh_setappend(qh, &facet2->neighbors, otherfacet);
        qh_setreplace(qh, otherfacet->neighbors, facet1, facet2);
        otherfacet->visitid= qh->visit_id;
      }else {
        if (otherfacet->simplicial)    /* is degen, needs ridges */
          qh_makeridges(qh, otherfacet);
        if (SETfirstt_(otherfacet->neighbors, facetT) == facet1) {
          /* keep new, otherfacet->neighbors->horizon */
          qh_setdel(otherfacet->neighbors, facet2);
          qh_setreplace(qh, otherfacet->neighbors, facet1, facet2);
        }else {
          /* facet2 is already a neighbor of otherfacet, by f.visitid */
          qh_setdel(otherfacet->neighbors, facet1);
        }
      }
      if (ridge->top == facet1) { /* wait until after qh_makeridges */
        ridge->top= facet2;
        ridge->simplicialtop= False;
      }else {
        ridge->bottom= facet2;
        ridge->simplicialbot= False;
      }
    }
  }
  trace3((qh, qh->ferr, 3006, "qh_mergesimplex: merged simplex f%d v%d into facet f%d\n",
          facet1->id, opposite->id, facet2->id));
} /* mergesimplex */

/*---------------------------------

  qh_mergevertex_del(qh, vertex, facet1, facet2 )
    delete a vertex because of merging facet1 into facet2

  returns:
    deletes vertex from facet2
    adds vertex to qh.del_vertices for later deletion
*/
void qh_mergevertex_del(qhT *qh, vertexT *vertex, facetT *facet1, facetT *facet2) {

  zinc_(Zmergevertex);
  trace2((qh, qh->ferr, 2035, "qh_mergevertex_del: deleted v%d when merging f%d into f%d\n",
          vertex->id, facet1->id, facet2->id));
  qh_setdelsorted(facet2->vertices, vertex);
  vertex->deleted= True;
  qh_setappend(qh, &qh->del_vertices, vertex);
} /* mergevertex_del */

/*---------------------------------

  qh_mergevertex_neighbors(qh, facet1, facet2 )
    merge the vertex neighbors of facet1 to facet2

  returns:
    if vertex is current qh.vertex_visit
      deletes facet1 from vertex->neighbors
    else
      renames facet1 to facet2 in vertex->neighbors
    deletes vertices if only one neighbor

  notes:
    assumes vertex neighbor sets are good
*/
void qh_mergevertex_neighbors(qhT *qh, facetT *facet1, facetT *facet2) {
  vertexT *vertex, **vertexp;

  trace4((qh, qh->ferr, 4042, "qh_mergevertex_neighbors: merge vertex neighborset for f%d into f%d\n",
          facet1->id, facet2->id));
  if (qh->tracevertex) {
    qh_fprintf(qh, qh->ferr, 8081, "qh_mergevertex_neighbors: of f%d into f%d at furthest p%d f0= %p\n",
             facet1->id, facet2->id, qh->furthest_id, qh->tracevertex->neighbors->e[0].p);
    qh_errprint(qh, "TRACE", NULL, NULL, NULL, qh->tracevertex);
  }
  FOREACHvertex_(facet1->vertices) {
    if (vertex->visitid != qh->vertex_visit)
      qh_setreplace(qh, vertex->neighbors, facet1, facet2);
    else {
      qh_setdel(vertex->neighbors, facet1);
      if (!SETsecond_(vertex->neighbors))
        qh_mergevertex_del(qh, vertex, facet1, facet2);
    }
  }
  if (qh->tracevertex)
    qh_errprint(qh, "TRACE", NULL, NULL, NULL, qh->tracevertex);
} /* mergevertex_neighbors */


/*---------------------------------

  qh_mergevertices(qh, vertices1, vertices2 )
    merges the vertex set of facet1 into facet2

  returns:
    replaces vertices2 with merged set
    preserves vertex_visit for qh_mergevertex_neighbors
    updates qh.newvertex_list

  design:
    create a merged set of both vertices (in inverse id order)
*/
void qh_mergevertices(qhT *qh, setT *vertices1, setT **vertices2) {
  int newsize= qh_setsize(qh, vertices1)+qh_setsize(qh, *vertices2) - qh->hull_dim + 1;
  setT *mergedvertices;
  vertexT *vertex, **vertexp, **vertex2= SETaddr_(*vertices2, vertexT);

  mergedvertices= qh_settemp(qh, newsize);
  FOREACHvertex_(vertices1) {
    if (!*vertex2 || vertex->id > (*vertex2)->id)
      qh_setappend(qh, &mergedvertices, vertex);
    else {
      while (*vertex2 && (*vertex2)->id > vertex->id)
        qh_setappend(qh, &mergedvertices, *vertex2++);
      if (!*vertex2 || (*vertex2)->id < vertex->id)
        qh_setappend(qh, &mergedvertices, vertex);
      else
        qh_setappend(qh, &mergedvertices, *vertex2++);
    }
  }
  while (*vertex2)
    qh_setappend(qh, &mergedvertices, *vertex2++);
  if (newsize < qh_setsize(qh, mergedvertices)) {
    qh_fprintf(qh, qh->ferr, 6100, "qhull internal error (qh_mergevertices): facets did not share a ridge\n");
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  qh_setfree(qh, vertices2);
  *vertices2= mergedvertices;
  qh_settemppop(qh);
} /* mergevertices */


/*---------------------------------

  qh_neighbor_intersections(qh, vertex )
    return intersection of all vertices in vertex->neighbors except for vertex

  returns:
    returns temporary set of vertices
    does not include vertex
    NULL if a neighbor is simplicial
    NULL if empty set

  notes:
    only called by qh_redundant_vertex for qh_reducevertices
      so f.vertices does not contain extraneous vertices that are not in f.ridges
    used for renaming vertices

  design:
    initialize the intersection set with vertices of the first two neighbors
    delete vertex from the intersection
    for each remaining neighbor
      intersect its vertex set with the intersection set
      return NULL if empty
    return the intersection set
*/
setT *qh_neighbor_intersections(qhT *qh, vertexT *vertex) {
  facetT *neighbor, **neighborp, *neighborA, *neighborB;
  setT *intersect;
  int neighbor_i, neighbor_n;

  FOREACHneighbor_(vertex) {
    if (neighbor->simplicial)
      return NULL;
  }
  neighborA= SETfirstt_(vertex->neighbors, facetT);
  neighborB= SETsecondt_(vertex->neighbors, facetT);
  zinc_(Zintersectnum);
  if (!neighborA)
    return NULL;
  if (!neighborB)
    intersect= qh_setcopy(qh, neighborA->vertices, 0);
  else
    intersect= qh_vertexintersect_new(qh, neighborA->vertices, neighborB->vertices);
  qh_settemppush(qh, intersect);
  qh_setdelsorted(intersect, vertex);
  FOREACHneighbor_i_(qh, vertex) {
    if (neighbor_i >= 2) {
      zinc_(Zintersectnum);
      qh_vertexintersect(qh, &intersect, neighbor->vertices);
      if (!SETfirst_(intersect)) {
        zinc_(Zintersectfail);
        qh_settempfree(qh, &intersect);
        return NULL;
      }
    }
  }
  trace3((qh, qh->ferr, 3007, "qh_neighbor_intersections: %d vertices in neighbor intersection of v%d\n",
          qh_setsize(qh, intersect), vertex->id));
  return intersect;
} /* neighbor_intersections */

/*---------------------------------

  qh_neighbor_vertices(qh, vertex )
    return neighboring vertices for a vertex (not in subridge)
    assumes vertices have full vertex->neighbors

  returns:
    temporary set of vertices

  notes:
    updates qh.visit_id and qh.vertex_visit
    similar to qh_vertexridges

*/
setT *qh_neighbor_vertices(qhT *qh, vertexT *vertexA, setT *subridge) {
  facetT *neighbor, **neighborp;
  vertexT *vertex, **vertexp;
  setT *vertices= qh_settemp(qh, qh->TEMPsize);

  qh->visit_id++;
  FOREACHneighbor_(vertexA)
    neighbor->visitid= qh->visit_id;
  qh->vertex_visit++;
  vertexA->visitid= qh->vertex_visit;
  FOREACHvertex_(subridge) {
    vertex->visitid= qh->vertex_visit;
  }
  FOREACHneighbor_(vertexA) {
    if (*neighborp)   /* no new ridges in last neighbor */
      qh_neighbor_vertices_facet(qh, vertexA, neighbor, &vertices);
  }
  trace3((qh, qh->ferr, 3035, "qh_neighbor_vertices: %d non-subridge, vertex neighbors for v%d\n",
    qh_setsize(qh, vertices), vertexA->id));
  return vertices;
} /* neighbor_vertices */

/*---------------------------------

  qh_neighbor_vertices_facet(qh, vertex, facet, vertices )
    add neighboring vertices on ridges for vertex in facet
    neighbor->visitid==qh.visit_id if it hasn't been visited
    v.visitid==qh.vertex_visit if it is already in vertices

  returns:
    vertices updated
    sets facet->visitid to qh.visit_id-1

  notes:
    only called by qh_neighbor_vertices
    similar to qh_vertexridges_facet

  design:
    for each ridge of facet
      if ridge of visited neighbor (i.e., unprocessed)
        if vertex in ridge
          append unprocessed vertices of ridge
    mark facet processed
*/
void qh_neighbor_vertices_facet(qhT *qh, vertexT *vertexA, facetT *facet, setT **vertices) {
  ridgeT *ridge, **ridgep;
  facetT *neighbor;
  vertexT *second, *last, *vertex, **vertexp;
  int last_i= qh->hull_dim-2, count= 0;
  boolT isridge;

  if (facet->simplicial) {
    FOREACHvertex_(facet->vertices) {
      if (vertex->visitid != qh->vertex_visit) {
        vertex->visitid= qh->vertex_visit;
        qh_setappend(qh, vertices, vertex);
        count++;
      }
    }
  }else {
    FOREACHridge_(facet->ridges) {
      neighbor= otherfacet_(ridge, facet);
      if (neighbor->visitid == qh->visit_id) {
        isridge= False;
        if (SETfirst_(ridge->vertices) == vertexA) {
          isridge= True;
        }else if (last_i > 2) {
          second= SETsecondt_(ridge->vertices, vertexT);
          last= SETelemt_(ridge->vertices, last_i, vertexT);
          if (second->id >= vertexA->id && last->id <= vertexA->id) { /* vertices inverse sorted by id */
            if (second == vertexA || last == vertexA)
              isridge= True;
            else if (qh_setin(ridge->vertices, vertexA))
              isridge= True;
          }
        }else if (SETelem_(ridge->vertices, last_i) == vertexA) {
          isridge= True;
        }else if (last_i > 1 && SETsecond_(ridge->vertices) == vertexA) {
          isridge= True;
        }
        if (isridge) {
          FOREACHvertex_(ridge->vertices) {
            if (vertex->visitid != qh->vertex_visit) {
              vertex->visitid= qh->vertex_visit;
              qh_setappend(qh, vertices, vertex);
              count++;
            }
          }
        }
      }
    }
  }
  facet->visitid= qh->visit_id-1;
  if (count) {
    trace4((qh, qh->ferr, 4079, "qh_neighbor_vertices_facet: found %d vertex neighbors for v%d in f%d (simplicial? %d)\n",
      count, vertexA->id, facet->id, facet->simplicial));
  }
} /* neighbor_vertices_facet */


/*---------------------------------

  qh_newvertices(qh, vertices )
    add vertices to end of qh.vertex_list (marks as new vertices)

  returns:
    vertices on qh.newvertex_list
    vertex->newfacet set
*/
void qh_newvertices(qhT *qh, setT *vertices) {
  vertexT *vertex, **vertexp;

  FOREACHvertex_(vertices) {
    if (!vertex->newfacet) {
      qh_removevertex(qh, vertex);
      qh_appendvertex(qh, vertex);
    }
  }
} /* newvertices */

/*---------------------------------

  qh_next_vertexmerge(qh )
    return next vertex merge from qh.vertex_mergeset

  returns:
    vertex merge either MRGvertices or MRGsubridge
    drops merges of deleted vertices

  notes:
    called from qh_merge_pinchedvertices
*/
mergeT *qh_next_vertexmerge(qhT *qh /* qh.vertex_mergeset */) {
  mergeT *merge;
  int merge_i, merge_n, best_i= -1;
  realT bestdist= REALmax;

  FOREACHmerge_i_(qh, qh->vertex_mergeset) {
    if (!merge->vertex1 || !merge->vertex2) {
      qh_fprintf(qh, qh->ferr, 6299, "qhull internal error (qh_next_vertexmerge): expecting two vertices for vertex merge.  Got v%d v%d and optional f%d\n",
        getid_(merge->vertex1), getid_(merge->vertex2), getid_(merge->facet1));
      qh_errexit(qh, qh_ERRqhull, merge->facet1, NULL);
    }
    if (merge->vertex1->deleted || merge->vertex2->deleted) {
      trace3((qh, qh->ferr, 3030, "qh_next_vertexmerge: drop merge of v%d (del? %d) into v%d (del? %d) due to deleted vertex of r%d and r%d\n",
        merge->vertex1->id, merge->vertex1->deleted, merge->vertex2->id, merge->vertex2->deleted, getid_(merge->ridge1), getid_(merge->ridge2)));
      qh_drop_mergevertex(qh, merge);
      qh_setdelnth(qh, qh->vertex_mergeset, merge_i);
      merge_i--; merge_n--;
      qh_memfree(qh, merge, (int)sizeof(mergeT));
    }else if (merge->distance < bestdist) {
      bestdist= merge->distance;
      best_i= merge_i;
    }
  }
  merge= NULL;
  if (best_i >= 0) {
    merge= SETelemt_(qh->vertex_mergeset, best_i, mergeT);
    if (bestdist/qh->ONEmerge > qh_WIDEpinched) {
      if (merge->mergetype==MRGvertices) {
        if (merge->ridge1->top == merge->ridge2->bottom && merge->ridge1->bottom == merge->ridge2->top)
          qh_fprintf(qh, qh->ferr, 6391, "qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve opposite oriented ridges r%d and r%d in f%d and f%d.  Nearest v%d and v%d dist %2.2g (%.1fx)\n",
            merge->ridge1->id, merge->ridge2->id, merge->ridge1->top->id, merge->ridge1->bottom->id, merge->vertex1->id, merge->vertex2->id, bestdist, bestdist/qh->ONEmerge);
        else
          qh_fprintf(qh, qh->ferr, 6381, "qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r%d and r%d.  Nearest v%d and v%d dist %2.2g (%.1fx)\n",
            merge->ridge1->id, merge->ridge2->id, merge->vertex1->id, merge->vertex2->id, bestdist, bestdist/qh->ONEmerge);
      }else {
        qh_fprintf(qh, qh->ferr, 6208, "qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve dupridge.  Nearest v%d and v%d dist %2.2g (%.1fx)\n",
          merge->vertex1->id, merge->vertex2->id, bestdist, bestdist/qh->ONEmerge);
      }
      /* it may be possible to find a different vertex, after other vertex merges have occurred */
      qh_errexit(qh, qh_ERRtopology, NULL, merge->ridge1);
    }
    qh_setdelnth(qh, qh->vertex_mergeset, best_i);
  }
  return merge;
} /* next_vertexmerge */

/*---------------------------------

  qh_opposite_horizonfacet(qh, merge, opposite )
    return horizon facet for one of the merge facets, and its opposite vertex across the ridge
    assumes either facet1 or facet2 of merge is 'mergehorizon'
    assumes both facets are simplicial facets on qh.new_facetlist

  returns:
    horizon facet and opposite vertex

  notes:
    called by qh_getpinchedmerges
*/
facetT *qh_opposite_horizonfacet(qhT *qh, mergeT *merge, vertexT **opposite) {
  facetT *facet, *horizon, *otherfacet;
  int neighbor_i;

  if (!merge->facet1->simplicial || !merge->facet2->simplicial || (!merge->facet1->mergehorizon && !merge->facet2->mergehorizon)) {
    qh_fprintf(qh, qh->ferr, 6273, "qhull internal error (qh_opposite_horizonfacet): expecting merge of simplicial facets, at least one of which is mergehorizon.  Either simplicial or mergehorizon is wrong\n");
    qh_errexit2(qh, qh_ERRqhull, merge->facet1, merge->facet2);
  }
  if (merge->facet1->mergehorizon) {
    facet= merge->facet1;
    otherfacet= merge->facet2;
  }else {
    facet= merge->facet2;
    otherfacet= merge->facet1;
  }
  horizon= SETfirstt_(facet->neighbors, facetT);
  neighbor_i= qh_setindex(otherfacet->neighbors, facet);
  if (neighbor_i==-1)
    neighbor_i= qh_setindex(otherfacet->neighbors, qh_MERGEridge);
  if (neighbor_i==-1) {
    qh_fprintf(qh, qh->ferr, 6238, "qhull internal error (qh_opposite_horizonfacet): merge facet f%d not connected to mergehorizon f%d\n",
      otherfacet->id, facet->id);
    qh_errexit2(qh, qh_ERRqhull, otherfacet, facet);
  }
  *opposite= SETelemt_(otherfacet->vertices, neighbor_i, vertexT);
  return horizon;
} /* opposite_horizonfacet */


/*---------------------------------

  qh_reducevertices(qh)
    reduce extra vertices, shared vertices, and redundant vertices
    facet->newmerge is set if merged since last call
    vertex->delridge is set if vertex was on a deleted ridge
    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:
    called by qh_all_merges and qh_postmerge
    ignored if 2-d

  design:
    merge any degenerate or redundant facets
    repeat until no more 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
        for each new, undeleted vertex
          remove delridge flag
          if vertex is redundant
            merge degenerate or redundant facets
*/
boolT qh_reducevertices(qhT *qh) {
  int numshare=0, numrename= 0;
  boolT degenredun= False;
  facetT *newfacet;
  vertexT *vertex, **vertexp;

  if (qh->hull_dim == 2)
    return False;
  trace2((qh, qh->ferr, 2101, "qh_reducevertices: reduce extra vertices, shared vertices, and redundant vertices\n"));
  if (qh_merge_degenredundant(qh))
    degenredun= True;
LABELrestart:
  FORALLnew_facets {
    if (newfacet->newmerge) {
      if (!qh->MERGEvertices)
        newfacet->newmerge= False;
      if (qh_remove_extravertices(qh, newfacet)) {
        qh_degen_redundant_facet(qh, newfacet);
        if (qh_merge_degenredundant(qh)) {
          degenredun= True;
          goto LABELrestart;
        }
      }
    }
  }
  if (!qh->MERGEvertices)
    return False;
  FORALLnew_facets {
    if (newfacet->newmerge) {
      newfacet->newmerge= False;
      FOREACHvertex_(newfacet->vertices) {
        if (vertex->delridge) {
          if (qh_rename_sharedvertex(qh, vertex, newfacet)) {
            numshare++;
            if (qh_merge_degenredundant(qh)) {
              degenredun= True;
              goto LABELrestart;
            }
            vertexp--; /* repeat since deleted vertex */
          }
        }
      }
    }
  }
  FORALLvertex_(qh->newvertex_list) {
    if (vertex->delridge && !vertex->deleted) {
      vertex->delridge= False;
      if (qh->hull_dim >= 4 && qh_redundant_vertex(qh, vertex)) {
        numrename++;
        if (qh_merge_degenredundant(qh)) {
          degenredun= True;
          goto LABELrestart;
        }
      }
    }
  }
  trace1((qh, qh->ferr, 1014, "qh_reducevertices: renamed %d shared vertices and %d redundant vertices. Degen? %d\n",
          numshare, numrename, degenredun));
  return degenredun;
} /* reducevertices */

/*---------------------------------

  qh_redundant_vertex(qh, vertex )
    rename a redundant vertex if qh_find_newvertex succeeds
    assumes vertices have full vertex->neighbors

  returns:
    if find a replacement vertex
      returns new vertex
      qh_renamevertex sets vertex->deleted for redundant vertex

  notes:
    only called by qh_reducevertices for 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 among these ridges and vertices
      rename vertex to the new vertex
*/
vertexT *qh_redundant_vertex(qhT *qh, vertexT *vertex) {
  vertexT *newvertex= NULL;
  setT *vertices, *ridges;

  trace3((qh, qh->ferr, 3008, "qh_redundant_vertex: check if v%d from a deleted ridge can be renamed\n", vertex->id));
  if ((vertices= qh_neighbor_intersections(qh, vertex))) {
    ridges= qh_vertexridges(qh, vertex, !qh_ALL);
    if ((newvertex= qh_find_newvertex(qh, vertex, vertices, ridges))) {
      zinc_(Zrenameall);
      qh_renamevertex(qh, vertex, newvertex, ridges, NULL, NULL); /* ridges invalidated */
    }
    qh_settempfree(qh, &ridges);
    qh_settempfree(qh, &vertices);
  }
  return newvertex;
} /* redundant_vertex */

/*---------------------------------

  qh_remove_extravertices(qh, facet )
    remove extra vertices from non-simplicial facets

  returns:
    returns True if it finds them
      deletes facet from vertex neighbors
      facet may be redundant (test with qh_degen_redundant)

  notes:
    called by qh_renamevertex and qh_reducevertices
    a merge (qh_reducevertices) or qh_renamevertex may drop all ridges for a vertex in a facet

  design:
    for each vertex in facet
      if vertex not in a ridge (i.e., no longer used)
        delete vertex from facet
        delete facet from vertex's neighbors
        unless vertex in another facet
          add vertex to qh.del_vertices for later deletion
*/
boolT qh_remove_extravertices(qhT *qh, facetT *facet) {
  ridgeT *ridge, **ridgep;
  vertexT *vertex, **vertexp;
  boolT foundrem= False;

  if (facet->simplicial) {
    return False;
  }
  trace4((qh, qh->ferr, 4043, "qh_remove_extravertices: test non-simplicial f%d for extra vertices\n",
          facet->id));
  FOREACHvertex_(facet->vertices)
    vertex->seen= False;
  FOREACHridge_(facet->ridges) {
    FOREACHvertex_(ridge->vertices)
      vertex->seen= True;
  }
  FOREACHvertex_(facet->vertices) {
    if (!vertex->seen) {
      foundrem= True;
      zinc_(Zremvertex);
      qh_setdelsorted(facet->vertices, vertex);
      qh_setdel(vertex->neighbors, facet);
      if (!qh_setsize(qh, vertex->neighbors)) {
        vertex->deleted= True;
        qh_setappend(qh, &qh->del_vertices, vertex);
        zinc_(Zremvertexdel);
        trace2((qh, qh->ferr, 2036, "qh_remove_extravertices: v%d deleted because it's lost all ridges\n", vertex->id));
      }else
        trace3((qh, qh->ferr, 3009, "qh_remove_extravertices: v%d removed from f%d because it's lost all ridges\n", vertex->id, facet->id));
      vertexp--; /*repeat*/
    }
  }
  return foundrem;
} /* remove_extravertices */

/*---------------------------------

  qh_remove_mergetype(qh, mergeset, mergetype )
    Remove mergetype merges from mergeset

  notes:
    Does not preserve order
*/
void qh_remove_mergetype(qhT *qh, setT *mergeset, mergeType type) {
  mergeT *merge;
  int merge_i, merge_n;

  FOREACHmerge_i_(qh, mergeset) {
    if (merge->mergetype == type) {
        trace3((qh, qh->ferr, 3037, "qh_remove_mergetype: remove merge f%d f%d v%d v%d r%d r%d dist %2.2g type %d",
            getid_(merge->facet1), getid_(merge->facet2), getid_(merge->vertex1), getid_(merge->vertex2), getid_(merge->ridge1), getid_(merge->ridge2), merge->distance, type));
        qh_setdelnth(qh, mergeset, merge_i);
        merge_i--; merge_n--;  /* repeat with next merge */
    }
  }
} /* remove_mergetype */

/*---------------------------------

  qh_rename_adjacentvertex(qh, oldvertex, newvertex )
    renames oldvertex as newvertex.  Must be adjacent (i.e., in the same subridge)
    no-op if either vertex is deleted

  notes:
    called from qh_merge_pinchedvertices

  design:
    for all neighbors of oldvertex
      if simplicial, rename oldvertex to newvertex and drop if degenerate
      if needed, add oldvertex neighbor to newvertex
    determine ridges for oldvertex
    rename oldvertex as newvertex in ridges (qh_renamevertex)
*/
void qh_rename_adjacentvertex(qhT *qh, vertexT *oldvertex, vertexT *newvertex, realT dist) {
  setT *ridges;
  facetT *neighbor, **neighborp, *maxfacet= NULL;
  ridgeT *ridge, **ridgep;
  boolT istrace= False;
  int oldsize= qh_setsize(qh, oldvertex->neighbors);
  int newsize= qh_setsize(qh, newvertex->neighbors);
  coordT maxdist2= -REALmax, dist2;

  if (qh->IStracing >= 4 || oldvertex->id == qh->tracevertex_id || newvertex->id == qh->tracevertex_id) {
    istrace= True;
  }
  zzinc_(Ztotmerge);
  if (istrace) {
    qh_fprintf(qh, qh->ferr, 2071, "qh_rename_adjacentvertex: merge #%d rename v%d (%d neighbors) to v%d (%d neighbors) dist %2.2g\n",
      zzval_(Ztotmerge), oldvertex->id, oldsize, newvertex->id, newsize, dist);
  }
  if (oldvertex->deleted || newvertex->deleted) {
    if (istrace || qh->IStracing >= 2) {
      qh_fprintf(qh, qh->ferr, 2072, "qh_rename_adjacentvertex: ignore rename.  Either v%d (%d) or v%d (%d) is deleted\n",
        oldvertex->id, oldvertex->deleted, newvertex->id, newvertex->deleted);
    }
    return;
  }
  if (oldsize == 0 || newsize == 0) {
    qh_fprintf(qh, qh->ferr, 2072, "qhull internal error (qh_rename_adjacentvertex): expecting neighbor facets for v%d and v%d.  Got %d and %d neighbors resp.\n",
      oldvertex->id, newvertex->id, oldsize, newsize);
      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  FOREACHneighbor_(oldvertex) {
    if (neighbor->simplicial) {
      if (qh_setin(neighbor->vertices, newvertex)) {
        if (istrace || qh->IStracing >= 2) {
          qh_fprintf(qh, qh->ferr, 2070, "qh_rename_adjacentvertex: simplicial f%d contains old v%d and new v%d.  Will be marked degenerate by qh_renamevertex\n",
            neighbor->id, oldvertex->id, newvertex->id);
        }
        qh_makeridges(qh, neighbor); /* no longer simplicial, nummerge==0, skipped by qh_maybe_duplicateridge */
      }else {
        qh_replacefacetvertex(qh, neighbor, oldvertex, newvertex);
        qh_setunique(qh, &newvertex->neighbors, neighbor);
        qh_newvertices(qh, neighbor->vertices);  /* for qh_update_vertexneighbors of vertex neighbors */
      }
    }
  }
  ridges= qh_vertexridges(qh, oldvertex, qh_ALL);
  if (istrace) {
    FOREACHridge_(ridges) {
      qh_printridge(qh, qh->ferr, ridge);
    }
  }
  FOREACHneighbor_(oldvertex) {
    if (!neighbor->simplicial){
      qh_addfacetvertex(qh, neighbor, newvertex);
      qh_setunique(qh, &newvertex->neighbors, neighbor);
      qh_newvertices(qh, neighbor->vertices);  /* for qh_update_vertexneighbors of vertex neighbors */
      if (qh->newfacet_list == qh->facet_tail) {
        qh_removefacet(qh, neighbor);  /* add a neighbor to newfacet_list so that qh_partitionvisible has a newfacet */
        qh_appendfacet(qh, neighbor);
        neighbor->newfacet= True;
      }
    }
  }
  qh_renamevertex(qh, oldvertex, newvertex, ridges, NULL, NULL);  /* ridges invalidated */
  if (oldvertex->deleted && !oldvertex->partitioned) {
    FOREACHneighbor_(newvertex) {
      if (!neighbor->visible) {
        qh_distplane(qh, oldvertex->point, neighbor, &dist2);
        if (dist2>maxdist2) {
          maxdist2= dist2;
          maxfacet= neighbor;
        }
      }
    }
    trace2((qh, qh->ferr, 2096, "qh_rename_adjacentvertex: partition old p%d(v%d) as a coplanar point for furthest f%d dist %2.2g.  Maybe repartition later (QH0031)\n",
      qh_pointid(qh, oldvertex->point), oldvertex->id, maxfacet->id, maxdist2))
    qh_partitioncoplanar(qh, oldvertex->point, maxfacet, NULL, !qh_ALL);  /* faster with maxdist2, otherwise duplicates distance tests from maxdist2/dist2 */
    oldvertex->partitioned= True;
  }
  qh_settempfree(qh, &ridges);
} /* rename_adjacentvertex */

/*---------------------------------

  qh_rename_sharedvertex(qh, vertex, facet )
    detect and rename if shared vertex in facet
    vertices have full ->neighbors

  returns:
    newvertex or NULL
    the vertex may still exist in other facets (i.e., a neighbor was pinched)
    does not change facet->neighbors
    updates vertex->neighbors

  notes:
    only called by qh_reducevertices after qh_remove_extravertices
       so f.vertices does not contain extraneous vertices
    a shared vertex for a facet is only in ridges to one neighbor
    this may undo a pinched facet

    it does not catch pinches involving multiple facets.  These appear
      to be difficult to detect, since an exhaustive search is too expensive.

  design:
    if vertex only has two neighbors
      determine the ridges that contain the vertex
      determine the vertices shared by both neighbors
      if can find a new vertex in this set
        rename the vertex to the new vertex
*/
vertexT *qh_rename_sharedvertex(qhT *qh, vertexT *vertex, facetT *facet) {
  facetT *neighbor, **neighborp, *neighborA= NULL;
  setT *vertices, *ridges;
  vertexT *newvertex= NULL;

  if (qh_setsize(qh, vertex->neighbors) == 2) {
    neighborA= SETfirstt_(vertex->neighbors, facetT);
    if (neighborA == facet)
      neighborA= SETsecondt_(vertex->neighbors, facetT);
  }else if (qh->hull_dim == 3)
    return NULL;
  else {
    qh->visit_id++;
    FOREACHneighbor_(facet)
      neighbor->visitid= qh->visit_id;
    FOREACHneighbor_(vertex) {
      if (neighbor->visitid == qh->visit_id) {
        if (neighborA)
          return NULL;
        neighborA= neighbor;
      }
    }
  }
  if (!neighborA) {
    qh_fprintf(qh, qh->ferr, 6101, "qhull internal error (qh_rename_sharedvertex): v%d's neighbors not in f%d\n",
        vertex->id, facet->id);
    qh_errprint(qh, "ERRONEOUS", facet, NULL, NULL, vertex);
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  if (neighborA) { /* avoid warning */
    /* the vertex is shared by facet and neighborA */
    ridges= qh_settemp(qh, qh->TEMPsize);
    neighborA->visitid= ++qh->visit_id;
    qh_vertexridges_facet(qh, vertex, facet, &ridges);
    trace2((qh, qh->ferr, 2037, "qh_rename_sharedvertex: p%d(v%d) is shared by f%d(%d ridges) and f%d\n",
      qh_pointid(qh, vertex->point), vertex->id, facet->id, qh_setsize(qh, ridges), neighborA->id));
    zinc_(Zintersectnum);
    vertices= qh_vertexintersect_new(qh, facet->vertices, neighborA->vertices);
    qh_setdel(vertices, vertex);
    qh_settemppush(qh, vertices);
    if ((newvertex= qh_find_newvertex(qh, vertex, vertices, ridges)))
      qh_renamevertex(qh, vertex, newvertex, ridges, facet, neighborA);  /* ridges invalidated */
    qh_settempfree(qh, &vertices);
    qh_settempfree(qh, &ridges);
  }
  return newvertex;
} /* rename_sharedvertex */

/*---------------------------------

  qh_renameridgevertex(qh, ridge, oldvertex, newvertex )
    renames oldvertex as newvertex in ridge

  returns:
    True if renames oldvertex
    False if deleted the ridge

  notes:
    called by qh_renamevertex
    caller sets newvertex->delridge for deleted ridges (qh_reducevertices)

  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
*/
boolT qh_renameridgevertex(qhT *qh, ridgeT *ridge, vertexT *oldvertex, vertexT *newvertex) {
  int nth= 0, oldnth;
  facetT *temp;
  vertexT *vertex, **vertexp;

  oldnth= qh_setindex(ridge->vertices, oldvertex);
  if (oldnth < 0) {
    qh_fprintf(qh, qh->ferr, 6424, "qhull internal error (qh_renameridgevertex): oldvertex v%d not found in r%d.  Cannot rename to v%d\n",
        oldvertex->id, ridge->id, newvertex->id);
    qh_errexit(qh, qh_ERRqhull, NULL, ridge);
  }
  qh_setdelnthsorted(qh, ridge->vertices, oldnth);
  FOREACHvertex_(ridge->vertices) {
    if (vertex == newvertex) {
      zinc_(Zdelridge);
      if (ridge->nonconvex) /* only one ridge has nonconvex set */
        qh_copynonconvex(qh, ridge);
      trace2((qh, qh->ferr, 2038, "qh_renameridgevertex: ridge r%d deleted.  It contained both v%d and v%d\n",
        ridge->id, oldvertex->id, newvertex->id));
      qh_delridge_merge(qh, ridge); /* ridge.vertices deleted */
      return False;
    }
    if (vertex->id < newvertex->id)
      break;
    nth++;
  }
  qh_setaddnth(qh, &ridge->vertices, nth, newvertex);
  ridge->simplicialtop= False;
  ridge->simplicialbot= False;
  if (abs(oldnth - nth)%2) {
    trace3((qh, qh->ferr, 3010, "qh_renameridgevertex: swapped the top and bottom of ridge r%d\n",
            ridge->id));
    temp= ridge->top;
    ridge->top= ridge->bottom;
    ridge->bottom= temp;
  }
  return True;
} /* renameridgevertex */


/*---------------------------------

  qh_renamevertex(qh, oldvertex, newvertex, ridges, oldfacet, neighborA )
    renames oldvertex as newvertex in ridges of non-simplicial neighbors
    set oldfacet/neighborA if oldvertex is shared between two facets (qh_rename_sharedvertex)
    otherwise qh_redundant_vertex or qh_rename_adjacentvertex

  returns:
    if oldfacet and multiple neighbors, oldvertex may still exist afterwards
    otherwise sets oldvertex->deleted for later deletion
    one or more ridges maybe deleted
    ridges is invalidated
    merges may be added to degen_mergeset via qh_maydropneighbor or qh_degen_redundant_facet

  notes:
    qh_rename_sharedvertex can not change neighbors of newvertex (since it's a subset)
    qh_redundant_vertex due to vertex->delridge for qh_reducevertices
    qh_rename_adjacentvertex for complete renames

  design:
    for each ridge in ridges
      rename oldvertex to newvertex and delete degenerate ridges
    if oldfacet not defined
      for each non-simplicial 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 old vertex's neighbors
      remove extra vertices (e.g., oldvertex) from neighborA
*/
void qh_renamevertex(qhT *qh, vertexT *oldvertex, vertexT *newvertex, setT *ridges, facetT *oldfacet, facetT *neighborA) {
  facetT *neighbor, **neighborp;
  ridgeT *ridge, **ridgep;
  int topsize, bottomsize;
  boolT istrace= False;

#ifndef qh_NOtrace
  if (qh->IStracing >= 2 || oldvertex->id == qh->tracevertex_id ||
        newvertex->id == qh->tracevertex_id) {
    istrace= True;
    qh_fprintf(qh, qh->ferr, 2086, "qh_renamevertex: rename v%d to v%d in %d ridges with old f%d and neighbor f%d\n",
      oldvertex->id, newvertex->id, qh_setsize(qh, ridges), getid_(oldfacet), getid_(neighborA));
  }
#endif
  FOREACHridge_(ridges) {
    if (qh_renameridgevertex(qh, ridge, oldvertex, newvertex)) { /* ridge is deleted if False, invalidating ridges */
      topsize= qh_setsize(qh, ridge->top->vertices);
      bottomsize= qh_setsize(qh, ridge->bottom->vertices);
      if (topsize < qh->hull_dim || (topsize == qh->hull_dim && !ridge->top->simplicial && qh_setin(ridge->top->vertices, newvertex))) {
        trace4((qh, qh->ferr, 4070, "qh_renamevertex: ignore duplicate check for r%d.  top f%d (size %d) will be degenerate after rename v%d to v%d\n",
          ridge->id, ridge->top->id, topsize, oldvertex->id, newvertex->id));
      }else if (bottomsize < qh->hull_dim || (bottomsize == qh->hull_dim && !ridge->bottom->simplicial && qh_setin(ridge->bottom->vertices, newvertex))) {
        trace4((qh, qh->ferr, 4071, "qh_renamevertex: ignore duplicate check for r%d.  bottom f%d (size %d) will be degenerate after rename v%d to v%d\n",
          ridge->id, ridge->bottom->id, bottomsize, oldvertex->id, newvertex->id));
      }else
        qh_maybe_duplicateridge(qh, ridge);
    }
  }
  if (!oldfacet) {
    /* stat Zrenameall or Zpinchduplicate */
    if (istrace)
      qh_fprintf(qh, qh->ferr, 2087, "qh_renamevertex: renaming v%d to v%d in several facets for qh_redundant_vertex or MRGsubridge\n",
               oldvertex->id, newvertex->id);
    FOREACHneighbor_(oldvertex) {
      if (neighbor->simplicial) {
        qh_degen_redundant_facet(qh, neighbor); /* e.g., rbox 175 C3,2e-13 D4 t1545235541 | qhull d */
      }else {
        if (istrace)
          qh_fprintf(qh, qh->ferr, 4080, "qh_renamevertex: rename vertices in non-simplicial neighbor f%d of v%d\n", neighbor->id, oldvertex->id);
        qh_maydropneighbor(qh, neighbor);
        qh_setdelsorted(neighbor->vertices, oldvertex); /* if degenerate, qh_degen_redundant_facet will add to mergeset */
        if (qh_remove_extravertices(qh, neighbor))
          neighborp--; /* neighbor deleted from oldvertex neighborset */
        qh_degen_redundant_facet(qh, neighbor); /* either direction may be redundant, faster if combine? */
        qh_test_redundant_neighbors(qh, neighbor);
        qh_test_degen_neighbors(qh, neighbor);
      }
    }
    if (!oldvertex->deleted) {
      oldvertex->deleted= True;
      qh_setappend(qh, &qh->del_vertices, oldvertex);
    }
  }else if (qh_setsize(qh, oldvertex->neighbors) == 2) {
    zinc_(Zrenameshare);
    if (istrace)
      qh_fprintf(qh, qh->ferr, 3039, "qh_renamevertex: renaming v%d to v%d in oldfacet f%d for qh_rename_sharedvertex\n",
               oldvertex->id, newvertex->id, oldfacet->id);
    FOREACHneighbor_(oldvertex) {
      qh_setdelsorted(neighbor->vertices, oldvertex);
      qh_degen_redundant_facet(qh, neighbor);
    }
    oldvertex->deleted= True;
    qh_setappend(qh, &qh->del_vertices, oldvertex);
  }else {
    zinc_(Zrenamepinch);
    if (istrace || qh->IStracing >= 1)
      qh_fprintf(qh, qh->ferr, 3040, "qh_renamevertex: renaming 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);
    if (qh_remove_extravertices(qh, neighborA))
      qh_degen_redundant_facet(qh, neighborA);
  }
  if (oldfacet)
    qh_degen_redundant_facet(qh, oldfacet);
} /* renamevertex */

/*---------------------------------

  qh_test_appendmerge(qh, facet, neighbor, simplicial )
    test convexity and append to qh.facet_mergeset if non-convex
    if pre-merging,
      no-op if qh.SKIPconvex, or qh.MERGEexact and coplanar
    if simplicial, assumes centrum test is valid (e.g., adjacent, simplicial new facets)

  returns:
    true if appends facet/neighbor to qh.facet_mergeset
    sets facet->center as needed
    does not change facet->seen

  notes:
    called from qh_getmergeset_initial, qh_getmergeset, and qh_test_vneighbors
    must be at least as strong as qh_checkconvex (poly2_r.c)
    assumes !f.flipped

  design:
    exit if qh.SKIPconvex ('Q0') and !qh.POSTmerging
    if qh.cos_max ('An') is defined and merging coplanars
      if the angle between facet normals is too shallow
        append an angle-coplanar merge to qh.mergeset
        return True
    test convexity of facet and neighbor
*/
boolT qh_test_appendmerge(qhT *qh, facetT *facet, facetT *neighbor, boolT simplicial) {
  realT angle= -REALmax;
  boolT okangle= False;

  if (qh->SKIPconvex && !qh->POSTmerging)
    return False;
  if (qh->cos_max < REALmax/2 && (!qh->MERGEexact || qh->POSTmerging)) {
    angle= qh_getangle(qh, facet->normal, neighbor->normal);
    okangle= True;
    zinc_(Zangletests);
    if (angle > qh->cos_max) {
      zinc_(Zcoplanarangle);
      qh_appendmergeset(qh, facet, neighbor, MRGanglecoplanar, 0.0, angle);
      trace2((qh, qh->ferr, 2039, "qh_test_appendmerge: coplanar angle %4.4g between f%d and f%d\n",
         angle, facet->id, neighbor->id));
      return True;
    }
  }
  if (simplicial || qh->hull_dim <= 3)
    return qh_test_centrum_merge(qh, facet, neighbor, angle, okangle);
  else
    return qh_test_nonsimplicial_merge(qh, facet, neighbor, angle, okangle);
} /* test_appendmerge */

/*---------------------------------

  qh_test_centrum_merge(qh, facet, neighbor, angle, okangle )
    test centrum convexity and append non-convex facets to qh.facet_mergeset
    'angle' is angle between facets if okangle is true, otherwise use 0.0

  returns:
    true if append facet/neighbor to qh.facet_mergeset
    sets facet->center as needed
    does not change facet->seen

  notes:
    called from test_appendmerge if adjacent simplicial facets or 2-d/3-d
    at least as strict as qh_checkconvex, including qh.DISTround ('En' and 'Rn')

  design:
    make facet's centrum if needed
    if facet's centrum is above the neighbor (qh.centrum_radius)
      set isconcave

    if facet's centrum is not below the neighbor (-qh.centrum_radius)
      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 and merging coplanars
      get angle if needed (qh.ANGLEmerge 'An')
      append concave-coplanar, concave ,or coplanar merge to qh.mergeset
*/
boolT qh_test_centrum_merge(qhT *qh, facetT *facet, facetT *neighbor, realT angle, boolT okangle) {
  coordT dist, dist2, mergedist;
  boolT isconcave= False, iscoplanar= False;

  if (!facet->center)
    facet->center= qh_getcentrum(qh, facet);
  zzinc_(Zcentrumtests);
  qh_distplane(qh, facet->center, neighbor, &dist);
  if (dist > qh->centrum_radius)
    isconcave= True;
  else if (dist >= -qh->centrum_radius)
    iscoplanar= True;
  if (!neighbor->center)
    neighbor->center= qh_getcentrum(qh, neighbor);
  zzinc_(Zcentrumtests);
  qh_distplane(qh, neighbor->center, facet, &dist2);
  if (dist2 > qh->centrum_radius)
    isconcave= True;
  else if (!iscoplanar && dist2 >= -qh->centrum_radius)
    iscoplanar= True;
  if (!isconcave && (!iscoplanar || (qh->MERGEexact && !qh->POSTmerging)))
    return False;
  if (!okangle && qh->ANGLEmerge) {
    angle= qh_getangle(qh, facet->normal, neighbor->normal);
    zinc_(Zangletests);
  }
  if (isconcave && iscoplanar) {
    zinc_(Zconcavecoplanarridge);
    if (dist > dist2)
      qh_appendmergeset(qh, facet, neighbor, MRGconcavecoplanar, dist, angle);
    else
      qh_appendmergeset(qh, neighbor, facet, MRGconcavecoplanar, dist2, angle);
    trace0((qh, qh->ferr, 36, "qh_test_centrum_merge: concave f%d to coplanar 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 if (isconcave) {
    mergedist= fmax_(dist, dist2);
    zinc_(Zconcaveridge);
    qh_appendmergeset(qh, facet, neighbor, MRGconcave, mergedist, angle);
    trace0((qh, qh->ferr, 37, "qh_test_centrum_merge: 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 */ {
    mergedist= fmin_(fabs_(dist), fabs_(dist2));
    zinc_(Zcoplanarcentrum);
    qh_appendmergeset(qh, facet, neighbor, MRGcoplanar, mergedist, angle);
    trace2((qh, qh->ferr, 2097, "qh_test_centrum_merge: 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_centrum_merge */

/*---------------------------------

  qh_test_degen_neighbors(qh, facet )
    append degenerate neighbors to qh.degen_mergeset

  notes:
  called at end of qh_mergefacet() and qh_renamevertex()
  call after test_redundant_facet() since MRGredundant is less expensive then MRGdegen
    a degenerate facet has fewer than hull_dim neighbors
    see: qh_merge_degenredundant()

*/
void qh_test_degen_neighbors(qhT *qh, facetT *facet) {
  facetT *neighbor, **neighborp;
  int size;

  trace4((qh, qh->ferr, 4073, "qh_test_degen_neighbors: test for degenerate neighbors of f%d\n", facet->id));
  FOREACHneighbor_(facet) {
    if (neighbor->visible) {
      qh_fprintf(qh, qh->ferr, 6359, "qhull internal error (qh_test_degen_neighbors): facet f%d has deleted neighbor f%d (qh.visible_list)\n",
        facet->id, neighbor->id);
      qh_errexit2(qh, qh_ERRqhull, facet, neighbor);
    }
    if (neighbor->degenerate || neighbor->redundant || neighbor->dupridge) /* will merge or delete */
      continue;
    /* merge flipped-degenerate facet before flipped facets */
    if ((size= qh_setsize(qh, neighbor->neighbors)) < qh->hull_dim) {
      qh_appendmergeset(qh, neighbor, neighbor, MRGdegen, 0.0, 1.0);
      trace2((qh, qh->ferr, 2019, "qh_test_degen_neighbors: f%d is degenerate with %d neighbors.  Neighbor of f%d.\n", neighbor->id, size, facet->id));
    }
  }
} /* test_degen_neighbors */


/*---------------------------------

  qh_test_nonsimplicial_merge(qh, facet, neighbor, angle, okangle )
    test centrum and vertex convexity and append non-convex or redundant facets to qh.facet_mergeset
    'angle' is angle between facets if okangle is true, otherwise use 0.0
    skips coplanar merges if pre-merging with qh.MERGEexact ('Qx')

  returns:
    true if appends facet/neighbor to qh.facet_mergeset
    sets facet->center as needed
    does not change facet->seen

  notes:
    only called from test_appendmerge if a non-simplicial facet and at least 4-d
    at least as strict as qh_checkconvex, including qh.DISTround ('En' and 'Rn')
      centrums must be < -qh.centrum_radius
    tests vertices as well as centrums since a facet may be twisted relative to its neighbor

  design:
    set precision constants for maxoutside, clearlyconcave, minvertex, and coplanarcentrum
      use maxoutside for coplanarcentrum if premerging with 'Qx' and qh_MAXcoplanarcentrum merges
      otherwise use qh.centrum_radious for coplanarcentrum
    make facet and neighbor centrums if needed
    isconcave if a centrum is above neighbor (coplanarcentrum)
    iscoplanar if a centrum is not below neighbor (-qh.centrum_radius)
    maybeconvex if a centrum is clearly below neighbor (-clearyconvex)
    return False if both centrums clearly below neighbor (-clearyconvex)
    return MRGconcave if isconcave

    facets are neither clearly convex nor clearly concave
    test vertices as well as centrums
    if maybeconvex
      determine mindist and maxdist for vertices of the other facet
      maybe MRGredundant
    otherwise
      determine mindist and maxdist for vertices of either facet
      maybe MRGredundant
      maybeconvex if a vertex is clearly below neighbor (-clearconvex)

    vertices are concave if dist > clearlyconcave
    vertices are twisted if dist > maxoutside (isconcave and maybeconvex)
    return False if not concave and pre-merge of 'Qx' (qh.MERGEexact)
    vertices are coplanar if dist in -minvertex..maxoutside
    if !isconcave, vertices are coplanar if dist >= -qh.MAXcoplanar (n*qh.premerge_centrum)

    return False if neither concave nor coplanar
    return MRGtwisted if isconcave and maybeconvex
    return MRGconcavecoplanar if isconcave and isconvex
    return MRGconcave if isconcave
    return MRGcoplanar if iscoplanar
*/
boolT qh_test_nonsimplicial_merge(qhT *qh, facetT *facet, facetT *neighbor, realT angle, boolT okangle) {
  coordT dist, mindist, maxdist, mindist2, maxdist2, dist2, maxoutside, clearlyconcave, minvertex, clearlyconvex, mergedist, coplanarcentrum;
  boolT isconcave= False, iscoplanar= False, maybeconvex= False, isredundant= False;
  vertexT *maxvertex= NULL, *maxvertex2= NULL;

  maxoutside= fmax_(neighbor->maxoutside, qh->ONEmerge + qh->DISTround);
  maxoutside= fmax_(maxoutside, facet->maxoutside);
  clearlyconcave= qh_RATIOconcavehorizon * maxoutside;
  minvertex= fmax_(-qh->min_vertex, qh->MAXcoplanar); /* non-negative, not available per facet, not used for iscoplanar */
  clearlyconvex= qh_RATIOconvexmerge * minvertex; /* must be convex for MRGtwisted */
  if (qh->MERGEexact && !qh->POSTmerging && (facet->nummerge > qh_MAXcoplanarcentrum || neighbor->nummerge > qh_MAXcoplanarcentrum))
    coplanarcentrum= maxoutside;
  else
    coplanarcentrum= qh->centrum_radius;

  if (!facet->center)
    facet->center= qh_getcentrum(qh, facet);
  zzinc_(Zcentrumtests);
  qh_distplane(qh, facet->center, neighbor, &dist);
  if (dist > coplanarcentrum)
    isconcave= True;
  else if (dist >= -qh->centrum_radius)
    iscoplanar= True;
  else if (dist < -clearlyconvex)
    maybeconvex= True;
  if (!neighbor->center)
    neighbor->center= qh_getcentrum(qh, neighbor);
  zzinc_(Zcentrumtests);
  qh_distplane(qh, neighbor->center, facet, &dist2);
  if (dist2 > coplanarcentrum)
    isconcave= True;
  else if (dist2 >= -qh->centrum_radius)
    iscoplanar= True;
  else if (dist2 < -clearlyconvex) {
    if (maybeconvex)
      return False; /* both centrums clearly convex */
    maybeconvex= True;
  }
  if (isconcave) {
    if (!okangle && qh->ANGLEmerge) {
      angle= qh_getangle(qh, facet->normal, neighbor->normal);
      zinc_(Zangletests);
    }
    mergedist= fmax_(dist, dist2);
    zinc_(Zconcaveridge);
    qh_appendmergeset(qh, facet, neighbor, MRGconcave, mergedist, angle);
    trace0((qh, qh->ferr, 18, "qh_test_nonsimplicial_merge: concave centrum for f%d or 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));
    return True;
  }
  /* neither clearly convex nor clearly concave, test vertices as well as centrums */
  if (maybeconvex) {
    if (dist < -clearlyconvex) {
      maxdist= dist;  /* facet centrum clearly convex, no need to test its vertex distance */
      mindist= dist;
      maxvertex2= qh_furthestvertex(qh, neighbor, facet, &maxdist2, &mindist2);
      if (!maxvertex2) {
        qh_appendmergeset(qh, neighbor, facet, MRGredundant, maxdist2, qh_ANGLEnone);
        isredundant= True;
      }
    }else { /* dist2 < -clearlyconvex */
      maxdist2= dist2;   /* neighbor centrum clearly convex, no need to test its vertex distance */
      mindist2= dist2;
      maxvertex= qh_furthestvertex(qh, facet, neighbor, &maxdist, &mindist);
      if (!maxvertex) {
        qh_appendmergeset(qh, facet, neighbor, MRGredundant, maxdist, qh_ANGLEnone);
        isredundant= True;
      }
    }
  }else {
    maxvertex= qh_furthestvertex(qh, facet, neighbor, &maxdist, &mindist);
    if (maxvertex) {
      maxvertex2= qh_furthestvertex(qh, neighbor, facet, &maxdist2, &mindist2);
      if (!maxvertex2) {
        qh_appendmergeset(qh, neighbor, facet, MRGredundant, maxdist2, qh_ANGLEnone);
        isredundant= True;
      }else if (mindist < -clearlyconvex || mindist2 < -clearlyconvex)
        maybeconvex= True;
    }else { /* !maxvertex */
      qh_appendmergeset(qh, facet, neighbor, MRGredundant, maxdist, qh_ANGLEnone);
      isredundant= True;
    }
  }
  if (isredundant) {
    zinc_(Zredundantmerge);
    return True;
  }

  if (maxdist > clearlyconcave || maxdist2 > clearlyconcave)
    isconcave= True;
  else if (maybeconvex) {
    if (maxdist > maxoutside || maxdist2 > maxoutside)
      isconcave= True;  /* MRGtwisted */
  }
  if (!isconcave && qh->MERGEexact && !qh->POSTmerging)
    return False;
  if (isconcave && !iscoplanar) {
    if (maxdist < maxoutside && (-qh->MAXcoplanar || (maxdist2 < maxoutside && mindist2 >= -qh->MAXcoplanar)))
      iscoplanar= True; /* MRGconcavecoplanar */
  }else if (!iscoplanar) {
    if (mindist >= -qh->MAXcoplanar || mindist2 >= -qh->MAXcoplanar)
      iscoplanar= True;  /* MRGcoplanar */
  }
  if (!isconcave && !iscoplanar)
    return False;
  if (!okangle && qh->ANGLEmerge) {
    angle= qh_getangle(qh, facet->normal, neighbor->normal);
    zinc_(Zangletests);
  }
  if (isconcave && maybeconvex) {
    zinc_(Ztwistedridge);
    if (maxdist > maxdist2)
      qh_appendmergeset(qh, facet, neighbor, MRGtwisted, maxdist, angle);
    else
      qh_appendmergeset(qh, neighbor, facet, MRGtwisted, maxdist2, angle);
    trace0((qh, qh->ferr, 27, "qh_test_nonsimplicial_merge: twisted concave f%d v%d to f%d v%d, dist %4.4g and reverse dist %4.4g, angle %4.4g during p%d\n",
           facet->id, getid_(maxvertex), neighbor->id, getid_(maxvertex2), maxdist, maxdist2, angle, qh->furthest_id));
  }else if (isconcave && iscoplanar) {
    zinc_(Zconcavecoplanarridge);
    if (maxdist > maxdist2)
      qh_appendmergeset(qh, facet, neighbor, MRGconcavecoplanar, maxdist, angle);
    else
      qh_appendmergeset(qh, neighbor, facet, MRGconcavecoplanar, maxdist2, angle);
    trace0((qh, qh->ferr, 28, "qh_test_nonsimplicial_merge: concave coplanar f%d v%d to f%d v%d, dist %4.4g and reverse dist %4.4g, angle %4.4g during p%d\n",
      facet->id, getid_(maxvertex), neighbor->id, getid_(maxvertex2), maxdist, maxdist2, angle, qh->furthest_id));
  }else if (isconcave) {
    mergedist= fmax_(maxdist, maxdist2);
    zinc_(Zconcaveridge);
    qh_appendmergeset(qh, facet, neighbor, MRGconcave, mergedist, angle);
    trace0((qh, qh->ferr, 29, "qh_test_nonsimplicial_merge: concave f%d v%d to f%d v%d, dist %4.4g and reverse dist %4.4g, angle %4.4g during p%d\n",
      facet->id, getid_(maxvertex), neighbor->id, getid_(maxvertex2), maxdist, maxdist2, angle, qh->furthest_id));
  }else /* iscoplanar */ {
    mergedist= fmax_(fmax_(maxdist, maxdist2), fmax_(-mindist, -mindist2));
    zinc_(Zcoplanarcentrum);
    qh_appendmergeset(qh, facet, neighbor, MRGcoplanar, mergedist, angle);
    trace2((qh, qh->ferr, 2099, "qh_test_nonsimplicial_merge: coplanar f%d v%d to f%d v%d, dist %4.4g and reverse dist %4.4g, angle %4.4g during p%d\n",
      facet->id, getid_(maxvertex), neighbor->id, getid_(maxvertex2), maxdist, maxdist2, angle, qh->furthest_id));
  }
  return True;
} /* test_nonsimplicial_merge */

/*---------------------------------

  qh_test_redundant_neighbors(qh, facet )
    append degenerate facet or its redundant neighbors to qh.degen_mergeset

  returns:
    bumps vertex_visit

  notes:
    called at end of qh_mergefacet(), qh_mergecycle_all(), and qh_renamevertex
    call before qh_test_degen_neighbors (MRGdegen are more likely to cause problems)
    a redundant neighbor's vertices is a subset of the facet's vertices
    with pinched and flipped facets, a redundant neighbor may have a wildly different normal

    see qh_merge_degenredundant() and qh_-_facet()

  design:
    if facet is degenerate
       appends facet to degen_mergeset
    else
       appends redundant neighbors of facet to degen_mergeset
*/
void qh_test_redundant_neighbors(qhT *qh, facetT *facet) {
  vertexT *vertex, **vertexp;
  facetT *neighbor, **neighborp;
  int size;

  trace4((qh, qh->ferr, 4022, "qh_test_redundant_neighbors: test neighbors of f%d vertex_visit %d\n",
          facet->id, qh->vertex_visit+1));
  if ((size= qh_setsize(qh, facet->neighbors)) < qh->hull_dim) {
    qh_appendmergeset(qh, facet, facet, MRGdegen, 0.0, 1.0);
    trace2((qh, qh->ferr, 2017, "qh_test_redundant_neighbors: f%d is degenerate with %d neighbors.\n", facet->id, size));
  }else {
    qh->vertex_visit++;
    FOREACHvertex_(facet->vertices)
      vertex->visitid= qh->vertex_visit;
    FOREACHneighbor_(facet) {
      if (neighbor->visible) {
        qh_fprintf(qh, qh->ferr, 6360, "qhull internal error (qh_test_redundant_neighbors): facet f%d has deleted neighbor f%d (qh.visible_list)\n",
          facet->id, neighbor->id);
        qh_errexit2(qh, qh_ERRqhull, facet, neighbor);
      }
      if (neighbor->degenerate || neighbor->redundant || neighbor->dupridge) /* will merge or delete */
        continue;
      if (facet->flipped && !neighbor->flipped) /* do not merge non-flipped into flipped */
        continue;
      /* merge redundant-flipped facet first */
      /* uses early out instead of checking vertex count */
      FOREACHvertex_(neighbor->vertices) {
        if (vertex->visitid != qh->vertex_visit)
          break;
      }
      if (!vertex) {
        qh_appendmergeset(qh, neighbor, facet, MRGredundant, 0.0, 1.0);
        trace2((qh, qh->ferr, 2018, "qh_test_redundant_neighbors: f%d is contained in f%d.  merge\n", neighbor->id, facet->id));
      }
    }
  }
} /* test_redundant_neighbors */

/*---------------------------------

  qh_test_vneighbors(qh)
    test vertex neighbors for convexity
    tests all facets on qh.newfacet_list

  returns:
    true if non-convex vneighbors appended to qh.facet_mergeset
    initializes vertex neighbors if needed

  notes:
    called by qh_all_merges from qh_postmerge if qh.TESTvneighbors ('Qv')
    assumes all facet neighbors have been tested
    this can be expensive
    this does not guarantee that a centrum is below all facets
      but it is unlikely
    uses qh.visit_id

  design:
    build vertex neighbors if necessary
    for all new facets
      for all vertices
        for each unvisited facet neighbor of the vertex
          test new facet and neighbor for convexity
*/
boolT qh_test_vneighbors(qhT *qh /* qh.newfacet_list */) {
  facetT *newfacet, *neighbor, **neighborp;
  vertexT *vertex, **vertexp;
  int nummerges= 0;

  trace1((qh, qh->ferr, 1015, "qh_test_vneighbors: testing vertex neighbors for convexity\n"));
  if (!qh->VERTEXneighbors)
    qh_vertexneighbors(qh);
  FORALLnew_facets
    newfacet->seen= False;
  FORALLnew_facets {
    newfacet->seen= True;
    newfacet->visitid= qh->visit_id++;
    FOREACHneighbor_(newfacet)
      newfacet->visitid= qh->visit_id;
    FOREACHvertex_(newfacet->vertices) {
      FOREACHneighbor_(vertex) {
        if (neighbor->seen || neighbor->visitid == qh->visit_id)
          continue;
        if (qh_test_appendmerge(qh, newfacet, neighbor, False)) /* ignores optimization for simplicial ridges */
          nummerges++;
      }
    }
  }
  zadd_(Ztestvneighbor, nummerges);
  trace1((qh, qh->ferr, 1016, "qh_test_vneighbors: found %d non-convex, vertex neighbors\n",
           nummerges));
  return (nummerges > 0);
} /* test_vneighbors */

/*---------------------------------

  qh_tracemerge(qh, facet1, facet2 )
    print trace message after merge
*/
void qh_tracemerge(qhT *qh, facetT *facet1, facetT *facet2, mergeType mergetype) {
  boolT waserror= False;
  const char *mergename;

#ifndef qh_NOtrace
  if(mergetype > 0 && mergetype < sizeof(mergetypes)/sizeof(char *))
    mergename= mergetypes[mergetype];
  else
    mergename= mergetypes[MRGnone];
  if (qh->IStracing >= 4)
    qh_errprint(qh, "MERGED", facet2, NULL, NULL, NULL);
  if (facet2 == qh->tracefacet || (qh->tracevertex && qh->tracevertex->newfacet)) {
    qh_fprintf(qh, qh->ferr, 8085, "qh_tracemerge: trace facet and vertex after merge of f%d into f%d type %d (%s), furthest p%d\n",
      facet1->id, facet2->id, mergetype, mergename, qh->furthest_id);
    if (facet2 != qh->tracefacet)
      qh_errprint(qh, "TRACE", qh->tracefacet,
        (qh->tracevertex && qh->tracevertex->neighbors) ?
           SETfirstt_(qh->tracevertex->neighbors, facetT) : NULL,
        NULL, qh->tracevertex);
  }
  if (qh->tracevertex) {
    if (qh->tracevertex->deleted)
      qh_fprintf(qh, qh->ferr, 8086, "qh_tracemerge: trace vertex deleted at furthest p%d\n",
            qh->furthest_id);
    else
      qh_checkvertex(qh, qh->tracevertex, qh_ALL, &waserror);
  }
  if (qh->tracefacet && qh->tracefacet->normal && !qh->tracefacet->visible)
    qh_checkfacet(qh, qh->tracefacet, True /* newmerge */, &waserror);
#endif /* !qh_NOtrace */
  if (qh->CHECKfrequently || qh->IStracing >= 4) { /* can't check polygon here */
    if (qh->IStracing >= 4 && qh->num_facets < 500) {
      qh_printlists(qh);
    }
    qh_checkfacet(qh, facet2, True /* newmerge */, &waserror);
  }
  if (waserror)
    qh_errexit(qh, qh_ERRqhull, NULL, NULL); /* erroneous facet logged by qh_checkfacet */
} /* tracemerge */

/*---------------------------------

  qh_tracemerging(qh)
    print trace message during POSTmerging

  returns:
    updates qh.mergereport

  notes:
    called from qh_mergecycle() and qh_mergefacet()

  see:
    qh_buildtracing()
*/
void qh_tracemerging(qhT *qh) {
  realT cpu;
  int total;
  time_t timedata;
  struct tm *tp;

  qh->mergereport= zzval_(Ztotmerge);
  time(&timedata);
  tp= localtime(&timedata);
  cpu= qh_CPUclock;
  cpu /= qh_SECticks;
  total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
  qh_fprintf(qh, qh->ferr, 8087, "\n\
At %d:%d:%d & %2.5g CPU secs, qhull has merged %d facets with max_outside %2.2g, min_vertex %2.2g.\n\
  The hull contains %d facets and %d vertices.\n",
      tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, total, qh->max_outside, qh->min_vertex,
      qh->num_facets - qh->num_visible,
      qh->num_vertices-qh_setsize(qh, qh->del_vertices));
} /* tracemerging */

/*---------------------------------

  qh_updatetested(qh, facet1, facet2 )
    clear facet2->tested and facet1->ridge->tested for merge

  returns:
    deletes facet2->center unless it's already large
      if so, clears facet2->ridge->tested

  notes:
    only called by qh_mergefacet

  design:
    clear facet2->tested
    clear ridge->tested for facet1's ridges
    if facet2 has a centrum
      if facet2 is large
        set facet2->keepcentrum
      else if facet2 has 3 vertices due to many merges, or not large and post merging
        clear facet2->keepcentrum
      unless facet2->keepcentrum
        clear facet2->center to recompute centrum later
        clear ridge->tested for facet2's ridges
*/
void qh_updatetested(qhT *qh, facetT *facet1, facetT *facet2) {
  ridgeT *ridge, **ridgep;
  int size;

  facet2->tested= False;
  FOREACHridge_(facet1->ridges)
    ridge->tested= False;
  if (!facet2->center)
    return;
  size= qh_setsize(qh, facet2->vertices);
  if (!facet2->keepcentrum) {
    if (size > qh->hull_dim + qh_MAXnewcentrum) {
      facet2->keepcentrum= True;
      zinc_(Zwidevertices);
    }
  }else if (size <= qh->hull_dim + qh_MAXnewcentrum) {
    /* center and keepcentrum was set */
    if (size == qh->hull_dim || qh->POSTmerging)
      facet2->keepcentrum= False; /* if many merges need to recompute centrum */
  }
  if (!facet2->keepcentrum) {
    qh_memfree(qh, facet2->center, qh->normal_size);
    facet2->center= NULL;
    FOREACHridge_(facet2->ridges)
      ridge->tested= False;
  }
} /* updatetested */

/*---------------------------------

  qh_vertexridges(qh, vertex, allneighbors )
    return temporary set of ridges adjacent to a vertex
    vertex->neighbors defined (qh_vertexneighbors)

  notes:
    uses qh.visit_id
    does not include implicit ridges for simplicial facets
    skips last neighbor, unless allneighbors.  For new facets, the last neighbor shares ridges with adjacent neighbors
    if the last neighbor is not simplicial, it will have ridges for its simplicial neighbors
    Use allneighbors when a new cone is attached to an existing convex hull
    similar to qh_neighbor_vertices

  design:
    for each neighbor of vertex
      add ridges that include the vertex to ridges
*/
setT *qh_vertexridges(qhT *qh, vertexT *vertex, boolT allneighbors) {
  facetT *neighbor, **neighborp;
  setT *ridges= qh_settemp(qh, qh->TEMPsize);
  int size;

  qh->visit_id += 2;  /* visit_id for vertex neighbors, visit_id-1 for facets of visited ridges */
  FOREACHneighbor_(vertex)
    neighbor->visitid= qh->visit_id;
  FOREACHneighbor_(vertex) {
    if (*neighborp || allneighbors)   /* no new ridges in last neighbor */
      qh_vertexridges_facet(qh, vertex, neighbor, &ridges);
  }
  if (qh->PRINTstatistics || qh->IStracing) {
    size= qh_setsize(qh, ridges);
    zinc_(Zvertexridge);
    zadd_(Zvertexridgetot, size);
    zmax_(Zvertexridgemax, size);
    trace3((qh, qh->ferr, 3011, "qh_vertexridges: found %d ridges for v%d\n",
             size, vertex->id));
  }
  return ridges;
} /* vertexridges */

/*---------------------------------

  qh_vertexridges_facet(qh, vertex, facet, ridges )
    add adjacent ridges for vertex in facet
    neighbor->visitid==qh.visit_id if it hasn't been visited

  returns:
    ridges updated
    sets facet->visitid to qh.visit_id-1

  design:
    for each ridge of facet
      if ridge of visited neighbor (i.e., unprocessed)
        if vertex in ridge
          append ridge
    mark facet processed
*/
void qh_vertexridges_facet(qhT *qh, vertexT *vertex, facetT *facet, setT **ridges) {
  ridgeT *ridge, **ridgep;
  facetT *neighbor;
  int last_i= qh->hull_dim-2;
  vertexT *second, *last;

  FOREACHridge_(facet->ridges) {
    neighbor= otherfacet_(ridge, facet);
    if (neighbor->visitid == qh->visit_id) {
      if (SETfirst_(ridge->vertices) == vertex) {
        qh_setappend(qh, ridges, ridge);
      }else if (last_i > 2) {
        second= SETsecondt_(ridge->vertices, vertexT);
        last= SETelemt_(ridge->vertices, last_i, vertexT);
        if (second->id >= vertex->id && last->id <= vertex->id) { /* vertices inverse sorted by id */
          if (second == vertex || last == vertex)
            qh_setappend(qh, ridges, ridge);
          else if (qh_setin(ridge->vertices, vertex))
            qh_setappend(qh, ridges, ridge);
        }
      }else if (SETelem_(ridge->vertices, last_i) == vertex
          || (last_i > 1 && SETsecond_(ridge->vertices) == vertex)) {
        qh_setappend(qh, ridges, ridge);
      }
    }
  }
  facet->visitid= qh->visit_id-1;
} /* vertexridges_facet */

/*---------------------------------

  qh_willdelete(qh, facet, replace )
    moves facet to visible list for qh_deletevisible
    sets facet->f.replace to replace (may be NULL)
    clears f.ridges and f.neighbors -- no longer valid

  returns:
    bumps qh.num_visible
*/
void qh_willdelete(qhT *qh, facetT *facet, facetT *replace) {

  trace4((qh, qh->ferr, 4081, "qh_willdelete: move f%d to visible list, set its replacement as f%d, and clear f.neighbors and f.ridges\n", facet->id, getid_(replace)));
  if (!qh->visible_list && qh->newfacet_list) {
    qh_fprintf(qh, qh->ferr, 6378, "qhull internal error (qh_willdelete): expecting qh.visible_list at before qh.newfacet_list f%d.   Got NULL\n",
        qh->newfacet_list->id);
    qh_errexit2(qh, qh_ERRqhull, NULL, NULL);
  }
  qh_removefacet(qh, facet);
  qh_prependfacet(qh, facet, &qh->visible_list);
  qh->num_visible++;
  facet->visible= True;
  facet->f.replace= replace;
  if (facet->ridges)
    SETfirst_(facet->ridges)= NULL;
  if (facet->neighbors)
    SETfirst_(facet->neighbors)= NULL;
} /* willdelete */

#else /* qh_NOmerge */

void qh_all_vertexmerges(qhT *qh, int apexpointid, facetT *facet, facetT **retryfacet) {
  QHULL_UNUSED(qh)
  QHULL_UNUSED(apexpointid)
  QHULL_UNUSED(facet)
  QHULL_UNUSED(retryfacet)
}
void qh_premerge(qhT *qh, int apexpointid, realT maxcentrum, realT maxangle) {
  QHULL_UNUSED(qh)
  QHULL_UNUSED(apexpointid)
  QHULL_UNUSED(maxcentrum)
  QHULL_UNUSED(maxangle)
}
void qh_postmerge(qhT *qh, const char *reason, realT maxcentrum, realT maxangle,
                      boolT vneighbors) {
  QHULL_UNUSED(qh)
  QHULL_UNUSED(reason)
  QHULL_UNUSED(maxcentrum)
  QHULL_UNUSED(maxangle)
  QHULL_UNUSED(vneighbors)
}
void qh_checkdelfacet(qhT *qh, facetT *facet, setT *mergeset) {
  QHULL_UNUSED(qh)
  QHULL_UNUSED(facet)
  QHULL_UNUSED(mergeset)
}
void qh_checkdelridge(qhT *qh /* qh.visible_facets, vertex_mergeset */) {
  QHULL_UNUSED(qh)
}
boolT qh_checkzero(qhT *qh, boolT testall) {
  QHULL_UNUSED(qh)
  QHULL_UNUSED(testall)
    
  return True;
}
void qh_freemergesets(qhT *qh) {
  QHULL_UNUSED(qh)
}
void qh_initmergesets(qhT *qh) {
  QHULL_UNUSED(qh)
}
void qh_merge_pinchedvertices(qhT *qh, int apexpointid /* qh.newfacet_list */) {
  QHULL_UNUSED(qh)
  QHULL_UNUSED(apexpointid)
}
#endif /* qh_NOmerge */

qhull-2020.2/src/libqhull_r/merge_r.h0000644060175106010010000002757313661631132015723 0ustar  bbarber/*
  ---------------------------------

   merge_r.h
   header file for merge_r.c

   see qh-merge_r.htm and merge_r.c

   Copyright (c) 1993-2020 C.B. Barber.
   $Id: //main/2019/qhull/src/libqhull_r/merge_r.h#2 $$Change: 2953 $
   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
*/

#ifndef qhDEFmerge
#define qhDEFmerge 1

#include "libqhull_r.h"


/*============ -constants- ==============*/

/*----------------------------------

  qh_ANGLEnone
    indicates missing angle for mergeT->angle
*/
#define qh_ANGLEnone 2.0

/*----------------------------------

  MRG... (mergeType)
    indicates the type of a merge (mergeT->type)
    MRGcoplanar...MRGtwisted set by qh_test_centrum_merge, qh_test_nonsimplicial_merge
*/
typedef enum {  /* must match mergetypes[] */
  MRGnone= 0,
                  /* MRGcoplanar..MRGtwisted go into qh.facet_mergeset for qh_all_merges 
                     qh_compare_facetmerge selects lower mergetypes for merging first */
  MRGcoplanar,          /* (1) centrum coplanar if centrum ('Cn') or vertex not clearly above or below neighbor */
  MRGanglecoplanar,     /* (2) angle coplanar if angle ('An') is coplanar */
  MRGconcave,           /* (3) concave ridge */
  MRGconcavecoplanar,   /* (4) concave and coplanar ridge, one side concave, other side coplanar */
  MRGtwisted,           /* (5) twisted ridge, both concave and convex, facet1 is wider */
                  /* MRGflip go into qh.facet_mergeset for qh_flipped_merges */
  MRGflip,              /* (6) flipped facet if qh.interior_point is above facet, w/ facet1 == facet2 */
                  /* MRGdupridge go into qh.facet_mergeset for qh_forcedmerges */
  MRGdupridge,          /* (7) dupridge if more than two neighbors.  Set by qh_mark_dupridges for qh_MERGEridge */
                  /* MRGsubridge and MRGvertices go into vertex_mergeset */
  MRGsubridge,          /* (8) merge pinched vertex to remove the subridge of a MRGdupridge */
  MRGvertices,          /* (9) merge pinched vertex to remove a facet's ridges with the same vertices */
                  /* MRGdegen, MRGredundant, and MRGmirror go into qh.degen_mergeset */
  MRGdegen,             /* (10) degenerate facet (!enough neighbors) facet1 == facet2 */
  MRGredundant,         /* (11) redundant facet (vertex subset) */
                        /* merge_degenredundant assumes degen < redundant */
  MRGmirror,            /* (12) mirror facets: same vertices due to null facets in qh_triangulate 
                           f.redundant for both facets*/
                  /* MRGcoplanarhorizon for qh_mergecycle_all only */
  MRGcoplanarhorizon,   /* (13) new facet coplanar with the horizon (qh_mergecycle_all) */
  ENDmrg
} mergeType;

/*----------------------------------

  qh_MERGEapex
    flag for qh_mergefacet() to indicate an apex merge
*/
#define qh_MERGEapex     True

/*============ -structures- ====================*/

/*----------------------------------

  mergeT
    structure used to merge facets
*/

typedef struct mergeT mergeT;
struct mergeT {         /* initialize in qh_appendmergeset */
  realT   angle;        /* cosine of angle between normals of facet1 and facet2, 
                           null value and right angle is 0.0, coplanar is 1.0, narrow is -1.0 */
  realT   distance;     /* absolute value of distance between vertices, centrum and facet, or vertex and facet */
  facetT *facet1;       /* will merge facet1 into facet2 */
  facetT *facet2;
  vertexT *vertex1;     /* will merge vertext1 into vertex2 for MRGsubridge or MRGvertices */
  vertexT *vertex2;
  ridgeT  *ridge1;      /* the duplicate ridges resolved by MRGvertices */
  ridgeT  *ridge2;      /* merge is deleted if either ridge is deleted (qh_delridge) */
  mergeType mergetype;
};


/*=========== -macros- =========================*/

/*----------------------------------

  FOREACHmerge_( merges ) {...}
    assign 'merge' to each merge in merges

  notes:
    uses 'mergeT *merge, **mergep;'
    if qh_mergefacet(),
      restart or use qh_setdellast() since qh.facet_mergeset may change
    see FOREACHsetelement_
*/
#define FOREACHmerge_(merges) FOREACHsetelement_(mergeT, merges, merge)

/*----------------------------------

  FOREACHmergeA_( vertices ) { ... }
    assign 'mergeA' to each merge in merges

  notes:
    uses 'mergeT *mergeA, *mergeAp;'
    see FOREACHsetelement_
*/
#define FOREACHmergeA_(merges) FOREACHsetelement_(mergeT, merges, mergeA)

/*----------------------------------

  FOREACHmerge_i_(qh, vertices ) { ... }
    assign 'merge' and 'merge_i' for each merge in mergeset

  declare:
    mergeT *merge;
    int     merge_n, merge_i;

  see:
    FOREACHsetelement_i_
*/
#define FOREACHmerge_i_(qh, mergeset) FOREACHsetelement_i_(qh, mergeT, mergeset, merge)

/*============ prototypes in alphabetical order after pre/postmerge =======*/

#ifdef __cplusplus
extern "C" {
#endif

void    qh_premerge(qhT *qh, int apexpointid, realT maxcentrum, realT maxangle);
void    qh_postmerge(qhT *qh, const char *reason, realT maxcentrum, realT maxangle,
             boolT vneighbors);
void    qh_all_merges(qhT *qh, boolT othermerge, boolT vneighbors);
void    qh_all_vertexmerges(qhT *qh, int apexpointid, facetT *facet, facetT **retryfacet);
void    qh_appendmergeset(qhT *qh, facetT *facet, facetT *neighbor, mergeType mergetype, coordT dist, realT angle);
void    qh_appendvertexmerge(qhT *qh, vertexT *vertex, vertexT *destination, mergeType mergetype, realT distance, ridgeT *ridge1, ridgeT *ridge2);
setT   *qh_basevertices(qhT *qh, facetT *samecycle);
void    qh_check_dupridge(qhT *qh, facetT *facet1, realT dist1, facetT *facet2, realT dist2);
void    qh_checkconnect(qhT *qh /* qh.new_facets */);
void    qh_checkdelfacet(qhT *qh, facetT *facet, setT *mergeset);
void    qh_checkdelridge(qhT *qh /* qh.visible_facets, vertex_mergeset */);
boolT   qh_checkzero(qhT *qh, boolT testall);
int     qh_compare_anglemerge(const void *p1, const void *p2);
int     qh_compare_facetmerge(const void *p1, const void *p2);
int     qh_comparevisit(const void *p1, const void *p2);
void    qh_copynonconvex(qhT *qh, ridgeT *atridge);
void    qh_degen_redundant_facet(qhT *qh, facetT *facet);
void    qh_drop_mergevertex(qhT *qh, mergeT *merge);
void    qh_delridge_merge(qhT *qh, ridgeT *ridge);
vertexT *qh_find_newvertex(qhT *qh, vertexT *oldvertex, setT *vertices, setT *ridges);
vertexT *qh_findbest_pinchedvertex(qhT *qh, mergeT *merge, vertexT *apex, vertexT **pinchedp, realT *distp /* qh.newfacet_list */);
vertexT *qh_findbest_ridgevertex(qhT *qh, ridgeT *ridge, vertexT **pinchedp, coordT *distp);
void    qh_findbest_test(qhT *qh, boolT testcentrum, facetT *facet, facetT *neighbor,
           facetT **bestfacet, realT *distp, realT *mindistp, realT *maxdistp);
facetT *qh_findbestneighbor(qhT *qh, facetT *facet, realT *distp, realT *mindistp, realT *maxdistp);
void    qh_flippedmerges(qhT *qh, facetT *facetlist, boolT *wasmerge);
void    qh_forcedmerges(qhT *qh, boolT *wasmerge);
void    qh_freemergesets(qhT *qh);
void    qh_getmergeset(qhT *qh, facetT *facetlist);
void    qh_getmergeset_initial(qhT *qh, facetT *facetlist);
boolT   qh_getpinchedmerges(qhT *qh, vertexT *apex, coordT maxdupdist, boolT *iscoplanar /* qh.newfacet_list, vertex_mergeset */);
boolT   qh_hasmerge(setT *mergeset, mergeType type, facetT *facetA, facetT *facetB);
void    qh_hashridge(qhT *qh, setT *hashtable, int hashsize, ridgeT *ridge, vertexT *oldvertex);
ridgeT *qh_hashridge_find(qhT *qh, setT *hashtable, int hashsize, ridgeT *ridge,
              vertexT *vertex, vertexT *oldvertex, int *hashslot);
void    qh_initmergesets(qhT *qh);
void    qh_makeridges(qhT *qh, facetT *facet);
void    qh_mark_dupridges(qhT *qh, facetT *facetlist, boolT allmerges);
void    qh_maybe_duplicateridge(qhT *qh, ridgeT *ridge);
void    qh_maybe_duplicateridges(qhT *qh, facetT *facet);
void    qh_maydropneighbor(qhT *qh, facetT *facet);
int     qh_merge_degenredundant(qhT *qh);
void    qh_merge_nonconvex(qhT *qh, facetT *facet1, facetT *facet2, mergeType mergetype);
void    qh_merge_pinchedvertices(qhT *qh, int apexpointid /* qh.newfacet_list */);
void    qh_merge_twisted(qhT *qh, facetT *facet1, facetT *facet2);
void    qh_mergecycle(qhT *qh, facetT *samecycle, facetT *newfacet);
void    qh_mergecycle_all(qhT *qh, facetT *facetlist, boolT *wasmerge);
void    qh_mergecycle_facets(qhT *qh, facetT *samecycle, facetT *newfacet);
void    qh_mergecycle_neighbors(qhT *qh, facetT *samecycle, facetT *newfacet);
void    qh_mergecycle_ridges(qhT *qh, facetT *samecycle, facetT *newfacet);
void    qh_mergecycle_vneighbors(qhT *qh, facetT *samecycle, facetT *newfacet);
void    qh_mergefacet(qhT *qh, facetT *facet1, facetT *facet2, mergeType mergetype, realT *mindist, realT *maxdist, boolT mergeapex);
void    qh_mergefacet2d(qhT *qh, facetT *facet1, facetT *facet2);
void    qh_mergeneighbors(qhT *qh, facetT *facet1, facetT *facet2);
void    qh_mergeridges(qhT *qh, facetT *facet1, facetT *facet2);
void    qh_mergesimplex(qhT *qh, facetT *facet1, facetT *facet2, boolT mergeapex);
void    qh_mergevertex_del(qhT *qh, vertexT *vertex, facetT *facet1, facetT *facet2);
void    qh_mergevertex_neighbors(qhT *qh, facetT *facet1, facetT *facet2);
void    qh_mergevertices(qhT *qh, setT *vertices1, setT **vertices);
setT   *qh_neighbor_intersections(qhT *qh, vertexT *vertex);
setT   *qh_neighbor_vertices(qhT *qh, vertexT *vertex, setT *subridge);
void    qh_neighbor_vertices_facet(qhT *qh, vertexT *vertexA, facetT *facet, setT **vertices);
void    qh_newvertices(qhT *qh, setT *vertices);
mergeT *qh_next_vertexmerge(qhT *qh);
facetT *qh_opposite_horizonfacet(qhT *qh, mergeT *merge, vertexT **vertex);
boolT   qh_reducevertices(qhT *qh);
vertexT *qh_redundant_vertex(qhT *qh, vertexT *vertex);
boolT   qh_remove_extravertices(qhT *qh, facetT *facet);
void    qh_remove_mergetype(qhT *qh, setT *mergeset, mergeType type);
void    qh_rename_adjacentvertex(qhT *qh, vertexT *oldvertex, vertexT *newvertex, realT dist);
vertexT *qh_rename_sharedvertex(qhT *qh, vertexT *vertex, facetT *facet);
boolT   qh_renameridgevertex(qhT *qh, ridgeT *ridge, vertexT *oldvertex, vertexT *newvertex);
void    qh_renamevertex(qhT *qh, vertexT *oldvertex, vertexT *newvertex, setT *ridges,
                        facetT *oldfacet, facetT *neighborA);
boolT   qh_test_appendmerge(qhT *qh, facetT *facet, facetT *neighbor, boolT simplicial);
void    qh_test_degen_neighbors(qhT *qh, facetT *facet);
boolT   qh_test_centrum_merge(qhT *qh, facetT *facet, facetT *neighbor, realT angle, boolT okangle);
boolT   qh_test_nonsimplicial_merge(qhT *qh, facetT *facet, facetT *neighbor, realT angle, boolT okangle);
void    qh_test_redundant_neighbors(qhT *qh, facetT *facet);
boolT   qh_test_vneighbors(qhT *qh /* qh.newfacet_list */);
void    qh_tracemerge(qhT *qh, facetT *facet1, facetT *facet2, mergeType mergetype);
void    qh_tracemerging(qhT *qh);
void    qh_undo_newfacets(qhT *qh);
void    qh_updatetested(qhT *qh, facetT *facet1, facetT *facet2);
setT   *qh_vertexridges(qhT *qh, vertexT *vertex, boolT allneighbors);
void    qh_vertexridges_facet(qhT *qh, vertexT *vertex, facetT *facet, setT **ridges);
void    qh_willdelete(qhT *qh, facetT *facet, facetT *replace);

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* qhDEFmerge */
qhull-2020.2/src/libqhull_r/poly2_r.c0000644060175106010010000046520213661631132015657 0ustar  bbarber/*
  ---------------------------------

   poly2_r.c
   implements polygons and simplicies

   see qh-poly_r.htm, poly_r.h and libqhull_r.h

   frequently used code is in poly_r.c

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull_r/poly2_r.c#20 $$Change: 2953 $
   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
*/

#include "qhull_ra.h"

/*======== functions in alphabetical order ==========*/

/*---------------------------------

  qh_addfacetvertex(qh, facet, newvertex )
    add newvertex to facet.vertices if not already there
    vertices are inverse sorted by vertex->id

  returns:
    True if new vertex for facet

  notes:
    see qh_replacefacetvertex
*/
boolT qh_addfacetvertex(qhT *qh, facetT *facet, vertexT *newvertex) {
  vertexT *vertex;
  int vertex_i= 0, vertex_n;
  boolT isnew= True;

  FOREACHvertex_i_(qh, facet->vertices) {
    if (vertex->id < newvertex->id) {
      break;
    }else if (vertex->id == newvertex->id) {
      isnew= False;
      break;
    }
  }
  if (isnew)
    qh_setaddnth(qh, &facet->vertices, vertex_i, newvertex);
  return isnew;
} /* addfacetvertex */

/*---------------------------------

  qh_addhash( newelem, hashtable, hashsize, hash )
    add newelem to linear hash table at hash if not already there
*/
void qh_addhash(void *newelem, setT *hashtable, int hashsize, int hash) {
  int scan;
  void *elem;

  for (scan= (int)hash; (elem= SETelem_(hashtable, scan));
       scan= (++scan >= hashsize ? 0 : scan)) {
    if (elem == newelem)
      break;
  }
  /* loop terminates because qh_HASHfactor >= 1.1 by qh_initbuffers */
  if (!elem)
    SETelem_(hashtable, scan)= newelem;
} /* addhash */

/*---------------------------------

  qh_check_bestdist(qh)
    check that all points are within max_outside of the nearest facet
    if qh.ONLYgood,
      ignores !good facets

  see:
    qh_check_maxout(), qh_outerinner()

  notes:
    only called from qh_check_points()
      seldom used since qh.MERGING is almost always set
    if notverified>0 at end of routine
      some points were well inside the hull.  If the hull contains
      a lens-shaped component, these points were not verified.  Use
      options 'Qi Tv' to verify all points.  (Exhaustive check also verifies)

  design:
    determine facet for each point (if any)
    for each point
      start with the assigned facet or with the first facet
      find the best facet for the point and check all coplanar facets
      error if point is outside of facet
*/
void qh_check_bestdist(qhT *qh) {
  boolT waserror= False, unassigned;
  facetT *facet, *bestfacet, *errfacet1= NULL, *errfacet2= NULL;
  facetT *facetlist;
  realT dist, maxoutside, maxdist= -REALmax;
  pointT *point;
  int numpart= 0, facet_i, facet_n, notgood= 0, notverified= 0;
  setT *facets;

  trace1((qh, qh->ferr, 1020, "qh_check_bestdist: check points below nearest facet.  Facet_list f%d\n",
      qh->facet_list->id));
  maxoutside= qh_maxouter(qh);
  maxoutside += qh->DISTround;
  /* one more qh.DISTround for check computation */
  trace1((qh, qh->ferr, 1021, "qh_check_bestdist: check that all points are within %2.2g of best facet\n", maxoutside));
  facets= qh_pointfacet(qh /* qh.facet_list */);
  if (!qh_QUICKhelp && qh->PRINTprecision)
    qh_fprintf(qh, qh->ferr, 8091, "\n\
qhull output completed.  Verifying that %d points are\n\
below %2.2g of the nearest %sfacet.\n",
             qh_setsize(qh, facets), maxoutside, (qh->ONLYgood ?  "good " : ""));
  FOREACHfacet_i_(qh, facets) {  /* for each point with facet assignment */
    if (facet)
      unassigned= False;
    else {
      unassigned= True;
      facet= qh->facet_list;
    }
    point= qh_point(qh, facet_i);
    if (point == qh->GOODpointp)
      continue;
    qh_distplane(qh, point, facet, &dist);
    numpart++;
    bestfacet= qh_findbesthorizon(qh, !qh_IScheckmax, point, facet, qh_NOupper, &dist, &numpart);
    /* occurs after statistics reported */
    maximize_(maxdist, dist);
    if (dist > maxoutside) {
      if (qh->ONLYgood && !bestfacet->good
      && !((bestfacet= qh_findgooddist(qh, point, bestfacet, &dist, &facetlist))
      && dist > maxoutside))
        notgood++;
      else {
        waserror= True;
        qh_fprintf(qh, qh->ferr, 6109, "qhull precision error (qh_check_bestdist): point p%d is outside facet f%d, distance= %6.8g maxoutside= %6.8g\n",
                facet_i, bestfacet->id, dist, maxoutside);
        if (errfacet1 != bestfacet) {
          errfacet2= errfacet1;
          errfacet1= bestfacet;
        }
      }
    }else if (unassigned && dist < -qh->MAXcoplanar)
      notverified++;
  }
  qh_settempfree(qh, &facets);
  if (notverified && !qh->DELAUNAY && !qh_QUICKhelp && qh->PRINTprecision)
    qh_fprintf(qh, qh->ferr, 8092, "\n%d points were well inside the hull.  If the hull contains\n\
a lens-shaped component, these points were not verified.  Use\n\
options 'Qci Tv' to verify all points.\n", notverified);
  if (maxdist > qh->outside_err) {
    qh_fprintf(qh, qh->ferr, 6110, "qhull precision error (qh_check_bestdist): a coplanar point is %6.2g from convex hull.  The maximum value is qh.outside_err (%6.2g)\n",
              maxdist, qh->outside_err);
    qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2);
  }else if (waserror && qh->outside_err > REALmax/2)
    qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2);
  /* else if waserror, the error was logged to qh.ferr but does not effect the output */
  trace0((qh, qh->ferr, 20, "qh_check_bestdist: max distance outside %2.2g\n", maxdist));
} /* check_bestdist */

#ifndef qh_NOmerge
/*---------------------------------

  qh_check_maxout(qh)
    updates qh.max_outside by checking all points against bestfacet
    if qh.ONLYgood, ignores !good facets

  returns:
    updates facet->maxoutside via qh_findbesthorizon()
    sets qh.maxoutdone
    if printing qh.min_vertex (qh_outerinner),
      it is updated to the current vertices
    removes inside/coplanar points from coplanarset as needed

  notes:
    defines coplanar as qh.min_vertex instead of qh.MAXcoplanar
    may not need to check near-inside points because of qh.MAXcoplanar
      and qh.KEEPnearinside (before it was -qh.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
*/
void qh_check_maxout(qhT *qh) {
  facetT *facet, *bestfacet, *neighbor, **neighborp, *facetlist, *maxbestfacet= NULL, *minfacet, *maxfacet, *maxpointfacet;
  realT dist, maxoutside, mindist, nearest;
  realT maxoutside_base, minvertex_base;
  pointT *point, *maxpoint= NULL;
  int numpart= 0, facet_i, facet_n, notgood= 0;
  setT *facets, *vertices;
  vertexT *vertex, *minvertex;

  trace1((qh, qh->ferr, 1022, "qh_check_maxout: check and update qh.min_vertex %2.2g and qh.max_outside %2.2g\n", qh->min_vertex, qh->max_outside));
  minvertex_base= fmin_(qh->min_vertex, -(qh->ONEmerge+qh->DISTround));
  maxoutside= mindist= 0.0;
  minvertex= qh->vertex_list;
  maxfacet= minfacet= maxpointfacet= qh->facet_list;
  if (qh->VERTEXneighbors
  && (qh->PRINTsummary || qh->KEEPinside || qh->KEEPcoplanar
        || qh->TRACElevel || qh->PRINTstatistics || qh->VERIFYoutput || qh->CHECKfrequently
        || qh->PRINTout[0] == qh_PRINTsummary || qh->PRINTout[0] == qh_PRINTnone)) {
    trace1((qh, qh->ferr, 1023, "qh_check_maxout: determine actual minvertex\n"));
    vertices= qh_pointvertex(qh /* qh.facet_list */);
    FORALLvertices {
      FOREACHneighbor_(vertex) {
        zinc_(Zdistvertex);  /* distance also computed by main loop below */
        qh_distplane(qh, vertex->point, neighbor, &dist);
        if (dist < mindist) {
          if (qh->min_vertex/minvertex_base > qh_WIDEmaxoutside && (qh->PRINTprecision || !qh->ALLOWwide)) {
            nearest= qh_vertex_bestdist(qh, neighbor->vertices);
            /* should be caught in qh_mergefacet */
            qh_fprintf(qh, qh->ferr, 7083, "Qhull precision warning: in post-processing (qh_check_maxout) p%d(v%d) is %2.2g below f%d nearest vertices %2.2g\n",
              qh_pointid(qh, vertex->point), vertex->id, dist, neighbor->id, nearest);
          }
          mindist= dist;
          minvertex= vertex;
          minfacet= neighbor;
        }
#ifndef qh_NOtrace
        if (-dist > qh->TRACEdist || dist > qh->TRACEdist
        || neighbor == qh->tracefacet || vertex == qh->tracevertex) {
          nearest= qh_vertex_bestdist(qh, neighbor->vertices);
          qh_fprintf(qh, qh->ferr, 8093, "qh_check_maxout: p%d(v%d) is %.2g from f%d nearest vertices %2.2g\n",
                    qh_pointid(qh, vertex->point), vertex->id, dist, neighbor->id, nearest);
        }
#endif
      }
    }
    if (qh->MERGING) {
      wmin_(Wminvertex, qh->min_vertex);
    }
    qh->min_vertex= mindist;
    qh_settempfree(qh, &vertices);
  }
  trace1((qh, qh->ferr, 1055, "qh_check_maxout: determine actual maxoutside\n"));
  maxoutside_base= fmax_(qh->max_outside, qh->ONEmerge+qh->DISTround);
  /* maxoutside_base is same as qh.MAXoutside without qh.MINoutside (qh_detmaxoutside) */
  facets= qh_pointfacet(qh /* qh.facet_list */);
  FOREACHfacet_i_(qh, facets) {     /* for each point with facet assignment */
    if (facet) {
      point= qh_point(qh, facet_i);
      if (point == qh->GOODpointp)
        continue;
      zzinc_(Ztotcheck);
      qh_distplane(qh, point, facet, &dist);
      numpart++;
      bestfacet= qh_findbesthorizon(qh, qh_IScheckmax, point, facet, !qh_NOupper, &dist, &numpart);
      if (bestfacet && dist >= maxoutside) { 
        if (qh->ONLYgood && !bestfacet->good
        && !((bestfacet= qh_findgooddist(qh, point, bestfacet, &dist, &facetlist))
        && dist > maxoutside)) {       
          notgood++;
        }else if (dist/maxoutside_base > qh_WIDEmaxoutside && (qh->PRINTprecision || !qh->ALLOWwide)) {
          nearest= qh_vertex_bestdist(qh, bestfacet->vertices);
          if (nearest < fmax_(qh->ONEmerge, qh->max_outside) * qh_RATIOcoplanaroutside * 2) {
            qh_fprintf(qh, qh->ferr, 7087, "Qhull precision warning: in post-processing (qh_check_maxout) p%d for f%d is %2.2g above twisted facet f%d nearest vertices %2.2g\n",
              qh_pointid(qh, point), facet->id, dist, bestfacet->id, nearest);
          }else {
            qh_fprintf(qh, qh->ferr, 7088, "Qhull precision warning: in post-processing (qh_check_maxout) p%d for f%d is %2.2g above hidden facet f%d nearest vertices %2.2g\n",
              qh_pointid(qh, point), facet->id, dist, bestfacet->id, nearest);
          }
          maxbestfacet= bestfacet;
        }
        maxoutside= dist;
        maxfacet= bestfacet;
        maxpoint= point;
        maxpointfacet= facet;
      }
      if (dist > qh->TRACEdist || (bestfacet && bestfacet == qh->tracefacet))
        qh_fprintf(qh, qh->ferr, 8094, "qh_check_maxout: p%d is %.2g above f%d\n",
              qh_pointid(qh, point), dist, (bestfacet ? bestfacet->id : UINT_MAX));
    }
  }
  zzadd_(Zcheckpart, numpart);
  qh_settempfree(qh, &facets);
  wval_(Wmaxout)= maxoutside - qh->max_outside;
  wmax_(Wmaxoutside, qh->max_outside);
  if (!qh->APPROXhull && maxoutside > qh->DISTround) { /* initial value for f.maxoutside */
    FORALLfacets {
      if (maxoutside < facet->maxoutside) {
        if (!qh->KEEPcoplanar) {
          maxoutside= facet->maxoutside;
        }else if (maxoutside + qh->DISTround < facet->maxoutside) { /* maxoutside is computed distance, e.g., rbox 100 s D3 t1547136913 | qhull R1e-3 Tcv Qc */
          qh_fprintf(qh, qh->ferr, 7082, "Qhull precision warning (qh_check_maxout): f%d.maxoutside (%4.4g) is greater than computed qh.max_outside (%2.2g) + qh.DISTround (%2.2g).  It should be less than or equal\n",
            facet->id, facet->maxoutside, maxoutside, qh->DISTround); 
        }
      }
    }
  }
  qh->max_outside= maxoutside; 
  qh_nearcoplanar(qh /* qh.facet_list */);
  qh->maxoutdone= True;
  trace1((qh, qh->ferr, 1024, "qh_check_maxout:  p%d(v%d) is qh.min_vertex %2.2g below facet f%d.  Point p%d for f%d is qh.max_outside %2.2g above f%d.  %d points are outside of not-good facets\n", 
    qh_pointid(qh, minvertex->point), minvertex->id, qh->min_vertex, minfacet->id, qh_pointid(qh, maxpoint), maxpointfacet->id, qh->max_outside, maxfacet->id, notgood));
  if(!qh->ALLOWwide) {
    if (maxoutside/maxoutside_base > qh_WIDEmaxoutside) {
      qh_fprintf(qh, qh->ferr, 6297, "Qhull precision error (qh_check_maxout): large increase in qh.max_outside during post-processing dist %2.2g (%.1fx).  See warning QH0032/QH0033.  Allow with 'Q12' (allow-wide) and 'Pp'\n",
        maxoutside, maxoutside/maxoutside_base);
      qh_errexit(qh, qh_ERRwide, maxbestfacet, NULL);
    }else if (!qh->APPROXhull && maxoutside_base > (qh->ONEmerge * qh_WIDEmaxoutside2)) {
      if (maxoutside > (qh->ONEmerge * qh_WIDEmaxoutside2)) {  /* wide facets may have been deleted */
        qh_fprintf(qh, qh->ferr, 6298, "Qhull precision error (qh_check_maxout): a facet merge, vertex merge, vertex, or coplanar point produced a wide facet %2.2g (%.1fx). Trace with option 'TWn' to identify the merge.   Allow with 'Q12' (allow-wide)\n",
          maxoutside_base, maxoutside_base/(qh->ONEmerge + qh->DISTround));
        qh_errexit(qh, qh_ERRwide, maxbestfacet, NULL);
      }
    }else if (qh->min_vertex/minvertex_base > qh_WIDEmaxoutside) {
      qh_fprintf(qh, qh->ferr, 6354, "Qhull precision error (qh_check_maxout): large increase in qh.min_vertex during post-processing dist %2.2g (%.1fx).  See warning QH7083.  Allow with 'Q12' (allow-wide) and 'Pp'\n",
        qh->min_vertex, qh->min_vertex/minvertex_base);
      qh_errexit(qh, qh_ERRwide, minfacet, NULL);
    }else if (minvertex_base < -(qh->ONEmerge * qh_WIDEmaxoutside2)) {
      if (qh->min_vertex < -(qh->ONEmerge * qh_WIDEmaxoutside2)) {  /* wide facets may have been deleted */
        qh_fprintf(qh, qh->ferr, 6380, "Qhull precision error (qh_check_maxout): a facet or vertex merge produced a wide facet: v%d below f%d distance %2.2g (%.1fx). Trace with option 'TWn' to identify the merge.  Allow with 'Q12' (allow-wide)\n",
          minvertex->id, minfacet->id, mindist, -qh->min_vertex/(qh->ONEmerge + qh->DISTround));
        qh_errexit(qh, qh_ERRwide, minfacet, NULL);
      }
    }
  }
} /* check_maxout */
#else /* qh_NOmerge */
void qh_check_maxout(qhT *qh) {
  QHULL_UNUSED(qh)
}
#endif

/*---------------------------------

  qh_check_output(qh)
    performs the checks at the end of qhull algorithm
    Maybe called after Voronoi output.  If so, it recomputes centrums since they are Voronoi centers instead.
*/
void qh_check_output(qhT *qh) {
  int i;

  if (qh->STOPcone)
    return;
  if (qh->VERIFYoutput || qh->IStracing || qh->CHECKfrequently) {
    qh_checkpolygon(qh, qh->facet_list);
    qh_checkflipped_all(qh, qh->facet_list);
    qh_checkconvex(qh, qh->facet_list, qh_ALGORITHMfault);
  }else if (!qh->MERGING && qh_newstats(qh, qh->qhstat.precision, &i)) {
    qh_checkflipped_all(qh, qh->facet_list);
    qh_checkconvex(qh, qh->facet_list, qh_ALGORITHMfault);
  }
} /* check_output */



/*---------------------------------

  qh_check_point(qh, point, facet, maxoutside, maxdist, errfacet1, errfacet2, errcount )
    check that point is less than maxoutside from facet

  notes:
    only called from qh_checkpoints
    reports up to qh_MAXcheckpoint-1 errors per facet
*/
void qh_check_point(qhT *qh, pointT *point, facetT *facet, realT *maxoutside, realT *maxdist, facetT **errfacet1, facetT **errfacet2, int *errcount) {
  realT dist, nearest;

  /* occurs after statistics reported */
  qh_distplane(qh, point, facet, &dist);
  maximize_(*maxdist, dist);
  if (dist > *maxoutside) {
    (*errcount)++;
    if (*errfacet1 != facet) {
      *errfacet2= *errfacet1;
      *errfacet1= facet;
    }
    if (*errcount < qh_MAXcheckpoint) {
      nearest= qh_vertex_bestdist(qh, facet->vertices);
      qh_fprintf(qh, qh->ferr, 6111, "qhull precision error: point p%d is outside facet f%d, distance= %6.8g maxoutside= %6.8g nearest vertices %2.2g\n",
                qh_pointid(qh, point), facet->id, dist, *maxoutside, nearest);
    }
  }
} /* qh_check_point */


/*---------------------------------

  qh_check_points(qh)
    checks that all points are inside all facets

  notes:
    if many points and qh_check_maxout not called (i.e., !qh.MERGING),
       calls qh_findbesthorizon via qh_check_bestdist (seldom done).
    ignores flipped facets
    maxoutside includes 2 qh.DISTrounds
      one qh.DISTround for the computed distances in qh_check_points
    qh_printafacet and qh_printsummary needs only one qh.DISTround
    the computation for qh.VERIFYdirect does not account for qh.other_points

  design:
    if many points
      use qh_check_bestdist()
    else
      for all facets
        for all points
          check that point is inside facet
*/
void qh_check_points(qhT *qh) {
  facetT *facet, *errfacet1= NULL, *errfacet2= NULL;
  realT total, maxoutside, maxdist= -REALmax;
  pointT *point, **pointp, *pointtemp;
  int errcount;
  boolT testouter;

  maxoutside= qh_maxouter(qh);
  maxoutside += qh->DISTround;
  /* one more qh.DISTround for check computation */
  trace1((qh, qh->ferr, 1025, "qh_check_points: check all points below %2.2g of all facet planes\n",
          maxoutside));
  if (qh->num_good)   /* miss counts other_points and !good facets */
     total= (float)qh->num_good * (float)qh->num_points;
  else
     total= (float)qh->num_facets * (float)qh->num_points;
  if (total >= qh_VERIFYdirect && !qh->maxoutdone) {
    if (!qh_QUICKhelp && qh->SKIPcheckmax && qh->MERGING)
      qh_fprintf(qh, qh->ferr, 7075, "qhull input warning: merging without checking outer planes('Q5' or 'Po').  Verify may report that a point is outside of a facet.\n");
    qh_check_bestdist(qh);
  }else {
    if (qh_MAXoutside && qh->maxoutdone)
      testouter= True;
    else
      testouter= False;
    if (!qh_QUICKhelp) {
      if (qh->MERGEexact)
        qh_fprintf(qh, qh->ferr, 7076, "qhull input warning: exact merge ('Qx').  Verify may report that a point is outside of a facet.  See qh-optq.htm#Qx\n");
      else if (qh->SKIPcheckmax || qh->NOnearinside)
        qh_fprintf(qh, qh->ferr, 7077, "qhull input warning: no outer plane check ('Q5') or no processing of near-inside points ('Q8').  Verify may report that a point is outside of a facet.\n");
    }
    if (qh->PRINTprecision) {
      if (testouter)
        qh_fprintf(qh, qh->ferr, 8098, "\n\
Output completed.  Verifying that all points are below outer planes of\n\
all %sfacets.  Will make %2.0f distance computations.\n",
              (qh->ONLYgood ?  "good " : ""), total);
      else
        qh_fprintf(qh, qh->ferr, 8099, "\n\
Output completed.  Verifying that all points are below %2.2g of\n\
all %sfacets.  Will make %2.0f distance computations.\n",
              maxoutside, (qh->ONLYgood ?  "good " : ""), total);
    }
    FORALLfacets {
      if (!facet->good && qh->ONLYgood)
        continue;
      if (facet->flipped)
        continue;
      if (!facet->normal) {
        qh_fprintf(qh, qh->ferr, 7061, "qhull warning (qh_check_points): missing normal for facet f%d\n", facet->id);
        if (!errfacet1)
          errfacet1= facet;
        continue;
      }
      if (testouter) {
#if qh_MAXoutside
        maxoutside= facet->maxoutside + 2 * qh->DISTround;
        /* one DISTround to actual point and another to computed point */
#endif
      }
      errcount= 0;
      FORALLpoints {
        if (point != qh->GOODpointp)
          qh_check_point(qh, point, facet, &maxoutside, &maxdist, &errfacet1, &errfacet2, &errcount);
      }
      FOREACHpoint_(qh->other_points) {
        if (point != qh->GOODpointp)
          qh_check_point(qh, point, facet, &maxoutside, &maxdist, &errfacet1, &errfacet2, &errcount);
      }
      if (errcount >= qh_MAXcheckpoint) {
        qh_fprintf(qh, qh->ferr, 6422, "qhull precision error (qh_check_points): %d additional points outside facet f%d, maxdist= %6.8g\n",
             errcount-qh_MAXcheckpoint+1, facet->id, maxdist);
      }
    }
    if (maxdist > qh->outside_err) {
      qh_fprintf(qh, qh->ferr, 6112, "qhull precision error (qh_check_points): a coplanar point is %6.2g from convex hull.  The maximum value(qh.outside_err) is %6.2g\n",
                maxdist, qh->outside_err );
      qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2 );
    }else if (errfacet1 && qh->outside_err > REALmax/2)
        qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2 );
    /* else if errfacet1, the error was logged to qh.ferr but does not effect the output */
    trace0((qh, qh->ferr, 21, "qh_check_points: max distance outside %2.2g\n", maxdist));
  }
} /* check_points */


/*---------------------------------

  qh_checkconvex(qh, facetlist, fault )
    check that each ridge in facetlist is convex
    fault = qh_DATAfault if reporting errors from qh_initialhull with qh.ZEROcentrum
          = qh_ALGORITHMfault otherwise

  returns:
    counts Zconcaveridges and Zcoplanarridges
    errors if !qh.FORCEoutput ('Fo') and concaveridge or if merging a coplanar ridge
    overwrites Voronoi centers if set by qh_setvoronoi_all/qh_ASvoronoi

  notes:
    called by qh_initial_hull, qh_check_output, qh_all_merges ('Tc'), qh_build_withrestart ('QJ')
    does not test f.tricoplanar facets (qh_triangulate)
    must be no stronger than qh_test_appendmerge
    if not merging,
      tests vertices for neighboring simplicial facets < -qh.DISTround
    else if ZEROcentrum and simplicial facet,
      tests vertices for neighboring simplicial facets < 0.0
      tests centrums of neighboring nonsimplicial facets < 0.0
    else if ZEROcentrum 
      tests centrums of neighboring facets < 0.0
    else 
      tests centrums of neighboring facets < -qh.DISTround ('En' 'Rn')
    Does not test against -qh.centrum_radius since repeated computations may have different round-off errors (e.g., 'Rn')

  design:
    for all facets
      report flipped facets
      if ZEROcentrum and simplicial neighbors
        test vertices against neighbor
      else
        test centrum against neighbor
*/
void qh_checkconvex(qhT *qh, facetT *facetlist, int fault) {
  facetT *facet, *neighbor, **neighborp, *errfacet1=NULL, *errfacet2=NULL;
  vertexT *vertex;
  realT dist;
  pointT *centrum;
  boolT waserror= False, centrum_warning= False, tempcentrum= False, first_nonsimplicial= False, tested_simplicial, allsimplicial;
  int neighbor_i, neighbor_n;

  if (qh->ZEROcentrum) {
    trace1((qh, qh->ferr, 1064, "qh_checkconvex: check that facets are not-flipped and for qh.ZEROcentrum that simplicial vertices are below their neighbor (dist<0.0)\n"));
    first_nonsimplicial= True;
  }else if (!qh->MERGING) {
    trace1((qh, qh->ferr, 1026, "qh_checkconvex: check that facets are not-flipped and that simplicial vertices are convex by qh.DISTround ('En', 'Rn')\n"));
    first_nonsimplicial= True;
  }else
    trace1((qh, qh->ferr, 1062, "qh_checkconvex: check that facets are not-flipped and that their centrums are convex by qh.DISTround ('En', 'Rn') \n"));
  if (!qh->RERUN) {
    zzval_(Zconcaveridges)= 0;
    zzval_(Zcoplanarridges)= 0;
  }
  FORALLfacet_(facetlist) {
    if (facet->flipped) {
      qh_joggle_restart(qh, "flipped facet"); /* also tested by qh_checkflipped */
      qh_fprintf(qh, qh->ferr, 6113, "qhull precision error: f%d is flipped (interior point is outside)\n",
               facet->id);
      errfacet1= facet;
      waserror= True;
      continue;
    }
    if (facet->tricoplanar)
      continue;
    if (qh->MERGING && (!qh->ZEROcentrum || !facet->simplicial)) {
      allsimplicial= False;
      tested_simplicial= False;
    }else {
      allsimplicial= True;
      tested_simplicial= True;
      FOREACHneighbor_i_(qh, facet) {
        if (neighbor->tricoplanar)
          continue;
        if (!neighbor->simplicial) {
          allsimplicial= False;
          continue;
        }
        vertex= SETelemt_(facet->vertices, neighbor_i, vertexT);
        qh_distplane(qh, vertex->point, neighbor, &dist);
        if (dist >= -qh->DISTround) {
          if (fault == qh_DATAfault) {
            qh_joggle_restart(qh, "non-convex initial simplex");
            if (dist > qh->DISTround)
              qh_fprintf(qh, qh->ferr, 6114, "qhull precision error: initial simplex is not convex, since p%d(v%d) is %6.4g above opposite f%d\n", 
                  qh_pointid(qh, vertex->point), vertex->id, dist, neighbor->id);
            else
              qh_fprintf(qh, qh->ferr, 6379, "qhull precision error: initial simplex is not convex, since p%d(v%d) is within roundoff of opposite facet f%d (dist %6.4g)\n",
                  qh_pointid(qh, vertex->point), vertex->id, neighbor->id, dist);
            qh_errexit(qh, qh_ERRsingular, neighbor, NULL);
          }
          if (dist > qh->DISTround) {
            zzinc_(Zconcaveridges);
            qh_joggle_restart(qh, "concave ridge");
            qh_fprintf(qh, qh->ferr, 6115, "qhull precision error: f%d is concave to f%d, since p%d(v%d) is %6.4g above f%d\n",
              facet->id, neighbor->id, qh_pointid(qh, vertex->point), vertex->id, dist, neighbor->id);
            errfacet1= facet;
            errfacet2= neighbor;
            waserror= True;
          }else if (qh->ZEROcentrum) {
            if (dist > 0.0) {     /* qh_checkzero checked convex (dist < (- 2*qh->DISTround)), computation may differ e.g. 'Rn' */
              zzinc_(Zcoplanarridges);
              qh_joggle_restart(qh, "coplanar ridge");
              qh_fprintf(qh, qh->ferr, 6116, "qhull precision error: f%d is clearly not convex to f%d, since p%d(v%d) is %6.4g above or coplanar with f%d with qh.ZEROcentrum\n",
                facet->id, neighbor->id, qh_pointid(qh, vertex->point), vertex->id, dist, neighbor->id);
              errfacet1= facet;
              errfacet2= neighbor;
              waserror= True;
            }
          }else {
            zzinc_(Zcoplanarridges);
            qh_joggle_restart(qh, "coplanar ridge");
            trace0((qh, qh->ferr, 22, "qhull precision error: f%d is coplanar to f%d, since p%d(v%d) is within %6.4g of f%d, during p%d\n",
              facet->id, neighbor->id, qh_pointid(qh, vertex->point), vertex->id, dist, neighbor->id, qh->furthest_id));
          }
        }
      }
    }
    if (!allsimplicial) {
      if (first_nonsimplicial) {
        trace1((qh, qh->ferr, 1063, "qh_checkconvex: starting with f%d, also check that centrums of non-simplicial ridges are below their neighbors (dist<0.0)\n",
             facet->id));
        first_nonsimplicial= False;
      }
      if (qh->CENTERtype == qh_AScentrum) {
        if (!facet->center)
          facet->center= qh_getcentrum(qh, facet);
        centrum= facet->center;
      }else {
        if (!centrum_warning && !facet->simplicial) {  /* recomputed centrum correct for simplicial facets */
           centrum_warning= True;
           qh_fprintf(qh, qh->ferr, 7062, "qhull warning: recomputing centrums for convexity test.  This may lead to false, precision errors.\n");
        }
        centrum= qh_getcentrum(qh, facet);
        tempcentrum= True;
      }
      FOREACHneighbor_(facet) {
        if (neighbor->simplicial && tested_simplicial) /* tested above since f.simplicial */
          continue;
        if (neighbor->tricoplanar)
          continue;
        zzinc_(Zdistconvex);
        qh_distplane(qh, centrum, neighbor, &dist);
        if (dist > qh->DISTround) {
          zzinc_(Zconcaveridges);
          qh_joggle_restart(qh, "concave ridge");
          qh_fprintf(qh, qh->ferr, 6117, "qhull precision error: f%d is concave to f%d.  Centrum of f%d is %6.4g above f%d\n",
            facet->id, neighbor->id, facet->id, dist, neighbor->id);
          errfacet1= facet;
          errfacet2= neighbor;
          waserror= True;
        }else if (dist >= 0.0) {   /* if arithmetic always rounds the same,
                                     can test against centrum radius instead */
          zzinc_(Zcoplanarridges);
          qh_joggle_restart(qh, "coplanar ridge");
          qh_fprintf(qh, qh->ferr, 6118, "qhull precision error: f%d is coplanar or concave to f%d.  Centrum of f%d is %6.4g above f%d\n",
            facet->id, neighbor->id, facet->id, dist, neighbor->id);
          errfacet1= facet;
          errfacet2= neighbor;
          waserror= True;
        }
      }
      if (tempcentrum)
        qh_memfree(qh, centrum, qh->normal_size);
    }
  }
  if (waserror && !qh->FORCEoutput)
    qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2);
} /* checkconvex */


/*---------------------------------

  qh_checkfacet(qh, facet, newmerge, waserror )
    checks for consistency errors in facet
    newmerge set if from merge_r.c

  returns:
    sets waserror if any error occurs

  checks:
    vertex ids are inverse sorted
    unless newmerge, at least hull_dim neighbors and vertices (exactly if simplicial)
    if non-simplicial, at least as many ridges as neighbors
    neighbors are not duplicated
    ridges are not duplicated
    in 3-d, ridges=verticies
    (qh.hull_dim-1) ridge vertices
    neighbors are reciprocated
    ridge neighbors are facet neighbors and a ridge for every neighbor
    simplicial neighbors match facetintersect
    vertex intersection matches vertices of common ridges
    vertex neighbors and facet vertices agree
    all ridges have distinct vertex sets

  notes:
    called by qh_tracemerge and qh_checkpolygon
    uses neighbor->seen

  design:
    check sets
    check vertices
    check sizes of neighbors and vertices
    check for qh_MERGEridge and qh_DUPLICATEridge flags
    check neighbor set
    check ridge set
    check ridges, neighbors, and vertices
*/
void qh_checkfacet(qhT *qh, facetT *facet, boolT newmerge, boolT *waserrorp) {
  facetT *neighbor, **neighborp, *errother=NULL;
  ridgeT *ridge, **ridgep, *errridge= NULL, *ridge2;
  vertexT *vertex, **vertexp;
  unsigned int previousid= INT_MAX;
  int numneighbors, numvertices, numridges=0, numRvertices=0;
  boolT waserror= False;
  int skipA, skipB, ridge_i, ridge_n, i, last_v= qh->hull_dim-2;
  setT *intersection;

  trace4((qh, qh->ferr, 4088, "qh_checkfacet: check f%d newmerge? %d\n", facet->id, newmerge));
  if (facet->id >= qh->facet_id) {
    qh_fprintf(qh, qh->ferr, 6414, "qhull internal error (qh_checkfacet): unknown facet id f%d >= qh.facet_id (%d)\n", facet->id, qh->facet_id);
    waserror= True;
  }
  if (facet->visitid > qh->visit_id) {
    qh_fprintf(qh, qh->ferr, 6415, "qhull internal error (qh_checkfacet): expecting f%d.visitid <= qh.visit_id (%d).  Got visitid %d\n", facet->id, qh->visit_id, facet->visitid);
    waserror= True;
  }
  if (facet->visible && !qh->NEWtentative) {
    qh_fprintf(qh, qh->ferr, 6119, "qhull internal error (qh_checkfacet): facet f%d is on qh.visible_list\n",
      facet->id);
    qh_errexit(qh, qh_ERRqhull, facet, NULL);
  }
  if (facet->redundant && !facet->visible && qh_setsize(qh, qh->degen_mergeset)==0) {
    qh_fprintf(qh, qh->ferr, 6399, "qhull internal error (qh_checkfacet): redundant facet f%d not on qh.visible_list\n",
      facet->id);
    waserror= True;
  }
  if (facet->degenerate && !facet->visible && qh_setsize(qh, qh->degen_mergeset)==0) { 
    qh_fprintf(qh, qh->ferr, 6400, "qhull internal error (qh_checkfacet): degenerate facet f%d is not on qh.visible_list and qh.degen_mergeset is empty\n",
      facet->id);
    waserror= True;
  }
  if (!facet->normal) {
    qh_fprintf(qh, qh->ferr, 6120, "qhull internal error (qh_checkfacet): facet f%d does not have a normal\n",
      facet->id);
    waserror= True;
  }
  if (!facet->newfacet) {
    if (facet->dupridge) {
      qh_fprintf(qh, qh->ferr, 6349, "qhull internal error (qh_checkfacet): f%d is 'dupridge' but it is not a newfacet on qh.newfacet_list f%d\n",
        facet->id, getid_(qh->newfacet_list));
      waserror= True;
    }
    if (facet->newmerge) {
      qh_fprintf(qh, qh->ferr, 6383, "qhull internal error (qh_checkfacet): f%d is 'newmerge' but it is not a newfacet on qh.newfacet_list f%d.  Missing call to qh_reducevertices\n",  
        facet->id, getid_(qh->newfacet_list));
      waserror= True;
    }
  }
  qh_setcheck(qh, facet->vertices, "vertices for f", facet->id);
  qh_setcheck(qh, facet->ridges, "ridges for f", facet->id);
  qh_setcheck(qh, facet->outsideset, "outsideset for f", facet->id);
  qh_setcheck(qh, facet->coplanarset, "coplanarset for f", facet->id);
  qh_setcheck(qh, facet->neighbors, "neighbors for f", facet->id);
  FOREACHvertex_(facet->vertices) {
    if (vertex->deleted) {
      qh_fprintf(qh, qh->ferr, 6121, "qhull internal error (qh_checkfacet): deleted vertex v%d in f%d\n", vertex->id, facet->id);
      qh_errprint(qh, "ERRONEOUS", NULL, NULL, NULL, vertex);
      waserror= True;
    }
    if (vertex->id >= previousid) {
      qh_fprintf(qh, qh->ferr, 6122, "qhull internal error (qh_checkfacet): vertices of f%d are not in descending id order at v%d\n", facet->id, vertex->id);
      waserror= True;
      break;
    }
    previousid= vertex->id;
  }
  numneighbors= qh_setsize(qh, facet->neighbors);
  numvertices= qh_setsize(qh, facet->vertices);
  numridges= qh_setsize(qh, facet->ridges);
  if (facet->simplicial) {
    if (numvertices+numneighbors != 2*qh->hull_dim
    && !facet->degenerate && !facet->redundant) {
      qh_fprintf(qh, qh->ferr, 6123, "qhull internal error (qh_checkfacet): for simplicial facet f%d, #vertices %d + #neighbors %d != 2*qh->hull_dim\n",
                facet->id, numvertices, numneighbors);
      qh_setprint(qh, qh->ferr, "", facet->neighbors);
      waserror= True;
    }
  }else { /* non-simplicial */
    if (!newmerge
    &&(numvertices < qh->hull_dim || numneighbors < qh->hull_dim)
    && !facet->degenerate && !facet->redundant) {
      qh_fprintf(qh, qh->ferr, 6124, "qhull internal error (qh_checkfacet): for facet f%d, #vertices %d or #neighbors %d < qh->hull_dim\n",
         facet->id, numvertices, numneighbors);
       waserror= True;
    }
    /* in 3-d, can get a vertex twice in an edge list, e.g., RBOX 1000 s W1e-13 t995849315 D2 | QHULL d Tc Tv TP624 TW1e-13 T4 */
    if (numridges < numneighbors
    ||(qh->hull_dim == 3 && numvertices > numridges && !qh->NEWfacets)
    ||(qh->hull_dim == 2 && numridges + numvertices + numneighbors != 6)) {
      if (!facet->degenerate && !facet->redundant) {
        qh_fprintf(qh, qh->ferr, 6125, "qhull internal error (qh_checkfacet): for facet f%d, #ridges %d < #neighbors %d or(3-d) > #vertices %d or(2-d) not all 2\n",
            facet->id, numridges, numneighbors, numvertices);
        waserror= True;
      }
    }
  }
  FOREACHneighbor_(facet) {
    if (neighbor == qh_MERGEridge || neighbor == qh_DUPLICATEridge) {
      qh_fprintf(qh, qh->ferr, 6126, "qhull internal error (qh_checkfacet): facet f%d still has a MERGEridge or DUPLICATEridge neighbor\n", facet->id);
      qh_errexit(qh, qh_ERRqhull, facet, NULL);
    }
    if (neighbor->visible) {
      qh_fprintf(qh, qh->ferr, 6401, "qhull internal error (qh_checkfacet): facet f%d has deleted neighbor f%d (qh.visible_list)\n",
        facet->id, neighbor->id);
      errother= neighbor;
      waserror= True;
    }
    neighbor->seen= True;
  }
  FOREACHneighbor_(facet) {
    if (!qh_setin(neighbor->neighbors, facet)) {
      qh_fprintf(qh, qh->ferr, 6127, "qhull internal error (qh_checkfacet): facet f%d has neighbor f%d, but f%d does not have neighbor f%d\n",
              facet->id, neighbor->id, neighbor->id, facet->id);
      errother= neighbor;
      waserror= True;
    }
    if (!neighbor->seen) {
      qh_fprintf(qh, qh->ferr, 6128, "qhull internal error (qh_checkfacet): facet f%d has a duplicate neighbor f%d\n",
              facet->id, neighbor->id);
      errother= neighbor;
      waserror= True;
    }
    neighbor->seen= False;
  }
  FOREACHridge_(facet->ridges) {
    qh_setcheck(qh, ridge->vertices, "vertices for r", ridge->id);
    ridge->seen= False;
  }
  FOREACHridge_(facet->ridges) {
    if (ridge->seen) {
      qh_fprintf(qh, qh->ferr, 6129, "qhull internal error (qh_checkfacet): facet f%d has a duplicate ridge r%d\n",
              facet->id, ridge->id);
      errridge= ridge;
      waserror= True;
    }
    ridge->seen= True;
    numRvertices= qh_setsize(qh, ridge->vertices);
    if (numRvertices != qh->hull_dim - 1) {
      qh_fprintf(qh, qh->ferr, 6130, "qhull internal error (qh_checkfacet): ridge between f%d and f%d has %d vertices\n",
                ridge->top->id, ridge->bottom->id, numRvertices);
      errridge= ridge;
      waserror= True;
    }
    neighbor= otherfacet_(ridge, facet);
    neighbor->seen= True;
    if (!qh_setin(facet->neighbors, neighbor)) {
      qh_fprintf(qh, qh->ferr, 6131, "qhull internal error (qh_checkfacet): for facet f%d, neighbor f%d of ridge r%d not in facet\n",
           facet->id, neighbor->id, ridge->id);
      errridge= ridge;
      waserror= True;
    }
    if (!facet->newfacet && !neighbor->newfacet) {
      if ((!ridge->tested) | ridge->nonconvex | ridge->mergevertex) {
        qh_fprintf(qh, qh->ferr, 6384, "qhull internal error (qh_checkfacet): ridge r%d is nonconvex (%d), mergevertex (%d) or not tested (%d) for facet f%d, neighbor f%d\n",
          ridge->id, ridge->nonconvex, ridge->mergevertex, ridge->tested, facet->id, neighbor->id);
        errridge= ridge;
        waserror= True;
      }
    }
  }
  if (!facet->simplicial) {
    FOREACHneighbor_(facet) {
      if (!neighbor->seen) {
        qh_fprintf(qh, qh->ferr, 6132, "qhull internal error (qh_checkfacet): facet f%d does not have a ridge for neighbor f%d\n",
              facet->id, neighbor->id);
        errother= neighbor;
        waserror= True;
      }
      intersection= qh_vertexintersect_new(qh, facet->vertices, neighbor->vertices);
      qh_settemppush(qh, intersection);
      FOREACHvertex_(facet->vertices) {
        vertex->seen= False;
        vertex->seen2= False;
      }
      FOREACHvertex_(intersection)
        vertex->seen= True;
      FOREACHridge_(facet->ridges) {
        if (neighbor != otherfacet_(ridge, facet))
            continue;
        FOREACHvertex_(ridge->vertices) {
          if (!vertex->seen) {
            qh_fprintf(qh, qh->ferr, 6133, "qhull internal error (qh_checkfacet): vertex v%d in r%d not in f%d intersect f%d\n",
                  vertex->id, ridge->id, facet->id, neighbor->id);
            qh_errexit(qh, qh_ERRqhull, facet, ridge);
          }
          vertex->seen2= True;
        }
      }
      if (!newmerge) {
        FOREACHvertex_(intersection) {
          if (!vertex->seen2) {
            if (!qh->MERGING) {
              qh_fprintf(qh, qh->ferr, 6420, "qhull topology error (qh_checkfacet): vertex v%d in f%d intersect f%d but not in a ridge.  Last point was p%d\n",
                     vertex->id, facet->id, neighbor->id, qh->furthest_id);
              if (!qh->FORCEoutput) {
                qh_errprint(qh, "ERRONEOUS", facet, neighbor, NULL, vertex);
                qh_errexit(qh, qh_ERRtopology, NULL, NULL);
              }
            }else {
              trace4((qh, qh->ferr, 4025, "qh_checkfacet: vertex v%d in f%d intersect f%d but not in a ridge.  Repaired by qh_remove_extravertices in qh_reducevertices\n",
                vertex->id, facet->id, neighbor->id));
            }
          }
        }
      }
      qh_settempfree(qh, &intersection);
    }
  }else { /* simplicial */
    FOREACHneighbor_(facet) {
      if (neighbor->simplicial && !facet->degenerate && !neighbor->degenerate) {
        skipA= SETindex_(facet->neighbors, neighbor);
        skipB= qh_setindex(neighbor->neighbors, facet);
        if (skipA<0 || skipB<0 || !qh_setequal_skip(facet->vertices, skipA, neighbor->vertices, skipB)) {
          qh_fprintf(qh, qh->ferr, 6135, "qhull internal error (qh_checkfacet): facet f%d skip %d and neighbor f%d skip %d do not match \n",
                   facet->id, skipA, neighbor->id, skipB);
          errother= neighbor;
          waserror= True;
        }
      }
    }
  }
  if (!newmerge && qh->CHECKduplicates && qh->hull_dim < 5 && (qh->IStracing > 2 || qh->CHECKfrequently)) {
    FOREACHridge_i_(qh, facet->ridges) {           /* expensive, if was merge and qh_maybe_duplicateridges hasn't been called yet */
      if (!ridge->mergevertex) {
        for (i=ridge_i+1; i < ridge_n; i++) {
          ridge2= SETelemt_(facet->ridges, i, ridgeT);
          if (SETelem_(ridge->vertices, last_v) == SETelem_(ridge2->vertices, last_v)) { /* SETfirst is likely to be the same */
            if (SETfirst_(ridge->vertices) == SETfirst_(ridge2->vertices)) {
              if (qh_setequal(ridge->vertices, ridge2->vertices)) {
                qh_fprintf(qh, qh->ferr, 6294, "qhull internal error (qh_checkfacet): ridges r%d and r%d (f%d) have the same vertices\n", /* same as duplicate ridge */
                    ridge->id, ridge2->id, facet->id);
                errridge= ridge;
                waserror= True;
              }
            }
          }
        }
      }
    }
  }
  if (waserror) {
    qh_errprint(qh, "ERRONEOUS", facet, errother, errridge, NULL);
    *waserrorp= True;
  }
} /* checkfacet */

/*---------------------------------

  qh_checkflipped_all(qh, facetlist )
    checks orientation of facets in list against interior point

  notes:
    called by qh_checkoutput
*/
void qh_checkflipped_all(qhT *qh, facetT *facetlist) {
  facetT *facet;
  boolT waserror= False;
  realT dist;

  if (facetlist == qh->facet_list)
    zzval_(Zflippedfacets)= 0;
  FORALLfacet_(facetlist) {
    if (facet->normal && !qh_checkflipped(qh, facet, &dist, !qh_ALL)) {
      qh_fprintf(qh, qh->ferr, 6136, "qhull precision error: facet f%d is flipped, distance= %6.12g\n",
              facet->id, dist);
      if (!qh->FORCEoutput) {
        qh_errprint(qh, "ERRONEOUS", facet, NULL, NULL, NULL);
        waserror= True;
      }
    }
  }
  if (waserror) {
    qh_fprintf(qh, qh->ferr, 8101, "\n\
A flipped facet occurs when its distance to the interior point is\n\
greater than or equal to %2.2g, the maximum roundoff error.\n", -qh->DISTround);
    qh_errexit(qh, qh_ERRprec, NULL, NULL);
  }
} /* checkflipped_all */

/*---------------------------------

  qh_checklists(qh, facetlist )
    Check and repair facetlist and qh.vertex_list for infinite loops or overwritten facets
    Checks that qh.newvertex_list is on qh.vertex_list
    if facetlist is qh.facet_list
      Checks that qh.visible_list and qh.newfacet_list are on qh.facet_list
    Updates qh.facetvisit and qh.vertexvisit

  returns:
    True if no errors found
    If false, repairs erroneous lists to prevent infinite loops by FORALL macros

  notes:
    called by qh_buildtracing, qh_checkpolygon, qh_collectstatistics, qh_printfacetlist, qh_printsummary
    not called by qh_printlists

  design:
    if facetlist
      check qh.facet_tail
      for each facet
        check for infinite loop or overwritten facet
        check previous facet
      if facetlist is qh.facet_list
        check qh.next_facet, qh.visible_list and qh.newfacet_list
    if vertexlist
      check qh.vertex_tail
      for each vertex
        check for infinite loop or overwritten vertex
        check previous vertex
      check qh.newvertex_list
*/
boolT qh_checklists(qhT *qh, facetT *facetlist) {
  facetT *facet, *errorfacet= NULL, *errorfacet2= NULL, *previousfacet;
  vertexT *vertex, *vertexlist, *previousvertex, *errorvertex= NULL;
  boolT waserror= False, newseen= False, nextseen= False, newvertexseen= False, visibleseen= False;

  if (facetlist == qh->newfacet_list || facetlist == qh->visible_list) {
    vertexlist= qh->vertex_list;
    previousvertex= NULL;
    trace2((qh, qh->ferr, 2110, "qh_checklists: check qh.%s_list f%d and qh.vertex_list v%d\n", 
        (facetlist == qh->newfacet_list ? "newfacet" : "visible"), facetlist->id, getid_(vertexlist)));
  }else {
    vertexlist= qh->vertex_list;
    previousvertex= NULL;
    trace2((qh, qh->ferr, 2111, "qh_checklists: check %slist f%d and qh.vertex_list v%d\n", 
        (facetlist == qh->facet_list ? "qh.facet_" : "facet"), getid_(facetlist), getid_(vertexlist)));
  }
  if (facetlist) {
    if (qh->facet_tail == NULL || qh->facet_tail->id != 0 || qh->facet_tail->next != NULL) {
      qh_fprintf(qh, qh->ferr, 6397, "qhull internal error (qh_checklists): either qh.facet_tail f%d is NULL, or its id is not 0, or its next is not NULL\n", 
          getid_(qh->facet_tail));
      qh_errexit(qh, qh_ERRqhull, qh->facet_tail, NULL);
    }
    previousfacet= (facetlist == qh->facet_list ? NULL : facetlist->previous);
    qh->visit_id++;
    FORALLfacet_(facetlist) {
      if (facet->visitid >= qh->visit_id || facet->id >= qh->facet_id) {
        waserror= True;
        errorfacet= facet;
        errorfacet2= previousfacet;
        if (facet->visitid == qh->visit_id)
          qh_fprintf(qh, qh->ferr, 6039, "qhull internal error (qh_checklists): f%d already in facetlist causing an infinite loop ... f%d > f%d ... > f%d > f%d.  Truncate facetlist at f%d\n", 
            facet->id, facet->id, facet->next->id, getid_(previousfacet), facet->id, getid_(previousfacet));
        else
          qh_fprintf(qh, qh->ferr, 6350, "qhull internal error (qh_checklists): unknown or overwritten facet f%d, either id >= qh.facet_id (%d) or f.visitid %u > qh.visit_id %u.  Facetlist terminated at previous facet f%d\n", 
              facet->id, qh->facet_id, facet->visitid, qh->visit_id, getid_(previousfacet));
        if (previousfacet)
          previousfacet->next= qh->facet_tail;
        else
          facetlist= qh->facet_tail;
        break;
      }
      facet->visitid= qh->visit_id;
      if (facet->previous != previousfacet) {
        qh_fprintf(qh, qh->ferr, 6416, "qhull internal error (qh_checklists): expecting f%d.previous == f%d.  Got f%d\n",
          facet->id, getid_(previousfacet), getid_(facet->previous));
        waserror= True;
        errorfacet= facet;
        errorfacet2= facet->previous;
      }
      previousfacet= facet;
      if (facetlist == qh->facet_list) {
        if (facet == qh->visible_list) {
          if(newseen){
            qh_fprintf(qh, qh->ferr, 6285, "qhull internal error (qh_checklists): qh.visible_list f%d is after qh.newfacet_list f%d.  It should be at, before, or NULL\n",
              facet->id, getid_(qh->newfacet_list));
            waserror= True;
            errorfacet= facet;
            errorfacet2= qh->newfacet_list;
          }
          visibleseen= True;
        }
        if (facet == qh->newfacet_list)
          newseen= True;
        if (facet == qh->facet_next)
          nextseen= True;
      }
    }
    if (facetlist == qh->facet_list) {
      if (!nextseen && qh->facet_next && qh->facet_next->next) {
        qh_fprintf(qh, qh->ferr, 6369, "qhull internal error (qh_checklists): qh.facet_next f%d for qh_addpoint is not on qh.facet_list f%d\n", 
          qh->facet_next->id, facetlist->id);
        waserror= True;
        errorfacet= qh->facet_next;
        errorfacet2= facetlist;
      }
      if (!newseen && qh->newfacet_list && qh->newfacet_list->next) {
        qh_fprintf(qh, qh->ferr, 6286, "qhull internal error (qh_checklists): qh.newfacet_list f%d is not on qh.facet_list f%d\n", 
          qh->newfacet_list->id, facetlist->id);
        waserror= True;
        errorfacet= qh->newfacet_list;
        errorfacet2= facetlist;
      }
      if (!visibleseen && qh->visible_list && qh->visible_list->next) {
        qh_fprintf(qh, qh->ferr, 6138, "qhull internal error (qh_checklists): qh.visible_list f%d is not on qh.facet_list f%d\n", 
          qh->visible_list->id, facetlist->id);
        waserror= True;
        errorfacet= qh->visible_list;
        errorfacet2= facetlist;
      }
    }
  }
  if (vertexlist) {
    if (qh->vertex_tail == NULL || qh->vertex_tail->id != 0 || qh->vertex_tail->next != NULL) {
      qh_fprintf(qh, qh->ferr, 6366, "qhull internal error (qh_checklists): either qh.vertex_tail v%d is NULL, or its id is not 0, or its next is not NULL\n", 
           getid_(qh->vertex_tail));
      qh_errprint(qh, "ERRONEOUS", errorfacet, errorfacet2, NULL, qh->vertex_tail);
      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
    }
    qh->vertex_visit++;
    FORALLvertex_(vertexlist) {
      if (vertex->visitid >= qh->vertex_visit || vertex->id >= qh->vertex_id) {
        waserror= True;
        errorvertex= vertex;
        if (vertex->visitid == qh->visit_id)
          qh_fprintf(qh, qh->ferr, 6367, "qhull internal error (qh_checklists): v%d already in vertexlist causing an infinite loop ... v%d > v%d ... > v%d > v%d.  Truncate vertexlist at v%d\n", 
            vertex->id, vertex->id, vertex->next->id, getid_(previousvertex), vertex->id, getid_(previousvertex));
        else
          qh_fprintf(qh, qh->ferr, 6368, "qhull internal error (qh_checklists): unknown or overwritten vertex v%d, either id >= qh.vertex_id (%d) or v.visitid %u > qh.visit_id %u.  vertexlist terminated at previous vertex v%d\n", 
            vertex->id, qh->vertex_id, vertex->visitid, qh->visit_id, getid_(previousvertex));
        if (previousvertex)
          previousvertex->next= qh->vertex_tail;
        else
          vertexlist= qh->vertex_tail;
        break;
      }
      vertex->visitid= qh->vertex_visit;
      if (vertex->previous != previousvertex) {
        qh_fprintf(qh, qh->ferr, 6427, "qhull internal error (qh_checklists): expecting v%d.previous == v%d.  Got v%d\n",
              vertex->id, previousvertex, getid_(vertex->previous));
        waserror= True;
        errorvertex= vertex;
      }
      previousvertex= vertex;
      if(vertex == qh->newvertex_list)
        newvertexseen= True;
    }
    if(!newvertexseen && qh->newvertex_list && qh->newvertex_list->next) {
      qh_fprintf(qh, qh->ferr, 6287, "qhull internal error (qh_checklists): new vertex list v%d is not on vertex list\n", qh->newvertex_list->id);
      waserror= True;
      errorvertex= qh->newvertex_list;
    }
  }
  if (waserror) {
    qh_errprint(qh, "ERRONEOUS", errorfacet, errorfacet2, NULL, errorvertex);
    return False;
  }
  return True;
} /* checklists */

/*---------------------------------

  qh_checkpolygon(qh, facetlist )
    checks the correctness of the structure

  notes:
    called by qh_addpoint, qh_all_vertexmerge, qh_check_output, qh_initialhull, qh_prepare_output, qh_triangulate
    call with qh.facet_list or qh.newfacet_list or another list
    checks num_facets and num_vertices if qh.facet_list

  design:
    check and repair lists for infinite loop
    for each facet
      check f.newfacet and f.visible
      check facet and outside set if qh.NEWtentative and not f.newfacet, or not f.visible
    initializes vertexlist for qh.facet_list or qh.newfacet_list
    for each vertex
      check vertex
      check v.newfacet
    for each facet
      count f.ridges
      check and count f.vertices
    if checking qh.facet_list
      check facet count
      if qh.VERTEXneighbors
        check and count v.neighbors for all vertices
        check v.neighbors count and report possible causes of mismatch
        check that facets are in their v.neighbors
      check vertex count
*/
void qh_checkpolygon(qhT *qh, facetT *facetlist) {
  facetT *facet, *neighbor, **neighborp;
  facetT *errorfacet= NULL, *errorfacet2= NULL;
  vertexT *vertex, **vertexp, *vertexlist;
  int numfacets= 0, numvertices= 0, numridges= 0;
  int totvneighbors= 0, totfacetvertices= 0;
  boolT waserror= False, newseen= False, newvertexseen= False, nextseen= False, visibleseen= False;
  boolT checkfacet;

  trace1((qh, qh->ferr, 1027, "qh_checkpolygon: check all facets from f%d, qh.NEWtentative? %d\n", facetlist->id, qh->NEWtentative));
  if (!qh_checklists(qh, facetlist)) {
    waserror= True;
    qh_fprintf(qh, qh->ferr, 6374, "qhull internal error: qh_checklists failed in qh_checkpolygon\n");
    if (qh->num_facets < 4000)
      qh_printlists(qh);
  }
  if (facetlist != qh->facet_list || qh->ONLYgood)
    nextseen= True; /* allow f.outsideset */
  FORALLfacet_(facetlist) {
    if (facet == qh->visible_list)
      visibleseen= True;
    if (facet == qh->newfacet_list)
      newseen= True;
    if (facet->newfacet && !newseen && !visibleseen) {
        qh_fprintf(qh, qh->ferr, 6289, "qhull internal error (qh_checkpolygon): f%d is 'newfacet' but it is not on qh.newfacet_list f%d or visible_list f%d\n",  facet->id, getid_(qh->newfacet_list), getid_(qh->visible_list));
        qh_errexit(qh, qh_ERRqhull, facet, NULL);
    }
    if (!facet->newfacet && newseen) {
        qh_fprintf(qh, qh->ferr, 6292, "qhull internal error (qh_checkpolygon): f%d is on qh.newfacet_list f%d but it is not 'newfacet'\n",  facet->id, getid_(qh->newfacet_list));
        qh_errexit(qh, qh_ERRqhull, facet, NULL);
    }
    if (facet->visible != (visibleseen & !newseen)) {
      if(facet->visible)
        qh_fprintf(qh, qh->ferr, 6290, "qhull internal error (qh_checkpolygon): f%d is 'visible' but it is not on qh.visible_list f%d\n", facet->id, getid_(qh->visible_list));
      else
        qh_fprintf(qh, qh->ferr, 6291, "qhull internal error (qh_checkpolygon): f%d is on qh.visible_list f%d but it is not 'visible'\n", facet->id, qh->newfacet_list->id);
      qh_errexit(qh, qh_ERRqhull, facet, NULL);
    }
    if (qh->NEWtentative) {
      checkfacet= !facet->newfacet;
    }else {
      checkfacet= !facet->visible;
    }
    if(checkfacet) {
      if (!nextseen) {
        if (facet == qh->facet_next)  /* previous facets do not have outsideset */
          nextseen= True;
        else if (qh_setsize(qh, facet->outsideset)) {
          if (!qh->NARROWhull
#if !qh_COMPUTEfurthest
          || facet->furthestdist >= qh->MINoutside
#endif
          ) {
            qh_fprintf(qh, qh->ferr, 6137, "qhull internal error (qh_checkpolygon): f%d has outside points before qh.facet_next f%d\n",
                     facet->id, getid_(qh->facet_next));
            qh_errexit2(qh, qh_ERRqhull, facet, qh->facet_next);
          }
        }
      }
      numfacets++;
      qh_checkfacet(qh, facet, False, &waserror);
    }else if (facet->visible && qh->NEWfacets) {
      if (!SETempty_(facet->neighbors) || !SETempty_(facet->ridges)) {
        qh_fprintf(qh, qh->ferr, 6376, "qhull internal error (qh_checkpolygon): expecting empty f.neighbors and f.ridges for visible facet f%d.  Got %d neighbors and %d ridges\n", 
          facet->id, qh_setsize(qh, facet->neighbors), qh_setsize(qh, facet->ridges));
        qh_errexit(qh, qh_ERRqhull, facet, 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) {
    qh_checkvertex(qh, vertex, !qh_ALL, &waserror);
    if(vertex == qh->newvertex_list)
      newvertexseen= True;
    vertex->seen= False;
    vertex->visitid= 0;
    if(vertex->newfacet && !newvertexseen && !vertex->deleted) {
      qh_fprintf(qh, qh->ferr, 6288, "qhull internal error (qh_checkpolygon): v%d is 'newfacet' but it is not on new vertex list v%d\n", vertex->id, getid_(qh->newvertex_list));
      qh_errexit(qh, qh_ERRqhull, qh->visible_list, NULL);
    }
  }
  FORALLfacet_(facetlist) {
    if (facet->visible)
      continue;
    if (facet->simplicial)
      numridges += qh->hull_dim;
    else
      numridges += qh_setsize(qh, facet->ridges);
    FOREACHvertex_(facet->vertices) {
      vertex->visitid++;
      if (!vertex->seen) {
        vertex->seen= True;
        numvertices++;
        if (qh_pointid(qh, vertex->point) == qh_IDunknown) {
          qh_fprintf(qh, qh->ferr, 6139, "qhull internal error (qh_checkpolygon): unknown point %p for vertex v%d first_point %p\n",
                   vertex->point, vertex->id, qh->first_point);
          waserror= True;
        }
      }
    }
  }
  qh->vertex_visit += (unsigned int)numfacets;
  if (facetlist == qh->facet_list) {
    if (numfacets != qh->num_facets - qh->num_visible) {
      qh_fprintf(qh, qh->ferr, 6140, "qhull internal error (qh_checkpolygon): actual number of facets is %d, cumulative facet count is %d - %d visible facets\n",
              numfacets, qh->num_facets, qh->num_visible);
      waserror= True;
    }
    qh->vertex_visit++;
    if (qh->VERTEXneighbors) {
      FORALLvertices {
        if (!vertex->neighbors) {
          qh_fprintf(qh, qh->ferr, 6407, "qhull internal error (qh_checkpolygon): missing vertex neighbors for v%d\n", vertex->id);
          waserror= True;
        }
        qh_setcheck(qh, vertex->neighbors, "neighbors for v", vertex->id);
        if (vertex->deleted)
          continue;
        totvneighbors += qh_setsize(qh, vertex->neighbors);
      }
      FORALLfacet_(facetlist) {
        if (!facet->visible)
          totfacetvertices += qh_setsize(qh, facet->vertices);
      }
      if (totvneighbors != totfacetvertices) {
        qh_fprintf(qh, qh->ferr, 6141, "qhull internal error (qh_checkpolygon): vertex neighbors inconsistent (tot_vneighbors %d != tot_facetvertices %d).  Maybe duplicate or missing vertex\n",
                totvneighbors, totfacetvertices);
        waserror= True;
        FORALLvertices {
          if (vertex->deleted)
            continue;
          qh->visit_id++;
          FOREACHneighbor_(vertex) {
            if (neighbor->visitid==qh->visit_id) {
              qh_fprintf(qh, qh->ferr, 6275, "qhull internal error (qh_checkpolygon): facet f%d occurs twice in neighbors of vertex v%d\n",
                  neighbor->id, vertex->id);
              errorfacet2= errorfacet;
              errorfacet= neighbor;
            }
            neighbor->visitid= qh->visit_id;
            if (!qh_setin(neighbor->vertices, vertex)) {
              qh_fprintf(qh, qh->ferr, 6276, "qhull internal error (qh_checkpolygon): facet f%d is a neighbor of vertex v%d but v%d is not a vertex of f%d\n",
                  neighbor->id, vertex->id, vertex->id, neighbor->id);
              errorfacet2= errorfacet;
              errorfacet= neighbor;
            }
          }
        }
        FORALLfacet_(facetlist){
          if (!facet->visible) {
            /* vertices are inverse sorted and are unlikely to be duplicated */
            FOREACHvertex_(facet->vertices){
              if (!qh_setin(vertex->neighbors, facet)) {
                qh_fprintf(qh, qh->ferr, 6277, "qhull internal error (qh_checkpolygon): v%d is a vertex of facet f%d but f%d is not a neighbor of v%d\n",
                  vertex->id, facet->id, facet->id, vertex->id);
                errorfacet2= errorfacet;
                errorfacet= facet;
              }
            }
          }
        }
      }
    }
    if (numvertices != qh->num_vertices - qh_setsize(qh, qh->del_vertices)) {
      qh_fprintf(qh, qh->ferr, 6142, "qhull internal error (qh_checkpolygon): actual number of vertices is %d, cumulative vertex count is %d\n",
              numvertices, qh->num_vertices - qh_setsize(qh, qh->del_vertices));
      waserror= True;
    }
    if (qh->hull_dim == 2 && numvertices != numfacets) {
      qh_fprintf(qh, qh->ferr, 6143, "qhull internal error (qh_checkpolygon): #vertices %d != #facets %d\n",
        numvertices, numfacets);
      waserror= True;
    }
    if (qh->hull_dim == 3 && numvertices + numfacets - numridges/2 != 2) {
      qh_fprintf(qh, qh->ferr, 7063, "qhull warning: #vertices %d + #facets %d - #edges %d != 2.  A vertex appears twice in a edge list.  May occur during merging.\n",
          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_errexit2(qh, qh_ERRqhull, errorfacet, errorfacet2);
} /* checkpolygon */


/*---------------------------------

  qh_checkvertex(qh, vertex, allchecks, &waserror )
    check vertex for consistency
    if allchecks, checks vertex->neighbors

  returns:
    sets waserror if any error occurs

  notes:
    called by qh_tracemerge and qh_checkpolygon
    neighbors checked efficiently in qh_checkpolygon
*/
void qh_checkvertex(qhT *qh, vertexT *vertex, boolT allchecks, boolT *waserrorp) {
  boolT waserror= False;
  facetT *neighbor, **neighborp, *errfacet=NULL;

  if (qh_pointid(qh, vertex->point) == qh_IDunknown) {
    qh_fprintf(qh, qh->ferr, 6144, "qhull internal error (qh_checkvertex): unknown point id %p\n", vertex->point);
    waserror= True;
  }
  if (vertex->id >= qh->vertex_id) {
    qh_fprintf(qh, qh->ferr, 6145, "qhull internal error (qh_checkvertex): unknown vertex id v%d >= qh.vertex_id (%d)\n", vertex->id, qh->vertex_id);
    waserror= True;
  }
  if (vertex->visitid > qh->vertex_visit) {
    qh_fprintf(qh, qh->ferr, 6413, "qhull internal error (qh_checkvertex): expecting v%d.visitid <= qh.vertex_visit (%d).  Got visitid %d\n", vertex->id, qh->vertex_visit, vertex->visitid);
    waserror= True;
  }
  if (allchecks && !waserror && !vertex->deleted) {
    if (qh_setsize(qh, vertex->neighbors)) {
      FOREACHneighbor_(vertex) {
        if (!qh_setin(neighbor->vertices, vertex)) {
          qh_fprintf(qh, qh->ferr, 6146, "qhull internal error (qh_checkvertex): neighbor f%d does not contain v%d\n", neighbor->id, vertex->id);
          errfacet= neighbor;
          waserror= True;
        }
      }
    }
  }
  if (waserror) {
    qh_errprint(qh, "ERRONEOUS", NULL, NULL, NULL, vertex);
    if (errfacet)
      qh_errexit(qh, qh_ERRqhull, errfacet, NULL);
    *waserrorp= True;
  }
} /* checkvertex */

/*---------------------------------

  qh_clearcenters(qh, type )
    clear old data from facet->center

  notes:
    sets new centertype
    nop if CENTERtype is the same
*/
void qh_clearcenters(qhT *qh, qh_CENTER type) {
  facetT *facet;

  if (qh->CENTERtype != type) {
    FORALLfacets {
      if (facet->tricoplanar && !facet->keepcentrum)
          facet->center= NULL;  /* center is owned by the ->keepcentrum facet */
      else if (qh->CENTERtype == qh_ASvoronoi){
        if (facet->center) {
          qh_memfree(qh, facet->center, qh->center_size);
          facet->center= NULL;
        }
      }else /* qh.CENTERtype == qh_AScentrum */ {
        if (facet->center) {
          qh_memfree(qh, facet->center, qh->normal_size);
          facet->center= NULL;
        }
      }
    }
    qh->CENTERtype= type;
  }
  trace2((qh, qh->ferr, 2043, "qh_clearcenters: switched to center type %d\n", type));
} /* clearcenters */

/*---------------------------------

  qh_createsimplex(qh, vertices )
    creates a simplex from a set of vertices

  returns:
    initializes qh.facet_list to the simplex

  notes: 
    only called by qh_initialhull

  design:
    for each vertex
      create a new facet
    for each new facet
      create its neighbor set
*/
void qh_createsimplex(qhT *qh, setT *vertices /* qh.facet_list */) {
  facetT *facet= NULL, *newfacet;
  boolT toporient= True;
  int vertex_i, vertex_n, nth;
  setT *newfacets= qh_settemp(qh, qh->hull_dim+1);
  vertexT *vertex;

  FOREACHvertex_i_(qh, vertices) {
    newfacet= qh_newfacet(qh);
    newfacet->vertices= qh_setnew_delnthsorted(qh, vertices, vertex_n, vertex_i, 0);
    if (toporient)
      newfacet->toporient= True;
    qh_appendfacet(qh, newfacet);
    newfacet->newfacet= True;
    qh_appendvertex(qh, vertex);
    qh_setappend(qh, &newfacets, newfacet);
    toporient ^= True;
  }
  FORALLnew_facets {
    nth= 0;
    FORALLfacet_(qh->newfacet_list) {
      if (facet != newfacet)
        SETelem_(newfacet->neighbors, nth++)= facet;
    }
    qh_settruncate(qh, newfacet->neighbors, qh->hull_dim);
  }
  qh_settempfree(qh, &newfacets);
  trace1((qh, qh->ferr, 1028, "qh_createsimplex: created simplex\n"));
} /* createsimplex */

/*---------------------------------

  qh_delridge(qh, ridge )
    delete a ridge's vertices and frees its memory

  notes:
    assumes r.top->ridges and r.bottom->ridges have been updated
*/
void qh_delridge(qhT *qh, ridgeT *ridge) {

  if (ridge == qh->traceridge)
    qh->traceridge= NULL;
  qh_setfree(qh, &(ridge->vertices));
  qh_memfree(qh, ridge, (int)sizeof(ridgeT));
} /* delridge */

/*---------------------------------

  qh_delvertex(qh, vertex )
    deletes a vertex and frees its memory

  notes:
    assumes vertex->adjacencies have been updated if needed
    unlinks from vertex_list
*/
void qh_delvertex(qhT *qh, vertexT *vertex) {

  if (vertex->deleted && !vertex->partitioned && !qh->NOerrexit) {
    qh_fprintf(qh, qh->ferr, 6395, "qhull internal error (qh_delvertex): vertex v%d was deleted but it was not partitioned as a coplanar point\n",
      vertex->id);
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  if (vertex == qh->tracevertex)
    qh->tracevertex= NULL;
  qh_removevertex(qh, vertex);
  qh_setfree(qh, &vertex->neighbors);
  qh_memfree(qh, vertex, (int)sizeof(vertexT));
} /* delvertex */


/*---------------------------------

  qh_facet3vertex(qh )
    return temporary set of 3-d vertices in qh_ORIENTclock order

  design:
    if simplicial facet
      build set from facet->vertices with facet->toporient
    else
      for each ridge in order
        build set from ridge's vertices
*/
setT *qh_facet3vertex(qhT *qh, facetT *facet) {
  ridgeT *ridge, *firstridge;
  vertexT *vertex;
  int cntvertices, cntprojected=0;
  setT *vertices;

  cntvertices= qh_setsize(qh, facet->vertices);
  vertices= qh_settemp(qh, cntvertices);
  if (facet->simplicial) {
    if (cntvertices != 3) {
      qh_fprintf(qh, qh->ferr, 6147, "qhull internal error (qh_facet3vertex): only %d vertices for simplicial facet f%d\n",
                  cntvertices, facet->id);
      qh_errexit(qh, qh_ERRqhull, facet, NULL);
    }
    qh_setappend(qh, &vertices, SETfirst_(facet->vertices));
    if (facet->toporient ^ qh_ORIENTclock)
      qh_setappend(qh, &vertices, SETsecond_(facet->vertices));
    else
      qh_setaddnth(qh, &vertices, 0, SETsecond_(facet->vertices));
    qh_setappend(qh, &vertices, SETelem_(facet->vertices, 2));
  }else {
    ridge= firstridge= SETfirstt_(facet->ridges, ridgeT);   /* no infinite */
    while ((ridge= qh_nextridge3d(ridge, facet, &vertex))) {
      qh_setappend(qh, &vertices, vertex);
      if (++cntprojected > cntvertices || ridge == firstridge)
        break;
    }
    if (!ridge || cntprojected != cntvertices) {
      qh_fprintf(qh, qh->ferr, 6148, "qhull internal error (qh_facet3vertex): ridges for facet %d don't match up.  got at least %d\n",
                  facet->id, cntprojected);
      qh_errexit(qh, qh_ERRqhull, facet, ridge);
    }
  }
  return vertices;
} /* facet3vertex */

/*---------------------------------

  qh_findbestfacet(qh, point, bestoutside, bestdist, isoutside )
    find facet that is furthest below a point

    for Delaunay triangulations,
      Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed
      Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates.

  returns:
    if bestoutside is set (e.g., qh_ALL)
      returns best facet that is not upperdelaunay
      if Delaunay and inside, point is outside circumsphere of bestfacet
    else
      returns first facet below point
      if point is inside, returns nearest, !upperdelaunay facet
    distance to facet
    isoutside set if outside of facet

  notes:
    Distance is measured by distance to the facet's hyperplane.  For
    Delaunay facets, this is not the same as the containing facet.  It may
    be an adjacent facet or a different tricoplanar facet.  See 
    locate a facet with qh_findbestfacet()

    For tricoplanar facets, this finds one of the tricoplanar facets closest
    to the point.  

    If inside, qh_findbestfacet performs an exhaustive search
       this may be too conservative.  Sometimes it is clearly required.

    qh_findbestfacet is not used by qhull.
    uses qh.visit_id and qh.coplanarset

  see:
    qh_findbest
*/
facetT *qh_findbestfacet(qhT *qh, pointT *point, boolT bestoutside,
           realT *bestdist, boolT *isoutside) {
  facetT *bestfacet= NULL;
  int numpart, totpart= 0;

  bestfacet= qh_findbest(qh, point, qh->facet_list,
                            bestoutside, !qh_ISnewfacets, bestoutside /* qh_NOupper */,
                            bestdist, isoutside, &totpart);
  if (*bestdist < -qh->DISTround) {
    bestfacet= qh_findfacet_all(qh, point, !qh_NOupper, bestdist, isoutside, &numpart);
    totpart += numpart;
    if ((isoutside && *isoutside && bestoutside)
    || (isoutside && !*isoutside && bestfacet->upperdelaunay)) {
      bestfacet= qh_findbest(qh, point, bestfacet,
                            bestoutside, False, bestoutside,
                            bestdist, isoutside, &totpart);
      totpart += numpart;
    }
  }
  trace3((qh, qh->ferr, 3014, "qh_findbestfacet: f%d dist %2.2g isoutside %d totpart %d\n",
          bestfacet->id, *bestdist, (isoutside ? *isoutside : UINT_MAX), totpart));
  return bestfacet;
} /* findbestfacet */

/*---------------------------------

  qh_findbestlower(qh, facet, point, bestdist, numpart )
    returns best non-upper, non-flipped neighbor of facet for point
    if needed, searches vertex neighbors

  returns:
    returns bestdist and updates numpart

  notes:
    called by qh_findbest() for points above an upperdelaunay facet
    if Delaunay and inside, point is outside of circumsphere of bestfacet

*/
facetT *qh_findbestlower(qhT *qh, facetT *upperfacet, pointT *point, realT *bestdistp, int *numpart) {
  facetT *neighbor, **neighborp, *bestfacet= NULL;
  realT bestdist= -REALmax/2 /* avoid underflow */;
  realT dist;
  vertexT *vertex;
  boolT isoutside= False;  /* not used */

  zinc_(Zbestlower);
  FOREACHneighbor_(upperfacet) {
    if (neighbor->upperdelaunay || neighbor->flipped)
      continue;
    (*numpart)++;
    qh_distplane(qh, point, neighbor, &dist);
    if (dist > bestdist) {
      bestfacet= neighbor;
      bestdist= dist;
    }
  }
  if (!bestfacet) {
    zinc_(Zbestlowerv);
    /* rarely called, numpart does not count nearvertex computations */
    vertex= qh_nearvertex(qh, upperfacet, point, &dist);
    qh_vertexneighbors(qh);
    FOREACHneighbor_(vertex) {
      if (neighbor->upperdelaunay || neighbor->flipped)
        continue;
      (*numpart)++;
      qh_distplane(qh, point, neighbor, &dist);
      if (dist > bestdist) {
        bestfacet= neighbor;
        bestdist= dist;
      }
    }
  }
  if (!bestfacet) {
    zinc_(Zbestlowerall);  /* invoked once per point in outsideset */
    zmax_(Zbestloweralln, qh->num_facets);
    /* [dec'15] Previously reported as QH6228 */
    trace3((qh, qh->ferr, 3025, "qh_findbestlower: all neighbors of facet %d are flipped or upper Delaunay.  Search all facets\n",
        upperfacet->id));
    /* rarely called */
    bestfacet= qh_findfacet_all(qh, point, qh_NOupper, &bestdist, &isoutside, numpart);
  }
  *bestdistp= bestdist;
  trace3((qh, qh->ferr, 3015, "qh_findbestlower: f%d dist %2.2g for f%d p%d\n",
          bestfacet->id, bestdist, upperfacet->id, qh_pointid(qh, point)));
  return bestfacet;
} /* findbestlower */

/*---------------------------------

  qh_findfacet_all(qh, point, noupper, bestdist, isoutside, numpart )
    exhaustive search for facet below a point
    ignore flipped and visible facets, f.normal==NULL, and if noupper, f.upperdelaunay facets

    for Delaunay triangulations,
      Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed
      Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates.

  returns:
    returns first facet below point
    if point is inside,
      returns nearest facet
    distance to facet
    isoutside if point is outside of the hull
    number of distance tests

  notes:
    called by qh_findbestlower if all neighbors are flipped or upper Delaunay (QH3025)
    primarily for library users (qh_findbestfacet), rarely used by Qhull
*/
facetT *qh_findfacet_all(qhT *qh, pointT *point, boolT noupper, realT *bestdist, boolT *isoutside,
                          int *numpart) {
  facetT *bestfacet= NULL, *facet;
  realT dist;
  int totpart= 0;

  *bestdist= -REALmax;
  *isoutside= False;
  FORALLfacets {
    if (facet->flipped || !facet->normal || facet->visible)
      continue;
    if (noupper && facet->upperdelaunay)
      continue;
    totpart++;
    qh_distplane(qh, point, facet, &dist);
    if (dist > *bestdist) {
      *bestdist= dist;
      bestfacet= facet;
      if (dist > qh->MINoutside) {
        *isoutside= True;
        break;
      }
    }
  }
  *numpart= totpart;
  trace3((qh, qh->ferr, 3016, "qh_findfacet_all: p%d, noupper? %d, f%d, dist %2.2g, isoutside %d, totpart %d\n",
      qh_pointid(qh, point), noupper, getid_(bestfacet), *bestdist, *isoutside, totpart));
  return bestfacet;
} /* findfacet_all */

/*---------------------------------

  qh_findgood(qh, facetlist, goodhorizon )
    identify good facets for qh.PRINTgood and qh_buildcone_onlygood
    goodhorizon is count of good, horizon facets from qh_find_horizon, otherwise 0 from qh_findgood_all
    if not qh.MERGING and qh.GOODvertex>0
      facet includes point as vertex
      if !match, returns goodhorizon
    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 to thresholds
      sets GOODclosest

  returns:
    number of new, good facets found
    determines facet->good
    may update qh.GOODclosest

  notes:
    called from qh_initbuild, qh_buildcone_onlygood, and qh_findgood_all
    qh_findgood_all (called from qh_prepare_output) further reduces the good region

  design:
    count good facets
    if not merging, clear good facets that fail qh.GOODvertex ('QVn', but not 'QV-n')
    clear good facets that fail qh.GOODpoint ('QGn' or 'QG-n')
    clear good facets that fail qh.GOODthreshold
    if !goodhorizon and !find f.good,
      sets GOODclosest to facet with closest angle to thresholds
*/
int qh_findgood(qhT *qh, facetT *facetlist, int goodhorizon) {
  facetT *facet, *bestfacet= NULL;
  realT angle, bestangle= REALmax, dist;
  int  numgood=0;

  FORALLfacet_(facetlist) {
    if (facet->good)
      numgood++;
  }
  if (qh->GOODvertex>0 && !qh->MERGING) {
    FORALLfacet_(facetlist) {
      if (facet->good && !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, qh->GOODpointp, facet, &dist);
        if ((qh->GOODpoint > 0) ^ (dist > 0.0)) {
          facet->good= False;
          numgood--;
        }
      }
    }
  }
  if (qh->GOODthreshold && (numgood || goodhorizon || qh->GOODclosest)) {
    FORALLfacet_(facetlist) {
      if (facet->good && facet->normal) {
        if (!qh_inthresholds(qh, facet->normal, &angle)) {
          facet->good= False;
          numgood--;
          if (angle < bestangle) {
            bestangle= angle;
            bestfacet= facet;
          }
        }
      }
    }
    if (numgood == 0 && (goodhorizon == 0 || qh->GOODclosest)) {
      if (qh->GOODclosest) {
        if (qh->GOODclosest->visible)
          qh->GOODclosest= NULL;
        else {
          qh_inthresholds(qh, qh->GOODclosest->normal, &angle);
          if (angle < bestangle)
            bestfacet= qh->GOODclosest;
        }
      }
      if (bestfacet && bestfacet != qh->GOODclosest) {   /* numgood == 0 */
        if (qh->GOODclosest)
          qh->GOODclosest->good= False;
        qh->GOODclosest= bestfacet;
        bestfacet->good= True;
        numgood++;
        trace2((qh, qh->ferr, 2044, "qh_findgood: f%d is closest(%2.2g) to thresholds\n",
           bestfacet->id, bestangle));
        return numgood;
      }
    }else if (qh->GOODclosest) { /* numgood > 0 */
      qh->GOODclosest->good= False;
      qh->GOODclosest= NULL;
    }
  }
  zadd_(Zgoodfacet, numgood);
  trace2((qh, qh->ferr, 2045, "qh_findgood: found %d good facets with %d good horizon and qh.GOODclosest f%d\n",
               numgood, goodhorizon, getid_(qh->GOODclosest)));
  if (!numgood && qh->GOODvertex>0 && !qh->MERGING)
    return goodhorizon;
  return numgood;
} /* findgood */

/*---------------------------------

  qh_findgood_all(qh, facetlist )
    apply other constraints for good facets (used by qh.PRINTgood)
    if qh.GOODvertex
      facet includes (>0) or doesn't include (<0) point as vertex
      if last good facet and ONLYgood, prints warning and continues
    if qh.SPLITthresholds (e.g., qh.DELAUNAY)
      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:
    called by qh_prepare_output and qh_printneighborhood
    unless qh.ONLYgood, calls qh_findgood first

  design:
    uses qh_findgood to mark good facets
    clear f.good for failed qh.GOODvertex
    clear f.good for failed qh.SPLITthreholds
       if no more good facets, select best of qh.SPLITthresholds
*/
void qh_findgood_all(qhT *qh, facetT *facetlist) {
  facetT *facet, *bestfacet=NULL;
  realT angle, bestangle= REALmax;
  int  numgood=0, startgood;

  if (!qh->GOODvertex && !qh->GOODthreshold && !qh->GOODpoint
  && !qh->SPLITthresholds)
    return;
  if (!qh->ONLYgood)
    qh_findgood(qh, qh->facet_list, 0);
  FORALLfacet_(facetlist) {
    if (facet->good)
      numgood++;
  }
  if (qh->GOODvertex <0 || (qh->GOODvertex > 0 && qh->MERGING)) {
    FORALLfacet_(facetlist) {
      if (facet->good && ((qh->GOODvertex > 0) ^ !!qh_isvertex(qh->GOODvertexp, facet->vertices))) { /* convert to bool */
        if (!--numgood) {
          if (qh->ONLYgood) {
            qh_fprintf(qh, qh->ferr, 7064, "qhull warning: good vertex p%d does not match last good facet f%d.  Ignored.\n",
               qh_pointid(qh, qh->GOODvertexp), facet->id);
            return;
          }else if (qh->GOODvertex > 0)
            qh_fprintf(qh, qh->ferr, 7065, "qhull warning: point p%d is not a vertex('QV%d').\n",
                qh->GOODvertex-1, qh->GOODvertex-1);
          else
            qh_fprintf(qh, qh->ferr, 7066, "qhull warning: point p%d is a vertex for every facet('QV-%d').\n",
                -qh->GOODvertex - 1, -qh->GOODvertex - 1);
        }
        facet->good= False;
      }
    }
  }
  startgood= numgood;
  if (qh->SPLITthresholds) {
    FORALLfacet_(facetlist) {
      if (facet->good) {
        if (!qh_inthresholds(qh, facet->normal, &angle)) {
          facet->good= False;
          numgood--;
          if (angle < bestangle) {
            bestangle= angle;
            bestfacet= facet;
          }
        }
      }
    }
    if (!numgood && bestfacet) {
      bestfacet->good= True;
      numgood++;
      trace0((qh, qh->ferr, 23, "qh_findgood_all: f%d is closest(%2.2g) to split thresholds\n",
           bestfacet->id, bestangle));
      return;
    }
  }
  if (numgood == 1 && !qh->PRINTgood && qh->GOODclosest && qh->GOODclosest->good) {
    trace2((qh, qh->ferr, 2109, "qh_findgood_all: undo selection of qh.GOODclosest f%d since it would fail qh_inthresholds in qh_skipfacet\n",
      qh->GOODclosest->id));
    qh->GOODclosest->good= False;
    numgood= 0;
  }
  qh->num_good= numgood;
  trace0((qh, qh->ferr, 24, "qh_findgood_all: %d good facets remain out of %d facets\n",
        numgood, startgood));
} /* findgood_all */

/*---------------------------------

  qh_furthestnext()
    set qh.facet_next to facet with furthest of all furthest points
    searches all facets on qh.facet_list

  notes:
    this may help avoid precision problems
*/
void qh_furthestnext(qhT *qh /* qh.facet_list */) {
  facetT *facet, *bestfacet= NULL;
  realT dist, bestdist= -REALmax;

  FORALLfacets {
    if (facet->outsideset) {
#if qh_COMPUTEfurthest
      pointT *furthest;
      furthest= (pointT *)qh_setlast(facet->outsideset);
      zinc_(Zcomputefurthest);
      qh_distplane(qh, furthest, facet, &dist);
#else
      dist= facet->furthestdist;
#endif
      if (dist > bestdist) {
        bestfacet= facet;
        bestdist= dist;
      }
    }
  }
  if (bestfacet) {
    qh_removefacet(qh, bestfacet);
    qh_prependfacet(qh, bestfacet, &qh->facet_next);
    trace1((qh, qh->ferr, 1029, "qh_furthestnext: made f%d next facet(dist %.2g)\n",
            bestfacet->id, bestdist));
  }
} /* furthestnext */

/*---------------------------------

  qh_furthestout(qh, facet )
    make furthest outside point the last point of outsideset

  returns:
    updates facet->outsideset
    clears facet->notfurthest
    sets facet->furthestdist

  design:
    determine best point of outsideset
    make it the last point of outsideset
*/
void qh_furthestout(qhT *qh, facetT *facet) {
  pointT *point, **pointp, *bestpoint= NULL;
  realT dist, bestdist= -REALmax;

  FOREACHpoint_(facet->outsideset) {
    qh_distplane(qh, point, facet, &dist);
    zinc_(Zcomputefurthest);
    if (dist > bestdist) {
      bestpoint= point;
      bestdist= dist;
    }
  }
  if (bestpoint) {
    qh_setdel(facet->outsideset, point);
    qh_setappend(qh, &facet->outsideset, point);
#if !qh_COMPUTEfurthest
    facet->furthestdist= bestdist;
#endif
  }
  facet->notfurthest= False;
  trace3((qh, qh->ferr, 3017, "qh_furthestout: p%d is furthest outside point of f%d\n",
          qh_pointid(qh, point), facet->id));
} /* furthestout */


/*---------------------------------

  qh_infiniteloop(qh, facet )
    report infinite loop error due to facet
*/
void qh_infiniteloop(qhT *qh, facetT *facet) {

  qh_fprintf(qh, qh->ferr, 6149, "qhull internal error (qh_infiniteloop): potential infinite loop detected.  If visible, f.replace. If newfacet, f.samecycle\n");
  qh_errexit(qh, qh_ERRqhull, facet, NULL);
} /* qh_infiniteloop */

/*---------------------------------

  qh_initbuild()
    initialize hull and outside sets with point array
    qh.FIRSTpoint/qh.NUMpoints is point array
    if qh.GOODpoint
      adds qh.GOODpoint to initial hull

  returns:
    qh_facetlist with initial hull
    points partioned into outside sets, coplanar sets, or inside
    initializes qh.GOODpointp, qh.GOODvertexp,

  design:
    initialize global variables used during qh_buildhull
    determine precision constants and points with max/min coordinate values
      if qh.SCALElast, scale last coordinate(for 'd')
    initialize qh.newfacet_list, qh.facet_tail
    initialize qh.vertex_list, qh.newvertex_list, qh.vertex_tail
    determine initial vertices
    build initial simplex
    partition input points into facets of initial simplex
    set up lists
    if qh.ONLYgood
      check consistency
      add qh.GOODvertex if defined
*/
void qh_initbuild(qhT *qh) {
  setT *maxpoints, *vertices;
  facetT *facet;
  int i, numpart;
  realT dist;
  boolT isoutside;

  if (qh->PRINTstatistics) {
    qh_fprintf(qh, qh->ferr, 9350, "qhull %s Statistics: %s | %s\n",
      qh_version, qh->rbox_command, qh->qhull_command);
    fflush(NULL);
  }
  qh->furthest_id= qh_IDunknown;
  qh->lastreport= 0;
  qh->lastfacets= 0;
  qh->lastmerges= 0;
  qh->lastplanes= 0;
  qh->lastdist= 0;
  qh->facet_id= qh->vertex_id= qh->ridge_id= 0;
  qh->visit_id= qh->vertex_visit= 0;
  qh->maxoutdone= False;

  if (qh->GOODpoint > 0)
    qh->GOODpointp= qh_point(qh, qh->GOODpoint-1);
  else if (qh->GOODpoint < 0)
    qh->GOODpointp= qh_point(qh, -qh->GOODpoint-1);
  if (qh->GOODvertex > 0)
    qh->GOODvertexp= qh_point(qh, qh->GOODvertex-1);
  else if (qh->GOODvertex < 0)
    qh->GOODvertexp= qh_point(qh, -qh->GOODvertex-1);
  if ((qh->GOODpoint
       && (qh->GOODpointp < qh->first_point  /* also catches !GOODpointp */
           || qh->GOODpointp > qh_point(qh, qh->num_points-1)))
  || (qh->GOODvertex
       && (qh->GOODvertexp < qh->first_point  /* also catches !GOODvertexp */
           || qh->GOODvertexp > qh_point(qh, qh->num_points-1)))) {
    qh_fprintf(qh, qh->ferr, 6150, "qhull input error: either QGn or QVn point is > p%d\n",
             qh->num_points-1);
    qh_errexit(qh, qh_ERRinput, NULL, NULL);
  }
  maxpoints= qh_maxmin(qh, qh->first_point, qh->num_points, qh->hull_dim);
  if (qh->SCALElast)
    qh_scalelast(qh, qh->first_point, qh->num_points, qh->hull_dim, qh->MINlastcoord, qh->MAXlastcoord, qh->MAXabs_coord);
  qh_detroundoff(qh);
  if (qh->DELAUNAY && qh->upper_threshold[qh->hull_dim-1] > REALmax/2
                  && qh->lower_threshold[qh->hull_dim-1] < -REALmax/2) {
    for (i=qh_PRINTEND; i--; ) {
      if (qh->PRINTout[i] == qh_PRINTgeom && qh->DROPdim < 0
          && !qh->GOODthreshold && !qh->SPLITthresholds)
        break;  /* in this case, don't set upper_threshold */
    }
    if (i < 0) {
      if (qh->UPPERdelaunay) { /* matches qh.upperdelaunay in qh_setfacetplane */
        qh->lower_threshold[qh->hull_dim-1]= qh->ANGLEround * qh_ZEROdelaunay;
        qh->GOODthreshold= True;
      }else {
        qh->upper_threshold[qh->hull_dim-1]= -qh->ANGLEround * qh_ZEROdelaunay;
        if (!qh->GOODthreshold)
          qh->SPLITthresholds= True; /* build upper-convex hull even if Qg */
          /* qh_initqhull_globals errors if Qg without Pdk/etc. */
      }
    }
  }
  trace4((qh, qh->ferr, 4091, "qh_initbuild: create sentinels for qh.facet_tail and qh.vertex_tail\n"));
  qh->facet_list= qh->newfacet_list= qh->facet_tail= qh_newfacet(qh);
  qh->num_facets= qh->num_vertices= qh->num_visible= 0;
  qh->vertex_list= qh->newvertex_list= qh->vertex_tail= qh_newvertex(qh, NULL);
  vertices= qh_initialvertices(qh, qh->hull_dim, maxpoints, qh->first_point, qh->num_points);
  qh_initialhull(qh, vertices);  /* initial qh->facet_list */
  qh_partitionall(qh, vertices, qh->first_point, qh->num_points);
  if (qh->PRINToptions1st || qh->TRACElevel || qh->IStracing) {
    if (qh->TRACElevel || qh->IStracing)
      qh_fprintf(qh, qh->ferr, 8103, "\nTrace level T%d, IStracing %d, point TP%d, merge TM%d, dist TW%2.2g, qh.tracefacet_id %d, traceridge_id %d, tracevertex_id %d, last qh.RERUN %d, %s | %s\n",
         qh->TRACElevel, qh->IStracing, qh->TRACEpoint, qh->TRACEmerge, qh->TRACEdist, qh->tracefacet_id, qh->traceridge_id, qh->tracevertex_id, qh->TRACElastrun, qh->rbox_command, qh->qhull_command);
    qh_fprintf(qh, qh->ferr, 8104, "Options selected for Qhull %s:\n%s\n", qh_version, qh->qhull_options);
  }
  qh_resetlists(qh, False, qh_RESETvisible /* qh.visible_list newvertex_list qh.newfacet_list */);
  qh->facet_next= qh->facet_list;
  qh_furthestnext(qh /* qh.facet_list */);
  if (qh->PREmerge) {
    qh->cos_max= qh->premerge_cos;
    qh->centrum_radius= qh->premerge_centrum; /* overwritten by qh_premerge */
  }
  if (qh->ONLYgood) {
    if (qh->GOODvertex > 0 && qh->MERGING) {
      qh_fprintf(qh, qh->ferr, 6151, "qhull input error: 'Qg QVn' (only good vertex) does not work with merging.\nUse 'QJ' to joggle the input or 'Q0' to turn off merging.\n");
      qh_errexit(qh, qh_ERRinput, NULL, NULL);
    }
    if (!(qh->GOODthreshold || qh->GOODpoint
         || (!qh->MERGEexact && !qh->PREmerge && qh->GOODvertexp))) {
      qh_fprintf(qh, qh->ferr, 6152, "qhull input error: 'Qg' (ONLYgood) needs a good threshold('Pd0D0'), a good point(QGn or QG-n), or a good vertex with 'QJ' or 'Q0' (QVn).\n");
      qh_errexit(qh, qh_ERRinput, NULL, NULL);
    }
    if (qh->GOODvertex > 0  && !qh->MERGING  /* matches qh_partitionall */
    && !qh_isvertex(qh->GOODvertexp, vertices)) {
      facet= qh_findbestnew(qh, qh->GOODvertexp, qh->facet_list,
                          &dist, !qh_ALL, &isoutside, &numpart);
      zadd_(Zdistgood, numpart);
      if (!isoutside) {
        qh_fprintf(qh, qh->ferr, 6153, "qhull input error: point for QV%d is inside initial simplex.  It can not be made a vertex.\n",
               qh_pointid(qh, qh->GOODvertexp));
        qh_errexit(qh, qh_ERRinput, NULL, NULL);
      }
      if (!qh_addpoint(qh, qh->GOODvertexp, facet, False)) {
        qh_settempfree(qh, &vertices);
        qh_settempfree(qh, &maxpoints);
        return;
      }
    }
    qh_findgood(qh, qh->facet_list, 0);
  }
  qh_settempfree(qh, &vertices);
  qh_settempfree(qh, &maxpoints);
  trace1((qh, qh->ferr, 1030, "qh_initbuild: initial hull created and points partitioned\n"));
} /* initbuild */

/*---------------------------------

  qh_initialhull(qh, vertices )
    constructs the initial hull as a DIM3 simplex of vertices

  notes:
    only called by qh_initbuild

  design:
    creates a simplex (initializes lists)
    determines orientation of simplex
    sets hyperplanes for facets
    doubles checks orientation (in case of axis-parallel facets with Gaussian elimination)
    checks for flipped facets and qh.NARROWhull
    checks the result
*/
void qh_initialhull(qhT *qh, setT *vertices) {
  facetT *facet, *firstfacet, *neighbor, **neighborp;
  realT angle, minangle= REALmax, dist;

  qh_createsimplex(qh, vertices /* qh.facet_list */);
  qh_resetlists(qh, False, qh_RESETvisible);
  qh->facet_next= qh->facet_list;      /* advance facet when processed */
  qh->interior_point= qh_getcenter(qh, vertices);
  if (qh->IStracing) {
    qh_fprintf(qh, qh->ferr, 8105, "qh_initialhull: ");
    qh_printpoint(qh, qh->ferr, "qh.interior_point", qh->interior_point);
  }
  firstfacet= qh->facet_list;
  qh_setfacetplane(qh, firstfacet);   /* qh_joggle_restart if flipped */
  if (firstfacet->flipped) {
    trace1((qh, qh->ferr, 1065, "qh_initialhull: ignore f%d flipped.  Test qh.interior_point (p-2) for clearly flipped\n", firstfacet->id));
    firstfacet->flipped= False;
  }
  zzinc_(Zdistcheck);
  qh_distplane(qh, qh->interior_point, firstfacet, &dist);
  if (dist > qh->DISTround) {  /* clearly flipped */
    trace1((qh, qh->ferr, 1060, "qh_initialhull: initial orientation incorrect, qh.interior_point is %2.2g from f%d.  Reversing orientation of all facets\n",
          dist, firstfacet->id));
    FORALLfacets
      facet->toporient ^= (unsigned char)True;
    qh_setfacetplane(qh, firstfacet);
  }
  FORALLfacets {
    if (facet != firstfacet)
      qh_setfacetplane(qh, facet);    /* qh_joggle_restart if flipped */
  }
  FORALLfacets {
    if (facet->flipped) {
      trace1((qh, qh->ferr, 1066, "qh_initialhull: ignore f%d flipped.  Test qh.interior_point (p-2) for clearly flipped\n", facet->id));
      facet->flipped= False;
    }
    zzinc_(Zdistcheck);
    qh_distplane(qh, qh->interior_point, facet, &dist);  /* duplicates qh_setfacetplane */
    if (dist > qh->DISTround) {  /* clearly flipped, due to axis-parallel facet or coplanar firstfacet */
      trace1((qh, qh->ferr, 1031, "qh_initialhull: initial orientation incorrect, qh.interior_point is %2.2g from f%d.  Either axis-parallel facet or coplanar firstfacet f%d.  Force outside orientation of all facets\n"));
      FORALLfacets { /* reuse facet, then 'break' */
        facet->flipped= False;
        facet->toporient ^= (unsigned char)True;
        qh_orientoutside(qh, facet);  /* force outside orientation for f.normal */
      }
      break;
    }
  }
  FORALLfacets {
    if (!qh_checkflipped(qh, facet, NULL, qh_ALL)) {
      if (qh->DELAUNAY && ! qh->ATinfinity) {
        qh_joggle_restart(qh, "initial Delaunay cocircular or cospherical");
        if (qh->UPPERdelaunay)
          qh_fprintf(qh, qh->ferr, 6240, "Qhull precision error: initial Delaunay input sites are cocircular or cospherical.  Option 'Qs' searches all points.  Use option 'QJ' to joggle the input, otherwise cannot compute the upper Delaunay triangulation or upper Voronoi diagram of cocircular/cospherical points.\n");
        else
          qh_fprintf(qh, qh->ferr, 6239, "Qhull precision error: initial Delaunay input sites are cocircular or cospherical.  Use option 'Qz' for the Delaunay triangulation or Voronoi diagram of cocircular/cospherical points; it adds a point \"at infinity\".  Alternatively use option 'QJ' to joggle the input.  Use option 'Qs' to search all points for the initial simplex.\n");
        qh_printvertexlist(qh, qh->ferr, "\ninput sites with last coordinate projected to a paraboloid\n", qh->facet_list, NULL, qh_ALL);
        qh_errexit(qh, qh_ERRinput, NULL, NULL);
      }else {
        qh_joggle_restart(qh, "initial simplex is flat");
        qh_fprintf(qh, qh->ferr, 6154, "Qhull precision error: Initial simplex is flat (facet %d is coplanar with the interior point)\n",
                   facet->id);
        qh_errexit(qh, qh_ERRsingular, NULL, NULL);  /* calls qh_printhelp_singular */
      }
    }
    FOREACHneighbor_(facet) {
      angle= qh_getangle(qh, facet->normal, neighbor->normal);
      minimize_( minangle, angle);
    }
  }
  if (minangle < qh_MAXnarrow && !qh->NOnarrow) {
    realT diff= 1.0 + minangle;

    qh->NARROWhull= True;
    qh_option(qh, "_narrow-hull", NULL, &diff);
    if (minangle < qh_WARNnarrow && !qh->RERUN && qh->PRINTprecision)
      qh_printhelp_narrowhull(qh, qh->ferr, minangle);
  }
  zzval_(Zprocessed)= qh->hull_dim+1;
  qh_checkpolygon(qh, qh->facet_list);
  qh_checkconvex(qh, qh->facet_list, qh_DATAfault);
  if (qh->IStracing >= 1) {
    qh_fprintf(qh, qh->ferr, 8105, "qh_initialhull: simplex constructed\n");
  }
} /* initialhull */

/*---------------------------------

  qh_initialvertices(qh, dim, maxpoints, points, numpoints )
    determines a non-singular set of initial vertices
    maxpoints may include duplicate points

  returns:
    temporary set of dim+1 vertices in descending order by vertex id
    if qh.RANDOMoutside && !qh.ALLpoints
      picks random points
    if dim >= qh_INITIALmax,
      uses min/max x and max points with non-zero determinants

  notes:
    unless qh.ALLpoints,
      uses maxpoints as long as determinate is non-zero
*/
setT *qh_initialvertices(qhT *qh, int dim, setT *maxpoints, pointT *points, int numpoints) {
  pointT *point, **pointp;
  setT *vertices, *simplex, *tested;
  realT randr;
  int idx, point_i, point_n, k;
  boolT nearzero= False;

  vertices= qh_settemp(qh, dim + 1);
  simplex= qh_settemp(qh, dim + 1);
  if (qh->ALLpoints)
    qh_maxsimplex(qh, dim, NULL, points, numpoints, &simplex);
  else if (qh->RANDOMoutside) {
    while (qh_setsize(qh, simplex) != dim+1) {
      randr= qh_RANDOMint;
      randr= randr/(qh_RANDOMmax+1);
      randr= floor(qh->num_points * randr);
      idx= (int)randr;
      while (qh_setin(simplex, qh_point(qh, idx))) {
        idx++; /* in case qh_RANDOMint always returns the same value */
        idx= idx < qh->num_points ? idx : 0;
      }
      qh_setappend(qh, &simplex, qh_point(qh, idx));
    }
  }else if (qh->hull_dim >= qh_INITIALmax) {
    tested= qh_settemp(qh, dim+1);
    qh_setappend(qh, &simplex, SETfirst_(maxpoints));   /* max and min X coord */
    qh_setappend(qh, &simplex, SETsecond_(maxpoints));
    qh_maxsimplex(qh, fmin_(qh_INITIALsearch, dim), maxpoints, points, numpoints, &simplex);
    k= qh_setsize(qh, simplex);
    FOREACHpoint_i_(qh, maxpoints) {
      if (k >= dim)  /* qh_maxsimplex for last point */
        break;
      if (point_i & 0x1) {     /* first try up to dim, max. coord. points */
        if (!qh_setin(simplex, point) && !qh_setin(tested, point)){
          qh_detsimplex(qh, point, simplex, k, &nearzero);
          if (nearzero)
            qh_setappend(qh, &tested, point);
          else {
            qh_setappend(qh, &simplex, point);
            k++;
          }
        }
      }
    }
    FOREACHpoint_i_(qh, maxpoints) {
      if (k >= dim)  /* qh_maxsimplex for last point */
        break;
      if ((point_i & 0x1) == 0) {  /* then test min. coord points */
        if (!qh_setin(simplex, point) && !qh_setin(tested, point)){
          qh_detsimplex(qh, point, simplex, k, &nearzero);
          if (nearzero)
            qh_setappend(qh, &tested, point);
          else {
            qh_setappend(qh, &simplex, point);
            k++;
          }
        }
      }
    }
    /* remove tested points from maxpoints */
    FOREACHpoint_i_(qh, maxpoints) {
      if (qh_setin(simplex, point) || qh_setin(tested, point))
        SETelem_(maxpoints, point_i)= NULL;
    }
    qh_setcompact(qh, maxpoints);
    idx= 0;
    while (k < dim && (point= qh_point(qh, idx++))) {
      if (!qh_setin(simplex, point) && !qh_setin(tested, point)){
        qh_detsimplex(qh, point, simplex, k, &nearzero);
        if (!nearzero){
          qh_setappend(qh, &simplex, point);
          k++;
        }
      }
    }
    qh_settempfree(qh, &tested);
    qh_maxsimplex(qh, dim, maxpoints, points, numpoints, &simplex);
  }else /* qh.hull_dim < qh_INITIALmax */
    qh_maxsimplex(qh, dim, maxpoints, points, numpoints, &simplex);
  FOREACHpoint_(simplex)
    qh_setaddnth(qh, &vertices, 0, qh_newvertex(qh, point)); /* descending order */
  qh_settempfree(qh, &simplex);
  return vertices;
} /* initialvertices */


/*---------------------------------

  qh_isvertex( point, vertices )
    returns vertex if point is in vertex set, else returns NULL

  notes:
    for qh.GOODvertex
*/
vertexT *qh_isvertex(pointT *point, setT *vertices) {
  vertexT *vertex, **vertexp;

  FOREACHvertex_(vertices) {
    if (vertex->point == point)
      return vertex;
  }
  return NULL;
} /* isvertex */

/*---------------------------------

  qh_makenewfacets(qh, point )
    make new facets from point and qh.visible_list

  returns:
    apex (point) of the new facets
    qh.newfacet_list= list of new facets with hyperplanes and ->newfacet
    qh.newvertex_list= list of vertices in new facets with ->newfacet set

    if (qh.NEWtentative)
      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->NEWtentative
    qh_matchnewfacets() -- match up neighbors
    qh_update_vertexneighbors() -- update vertex neighbors and delvertices
    qh_deletevisible() -- delete visible facets
    qh_checkpolygon() --check the result
    qh_triangulate() -- triangulate a non-simplicial facet

  design:
    for each visible facet
      make new facets to its horizon facets
      update its f.replace
      clear its neighbor set
*/
vertexT *qh_makenewfacets(qhT *qh, pointT *point /* qh.visible_list */) {
  facetT *visible, *newfacet= NULL, *newfacet2= NULL, *neighbor, **neighborp;
  vertexT *apex;
  int numnew=0;

  if (qh->CHECKfrequently) {
    qh_checkdelridge(qh);
  }
  qh->newfacet_list= qh->facet_tail;
  qh->newvertex_list= qh->vertex_tail;
  apex= qh_newvertex(qh, point);
  qh_appendvertex(qh, apex);
  qh->visit_id++;
  FORALLvisible_facets {
    FOREACHneighbor_(visible)
      neighbor->seen= False;
    if (visible->ridges) {
      visible->visitid= qh->visit_id;
      newfacet2= qh_makenew_nonsimplicial(qh, visible, apex, &numnew);
    }
    if (visible->simplicial)
      newfacet= qh_makenew_simplicial(qh, visible, apex, &numnew);
    if (!qh->NEWtentative) {
      if (newfacet2)  /* newfacet is null if all ridges defined */
        newfacet= newfacet2;
      if (newfacet)
        visible->f.replace= newfacet;
      else
        zinc_(Zinsidevisible);
      if (visible->ridges)      /* ridges and neighbors are no longer valid for visible facet */
        SETfirst_(visible->ridges)= NULL;
      SETfirst_(visible->neighbors)= NULL;
    }
  }
  if (!qh->NEWtentative)
    qh->NEWfacets= True;
  trace1((qh, qh->ferr, 1032, "qh_makenewfacets: created %d new facets f%d..f%d from point p%d to horizon\n",
    numnew, qh->first_newfacet, qh->facet_id-1, qh_pointid(qh, point)));
  if (qh->IStracing >= 4)
    qh_printfacetlist(qh, qh->newfacet_list, NULL, qh_ALL);
  return apex;
} /* makenewfacets */

#ifndef qh_NOmerge
/*---------------------------------

  qh_matchdupridge(qh, atfacet, atskip, hashsize, hashcount )
    match duplicate ridges in qh.hash_table for atfacet@atskip
    duplicates marked with ->dupridge and qh_DUPLICATEridge

  returns:
    vertex-facet distance (>0.0) for qh_MERGEridge ridge
    updates hashcount
    set newfacet, facet, matchfacet's hyperplane (removes from mergecycle of coplanarhorizon facets)

  see also:
    qh_matchneighbor

  notes:
    only called by qh_matchnewfacets for qh_buildcone and qh_triangulate_facet
    assumes atfacet is simplicial
    assumes atfacet->neighbors @ atskip == qh_DUPLICATEridge
    usually keeps ridge with the widest merge
    both MRGdupridge and MRGflipped are required merges -- rbox 100 C1,2e-13 D4 t1 | qhull d Qbb
      can merge flipped f11842 skip 3 into f11862 skip 2 and vice versa (forced by goodmatch/goodmatch2)
         blocks -- cannot merge f11862 skip 2 and f11863 skip2 (the widest merge)
         must block -- can merge f11843 skip 3 into f11842 flipped skip 3, but not vice versa
      can merge f11843 skip 3 into f11863 skip 2, but not vice versa
    working/unused.h: [jan'19] Dropped qh_matchdupridge_coplanarhorizon, it was the same or slightly worse.  Complex addition, rarely occurs

  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 with the same orientation 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 with the same orientation and pass 1
          test if this is a better match
      if pass 1,
        make best match (it will not be merged)
        set newfacet, facet, matchfacet's hyperplane (removes from mergecycle of coplanarhorizon facets)

*/
coordT qh_matchdupridge(qhT *qh, facetT *atfacet, int atskip, int hashsize, int *hashcount) {
  boolT same, ismatch, isduplicate= False;
  int hash, scan;
  facetT *facet, *newfacet, *nextfacet;
  facetT *maxmatch= NULL, *maxmatch2= NULL, *goodmatch= NULL, *goodmatch2= NULL;
  int skip, newskip, nextskip= 0, makematch;
  int maxskip= 0, maxskip2= 0, goodskip= 0, goodskip2= 0;
  coordT maxdist= -REALmax, maxdist2= 0.0, dupdist, dupdist2, low, high, maxgood, gooddist= 0.0;

  maxgood= qh_WIDEdupridge * (qh->ONEmerge + qh->DISTround); 
  hash= qh_gethash(qh, hashsize, atfacet->vertices, qh->hull_dim, 1,
                     SETelem_(atfacet->vertices, atskip));
  trace2((qh, qh->ferr, 2046, "qh_matchdupridge: find dupridge matches for f%d skip %d hash %d hashcount %d\n",
          atfacet->id, atskip, hash, *hashcount));
  for (makematch=0; makematch < 2; makematch++) { /* makematch is false on the first pass and 1 on the second */
    qh->visit_id++;
    for (newfacet=atfacet, newskip=atskip; newfacet; newfacet= nextfacet, newskip= nextskip) {
      zinc_(Zhashlookup);
      nextfacet= NULL; /* exit when ismatch found */
      newfacet->visitid= qh->visit_id;
      for (scan=hash; (facet= SETelemt_(qh->hash_table, scan, facetT));
           scan= (++scan >= hashsize ? 0 : scan)) {
        if (!facet->dupridge || facet->visitid == qh->visit_id)
          continue;
        zinc_(Zhashtests);
        if (qh_matchvertices(qh, 1, newfacet->vertices, newskip, facet->vertices, &skip, &same)) {
          if (SETelem_(newfacet->vertices, newskip) == SETelem_(facet->vertices, skip)) {
            trace3((qh, qh->ferr, 3053, "qh_matchdupridge: duplicate ridge due to duplicate facets (f%d skip %d and f%d skip %d) previously reported as QH7084.  Maximize dupdist to force vertex merge\n",
              newfacet->id, newskip, facet->id, skip));
            isduplicate= True;
          }
          ismatch= (same == (boolT)(newfacet->toporient ^ facet->toporient));
          if (SETelemt_(facet->neighbors, skip, facetT) != qh_DUPLICATEridge) {
            if (!makematch) {  /* occurs if many merges, e.g., rbox 100 W0 C2,1e-13 D6 t1546872462 | qhull C0 Qt Tcv */
              qh_fprintf(qh, qh->ferr, 6155, "qhull topology error (qh_matchdupridge): missing qh_DUPLICATEridge at f%d skip %d for new f%d skip %d hash %d ismatch %d.  Set by qh_matchneighbor\n",
                facet->id, skip, newfacet->id, newskip, hash, ismatch);
              qh_errexit2(qh, qh_ERRtopology, facet, newfacet);
            }
          }else if (!ismatch) {
            nextfacet= facet;
            nextskip= skip;
          }else if (SETelemt_(newfacet->neighbors, newskip, facetT) == qh_DUPLICATEridge) {
            if (makematch) {
              if (newfacet->tricoplanar) {
                SETelem_(facet->neighbors, skip)= newfacet;
                SETelem_(newfacet->neighbors, newskip)= facet;
                *hashcount -= 2; /* removed two unmatched facets */
                trace2((qh, qh->ferr, 2075, "qh_matchdupridge: allow tricoplanar dupridge for new f%d skip %d and f%d skip %d\n",
                    newfacet->id, newskip, facet->id, skip)); 
              }else if (goodmatch && goodmatch2) {
                SETelem_(goodmatch2->neighbors, goodskip2)= qh_MERGEridge;  /* undo selection of goodmatch */
                SETelem_(facet->neighbors, skip)= newfacet;
                SETelem_(newfacet->neighbors, newskip)= facet;
                *hashcount -= 2; /* removed two unmatched facets */
                trace2((qh, qh->ferr, 2105, "qh_matchdupridge: make good forced merge of dupridge f%d skip %d into f%d skip %d, keep new f%d skip %d and f%d skip %d, dist %4.4g\n",
                  goodmatch->id, goodskip, goodmatch2->id, goodskip2, newfacet->id, newskip, facet->id, skip, gooddist)); 
                goodmatch2= NULL;
              }else {
                SETelem_(facet->neighbors, skip)= newfacet;
                SETelem_(newfacet->neighbors, newskip)= qh_MERGEridge;  /* resolved by qh_mark_dupridges */
                *hashcount -= 2; /* removed two unmatched facets */
                trace3((qh, qh->ferr, 3073, "qh_matchdupridge: make forced merge of dupridge for new f%d skip %d and f%d skip %d, maxdist %4.4g in qh_forcedmerges\n",
                  newfacet->id, newskip, facet->id, skip, maxdist2));
              }
            }else { /* !makematch */
              if (!facet->normal)
                qh_setfacetplane(qh, facet); /* qh_mergecycle will ignore 'mergehorizon' facets with normals, too many cases otherwise */
              if (!newfacet->normal) 
                qh_setfacetplane(qh, newfacet);
              dupdist= qh_getdistance(qh, facet, newfacet, &low, &high); /* ignore low/high */
              dupdist2= qh_getdistance(qh, newfacet, facet, &low, &high);
              if (isduplicate) {
                goodmatch= NULL;
                minimize_(dupdist, dupdist2);
                maxdist= dupdist;
                maxdist2= REALmax/2;
                maxmatch= facet;
                maxskip= skip;
                maxmatch2= newfacet;
                maxskip2= newskip;
                break; /* force maxmatch */
              }else if (facet->flipped && !newfacet->flipped && dupdist < maxgood) {
                if (!goodmatch || !goodmatch->flipped || dupdist < gooddist) {
                  goodmatch= facet; 
                  goodskip= skip;
                  goodmatch2= newfacet;
                  goodskip2= newskip;
                  gooddist= dupdist;
                  trace3((qh, qh->ferr, 3070, "qh_matchdupridge: try good dupridge flipped f%d skip %d into new f%d skip %d at dist %2.2g otherdist %2.2g\n",
                    goodmatch->id, goodskip, goodmatch2->id, goodskip2, gooddist, dupdist2));
                }
              }else if (newfacet->flipped && !facet->flipped && dupdist2 < maxgood) {
                if (!goodmatch || !goodmatch->flipped || dupdist2 < gooddist) {
                  goodmatch= newfacet;  
                  goodskip= newskip;
                  goodmatch2= facet;
                  goodskip2= skip;
                  gooddist= dupdist2;
                  trace3((qh, qh->ferr, 3071, "qh_matchdupridge: try good dupridge flipped new f%d skip %d into f%d skip %d at dist %2.2g otherdist %2.2g\n",
                    goodmatch->id, goodskip, goodmatch2->id, goodskip2, gooddist, dupdist));
                }
              }else if (dupdist < maxgood && (!newfacet->flipped || facet->flipped)) { /* disallow not-flipped->flipped */
                if (!goodmatch || (!goodmatch->flipped && dupdist < gooddist)) {
                  goodmatch= facet;
                  goodskip= skip;
                  goodmatch2= newfacet;
                  goodskip2= newskip;
                  gooddist= dupdist;
                  trace3((qh, qh->ferr, 3072, "qh_matchdupridge: try good dupridge f%d skip %d into new f%d skip %d at dist %2.2g otherdist %2.2g\n",
                    goodmatch->id, goodskip, goodmatch2->id, goodskip2, gooddist, dupdist2));
                }
              }else if (dupdist2 < maxgood && (!facet->flipped || newfacet->flipped)) { /* disallow not-flipped->flipped */
                if (!goodmatch || (!goodmatch->flipped && dupdist2 < gooddist)) {
                  goodmatch= newfacet;  
                  goodskip= newskip;
                  goodmatch2= facet;
                  goodskip2= skip;
                  gooddist= dupdist2;
                  trace3((qh, qh->ferr, 3018, "qh_matchdupridge: try good dupridge new f%d skip %d into f%d skip %d at dist %2.2g otherdist %2.2g\n",
                    goodmatch->id, goodskip, goodmatch2->id, goodskip2, gooddist, dupdist));
                }
              }else if (!goodmatch) { /* otherwise match the furthest apart facets */
                if (!newfacet->flipped || facet->flipped) {
                  minimize_(dupdist, dupdist2);
                }
                if (dupdist > maxdist) { /* could keep !flipped->flipped, but probably lost anyway */
                  maxdist2= maxdist;
                  maxdist= dupdist;
                  maxmatch= facet;
                  maxskip= skip;
                  maxmatch2= newfacet;
                  maxskip2= newskip;
                  trace3((qh, qh->ferr, 3055, "qh_matchdupridge: try furthest dupridge f%d skip %d new f%d skip %d at dist %2.2g\n",
                    maxmatch->id, maxskip, maxmatch2->id, maxskip2, maxdist));
                }else if (dupdist > maxdist2)
                  maxdist2= dupdist;
              }
            }
          }
        }
      } /* end of foreach entry in qh.hash_table starting at 'hash' */
      if (makematch && SETelemt_(newfacet->neighbors, newskip, facetT) == qh_DUPLICATEridge) {
        qh_fprintf(qh, qh->ferr, 6156, "qhull internal error (qh_matchdupridge): no MERGEridge match for dupridge new f%d skip %d at hash %d..%d\n",
                    newfacet->id, newskip, hash, scan);
        qh_errexit(qh, qh_ERRqhull, newfacet, NULL);
      }
    } /* end of foreach newfacet at 'hash' */
    if (!makematch) {
      if (!maxmatch && !goodmatch) {
        qh_fprintf(qh, qh->ferr, 6157, "qhull internal error (qh_matchdupridge): no maximum or good match for dupridge new f%d skip %d at hash %d..%d\n",
          atfacet->id, atskip, hash, scan);
        qh_errexit(qh, qh_ERRqhull, atfacet, NULL);
      }
      if (goodmatch) {
        SETelem_(goodmatch->neighbors, goodskip)= goodmatch2;
        SETelem_(goodmatch2->neighbors, goodskip2)= goodmatch;
        *hashcount -= 2; /* removed two unmatched facets */
        if (goodmatch->flipped) {
          if (!goodmatch2->flipped) {
            zzinc_(Zflipridge);
          }else {
            zzinc_(Zflipridge2);
            /* qh_joggle_restart called by qh_matchneighbor if qh_DUPLICATEridge */
          }
        }
        /* previously traced */
      }else {
        SETelem_(maxmatch->neighbors, maxskip)= maxmatch2; /* maxmatch!=NULL by QH6157 */
        SETelem_(maxmatch2->neighbors, maxskip2)= maxmatch;
        *hashcount -= 2; /* removed two unmatched facets */
        zzinc_(Zmultiridge);
        /* qh_joggle_restart called by qh_matchneighbor if qh_DUPLICATEridge */
        trace0((qh, qh->ferr, 25, "qh_matchdupridge: keep dupridge f%d skip %d and f%d skip %d, dist %4.4g\n",
          maxmatch2->id, maxskip2, maxmatch->id, maxskip, maxdist));
      }
    }
  }
  if (goodmatch)
    return gooddist;
  return maxdist2;
} /* matchdupridge */

#else /* qh_NOmerge */
coordT qh_matchdupridge(qhT *qh, facetT *atfacet, int atskip, int hashsize, int *hashcount) {
  QHULL_UNUSED(qh)
  QHULL_UNUSED(atfacet)
  QHULL_UNUSED(atskip)
  QHULL_UNUSED(hashsize)
  QHULL_UNUSED(hashcount)

  return 0.0;
}
#endif /* qh_NOmerge */

/*---------------------------------

  qh_nearcoplanar()
    for all facets, remove near-inside points from facet->coplanarset
    coplanar points defined by innerplane from qh_outerinner()

  returns:
    if qh->KEEPcoplanar && !qh->KEEPinside
      facet->coplanarset only contains coplanar points
    if qh.JOGGLEmax
      drops inner plane by another qh.JOGGLEmax diagonal since a
        vertex could shift out while a coplanar point shifts in

  notes:
    used for qh.PREmerge and qh.JOGGLEmax
    must agree with computation of qh.NEARcoplanar in qh_detroundoff

  design:
    if not keeping coplanar or inside points
      free all coplanar sets
    else if not keeping both coplanar and inside points
      remove !coplanar or !inside points from coplanar sets
*/
void qh_nearcoplanar(qhT *qh /* qh.facet_list */) {
  facetT *facet;
  pointT *point, **pointp;
  int numpart;
  realT dist, innerplane;

  if (!qh->KEEPcoplanar && !qh->KEEPinside) {
    FORALLfacets {
      if (facet->coplanarset)
        qh_setfree(qh, &facet->coplanarset);
    }
  }else if (!qh->KEEPcoplanar || !qh->KEEPinside) {
    qh_outerinner(qh, NULL, NULL, &innerplane);
    if (qh->JOGGLEmax < REALmax/2)
      innerplane -= qh->JOGGLEmax * sqrt((realT)qh->hull_dim);
    numpart= 0;
    FORALLfacets {
      if (facet->coplanarset) {
        FOREACHpoint_(facet->coplanarset) {
          numpart++;
          qh_distplane(qh, point, facet, &dist);
          if (dist < innerplane) {
            if (!qh->KEEPinside)
              SETref_(point)= NULL;
          }else if (!qh->KEEPcoplanar)
            SETref_(point)= NULL;
        }
        qh_setcompact(qh, facet->coplanarset);
      }
    }
    zzadd_(Zcheckpart, numpart);
  }
} /* nearcoplanar */

/*---------------------------------

  qh_nearvertex(qh, facet, point, bestdist )
    return nearest vertex in facet to point

  returns:
    vertex and its distance

  notes:
    if qh.DELAUNAY
      distance is measured in the input set
    searches neighboring tricoplanar facets (requires vertexneighbors)
      Slow implementation.  Recomputes vertex set for each point.
    The vertex set could be stored in the qh.keepcentrum facet.
*/
vertexT *qh_nearvertex(qhT *qh, facetT *facet, pointT *point, realT *bestdistp) {
  realT bestdist= REALmax, dist;
  vertexT *bestvertex= NULL, *vertex, **vertexp, *apex;
  coordT *center;
  facetT *neighbor, **neighborp;
  setT *vertices;
  int dim= qh->hull_dim;

  if (qh->DELAUNAY)
    dim--;
  if (facet->tricoplanar) {
    if (!qh->VERTEXneighbors || !facet->center) {
      qh_fprintf(qh, qh->ferr, 6158, "qhull internal error (qh_nearvertex): qh.VERTEXneighbors and facet->center required for tricoplanar facets\n");
      qh_errexit(qh, qh_ERRqhull, facet, NULL);
    }
    vertices= qh_settemp(qh, qh->TEMPsize);
    apex= SETfirstt_(facet->vertices, vertexT);
    center= facet->center;
    FOREACHneighbor_(apex) {
      if (neighbor->center == center) {
        FOREACHvertex_(neighbor->vertices)
          qh_setappend(qh, &vertices, vertex);
      }
    }
  }else
    vertices= facet->vertices;
  FOREACHvertex_(vertices) {
    dist= qh_pointdist(vertex->point, point, -dim);
    if (dist < bestdist) {
      bestdist= dist;
      bestvertex= vertex;
    }
  }
  if (facet->tricoplanar)
    qh_settempfree(qh, &vertices);
  *bestdistp= sqrt(bestdist);
  if (!bestvertex) {
      qh_fprintf(qh, qh->ferr, 6261, "qhull internal error (qh_nearvertex): did not find bestvertex for f%d p%d\n", facet->id, qh_pointid(qh, point));
      qh_errexit(qh, qh_ERRqhull, facet, NULL);
  }
  trace3((qh, qh->ferr, 3019, "qh_nearvertex: v%d dist %2.2g for f%d p%d\n",
        bestvertex->id, *bestdistp, facet->id, qh_pointid(qh, point))); /* bestvertex!=0 by QH2161 */
  return bestvertex;
} /* nearvertex */

/*---------------------------------

  qh_newhashtable(qh, newsize )
    returns size of qh.hash_table of at least newsize slots

  notes:
    assumes qh.hash_table is NULL
    qh_HASHfactor determines the number of extra slots
    size is not divisible by 2, 3, or 5
*/
int qh_newhashtable(qhT *qh, int newsize) {
  int size;

  size= ((newsize+1)*qh_HASHfactor) | 0x1;  /* odd number */
  while (True) {
    if (newsize<0 || size<0) {
        qh_fprintf(qh, qh->qhmem.ferr, 6236, "qhull error (qh_newhashtable): negative request (%d) or size (%d).  Did int overflow due to high-D?\n", newsize, size); /* WARN64 */
        qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
    }
    if ((size%3) && (size%5))
      break;
    size += 2;
    /* loop terminates because there is an infinite number of primes */
  }
  qh->hash_table= qh_setnew(qh, size);
  qh_setzero(qh, qh->hash_table, 0, size);
  return size;
} /* newhashtable */

/*---------------------------------

  qh_newvertex(qh, point )
    returns a new vertex for point
*/
vertexT *qh_newvertex(qhT *qh, pointT *point) {
  vertexT *vertex;

  zinc_(Ztotvertices);
  vertex= (vertexT *)qh_memalloc(qh, (int)sizeof(vertexT));
  memset((char *) vertex, (size_t)0, sizeof(vertexT));
  if (qh->vertex_id == UINT_MAX) {
    qh_memfree(qh, vertex, (int)sizeof(vertexT));
    qh_fprintf(qh, qh->ferr, 6159, "qhull error: 2^32 or more vertices.  vertexT.id field overflows.  Vertices would not be sorted correctly.\n");
    qh_errexit(qh, qh_ERRother, NULL, NULL);
  }
  if (qh->vertex_id == qh->tracevertex_id)
    qh->tracevertex= vertex;
  vertex->id= qh->vertex_id++;
  vertex->point= point;
  trace4((qh, qh->ferr, 4060, "qh_newvertex: vertex p%d(v%d) created\n", qh_pointid(qh, vertex->point),
          vertex->id));
  return(vertex);
} /* newvertex */

/*---------------------------------

  qh_nextfacet2d( facet, &nextvertex )
    return next facet and vertex for a 2d facet in qh_ORIENTclock order
    returns NULL on error

  notes:
    in qh_ORIENTclock order (default counter-clockwise)
    nextvertex is in between the two facets
    does not use qhT or qh_errexit [QhullFacet.cpp]

  design:
    see io_r.c/qh_printextremes_2d
*/
facetT *qh_nextfacet2d(facetT *facet, vertexT **nextvertexp) {
  facetT *nextfacet;

  if (facet->toporient ^ qh_ORIENTclock) {
    *nextvertexp= SETfirstt_(facet->vertices, vertexT);
    nextfacet= SETfirstt_(facet->neighbors, facetT);
  }else {
    *nextvertexp= SETsecondt_(facet->vertices, vertexT);
    nextfacet= SETsecondt_(facet->neighbors, facetT);
  }
  return nextfacet;
} /* nextfacet2d */

/*---------------------------------

  qh_nextridge3d( atridge, facet, &vertex )
    return next ridge and vertex for a 3d facet
    returns NULL on error
    [for QhullFacet::nextRidge3d] Does not call qh_errexit nor access qhT.

  notes:
    in qh_ORIENTclock order
    this is a O(n^2) implementation to trace all ridges
    be sure to stop on any 2nd visit
    same as QhullRidge::nextRidge3d
    does not use qhT or qh_errexit [QhullFacet.cpp]

  design:
    for each ridge
      exit if it is the ridge after atridge
*/
ridgeT *qh_nextridge3d(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 */

/*---------------------------------

  qh_opposite_vertex(qh, facetA, neighbor )
    return the opposite vertex in facetA to neighbor

*/
vertexT *qh_opposite_vertex(qhT *qh, facetT *facetA,  facetT *neighbor) {
    vertexT *opposite= NULL;
    facetT *facet;
    int facet_i, facet_n;

    if (facetA->simplicial) {
      FOREACHfacet_i_(qh, facetA->neighbors) {
        if (facet == neighbor) {
          opposite= SETelemt_(facetA->vertices, facet_i, vertexT);
          break;
        }
      }
    }
    if (!opposite) {
      qh_fprintf(qh, qh->ferr, 6396, "qhull internal error (qh_opposite_vertex): opposite vertex in facet f%d to neighbor f%d is not defined.  Either is facet is not simplicial or neighbor not found\n",
        facetA->id, neighbor->id);
      qh_errexit2(qh, qh_ERRqhull, facetA, neighbor);
    }
    return opposite;
} /* opposite_vertex */

/*---------------------------------

  qh_outcoplanar()
    move points from all facets' outsidesets to their coplanarsets

  notes:
    for post-processing under qh.NARROWhull

  design:
    for each facet
      for each outside point for facet
        partition point into coplanar set
*/
void qh_outcoplanar(qhT *qh /* facet_list */) {
  pointT *point, **pointp;
  facetT *facet;
  realT dist;

  trace1((qh, qh->ferr, 1033, "qh_outcoplanar: move outsideset to coplanarset for qh->NARROWhull\n"));
  FORALLfacets {
    FOREACHpoint_(facet->outsideset) {
      qh->num_outside--;
      if (qh->KEEPcoplanar || qh->KEEPnearinside) {
        qh_distplane(qh, point, facet, &dist);
        zinc_(Zpartition);
        qh_partitioncoplanar(qh, point, facet, &dist, qh->findbestnew);
      }
    }
    qh_setfree(qh, &facet->outsideset);
  }
} /* outcoplanar */

/*---------------------------------

  qh_point(qh, id )
    return point for a point id, or NULL if unknown

  alternative code:
    return((pointT *)((unsigned long)qh.first_point
           + (unsigned long)((id)*qh.normal_size)));
*/
pointT *qh_point(qhT *qh, int id) {

  if (id < 0)
    return NULL;
  if (id < qh->num_points)
    return qh->first_point + id * qh->hull_dim;
  id -= qh->num_points;
  if (id < qh_setsize(qh, qh->other_points))
    return SETelemt_(qh->other_points, id, pointT);
  return NULL;
} /* point */

/*---------------------------------

  qh_point_add(qh, set, point, elem )
    stores elem at set[point.id]

  returns:
    access function for qh_pointfacet and qh_pointvertex

  notes:
    checks point.id
*/
void qh_point_add(qhT *qh, setT *set, pointT *point, void *elem) {
  int id, size;

  SETreturnsize_(set, size);
  if ((id= qh_pointid(qh, point)) < 0)
    qh_fprintf(qh, qh->ferr, 7067, "qhull internal warning (point_add): unknown point %p id %d\n",
      point, id);
  else if (id >= size) {
    qh_fprintf(qh, qh->ferr, 6160, "qhull internal error (point_add): point p%d is out of bounds(%d)\n",
             id, size);
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }else
    SETelem_(set, id)= elem;
} /* point_add */


/*---------------------------------

  qh_pointfacet()
    return temporary set of facet for each point
    the set is indexed by point id
    at most one facet per point, arbitrary selection

  notes:
    each point is assigned to at most one of vertices, coplanarset, or outsideset
    unassigned points are interior points or 
    vertices assigned to one of its facets
    coplanarset assigned to the facet
    outside set assigned to the facet
    NULL if no facet for point (inside)
      includes qh.GOODpointp

  access:
    FOREACHfacet_i_(qh, facets) { ... }
    SETelem_(facets, i)

  design:
    for each facet
      add each vertex
      add each coplanar point
      add each outside point
*/
setT *qh_pointfacet(qhT *qh /* qh.facet_list */) {
  int numpoints= qh->num_points + qh_setsize(qh, qh->other_points);
  setT *facets;
  facetT *facet;
  vertexT *vertex, **vertexp;
  pointT *point, **pointp;

  facets= qh_settemp(qh, numpoints);
  qh_setzero(qh, facets, 0, numpoints);
  qh->vertex_visit++;
  FORALLfacets {
    FOREACHvertex_(facet->vertices) {
      if (vertex->visitid != qh->vertex_visit) {
        vertex->visitid= qh->vertex_visit;
        qh_point_add(qh, facets, vertex->point, facet);
      }
    }
    FOREACHpoint_(facet->coplanarset)
      qh_point_add(qh, facets, point, facet);
    FOREACHpoint_(facet->outsideset)
      qh_point_add(qh, facets, point, facet);
  }
  return facets;
} /* pointfacet */

/*---------------------------------

  qh_pointvertex(qh )
    return temporary set of vertices indexed by point id
    entry is NULL if no vertex for a point
      this will include qh.GOODpointp

  access:
    FOREACHvertex_i_(qh, vertices) { ... }
    SETelem_(vertices, i)
*/
setT *qh_pointvertex(qhT *qh /* qh.facet_list */) {
  int numpoints= qh->num_points + qh_setsize(qh, qh->other_points);
  setT *vertices;
  vertexT *vertex;

  vertices= qh_settemp(qh, numpoints);
  qh_setzero(qh, vertices, 0, numpoints);
  FORALLvertices
    qh_point_add(qh, vertices, vertex->point, vertex);
  return vertices;
} /* pointvertex */


/*---------------------------------

  qh_prependfacet(qh, facet, facetlist )
    prepend facet to the start of a facetlist

  returns:
    increments qh.numfacets
    updates facetlist, qh.facet_list, facet_next

  notes:
    be careful of prepending since it can lose a pointer.
      e.g., can lose _next by deleting and then prepending before _next
*/
void qh_prependfacet(qhT *qh, facetT *facet, facetT **facetlist) {
  facetT *prevfacet, *list;

  trace4((qh, qh->ferr, 4061, "qh_prependfacet: prepend f%d before f%d\n",
          facet->id, getid_(*facetlist)));
  if (!*facetlist)
    (*facetlist)= qh->facet_tail;
  list= *facetlist;
  prevfacet= list->previous;
  facet->previous= prevfacet;
  if (prevfacet)
    prevfacet->next= facet;
  list->previous= facet;
  facet->next= *facetlist;
  if (qh->facet_list == list)  /* this may change *facetlist */
    qh->facet_list= facet;
  if (qh->facet_next == list)
    qh->facet_next= facet;
  *facetlist= facet;
  qh->num_facets++;
} /* prependfacet */


/*---------------------------------

  qh_printhashtable(qh, fp )
    print hash table to fp

  notes:
    not in I/O to avoid bringing io_r.c in

  design:
    for each hash entry
      if defined
        if unmatched or will merge (NULL, qh_MERGEridge, qh_DUPLICATEridge)
          print entry and neighbors
*/
void qh_printhashtable(qhT *qh, FILE *fp) {
  facetT *facet, *neighbor;
  int id, facet_i, facet_n, neighbor_i= 0, neighbor_n= 0;
  vertexT *vertex, **vertexp;

  FOREACHfacet_i_(qh, qh->hash_table) {
    if (facet) {
      FOREACHneighbor_i_(qh, facet) {
        if (!neighbor || neighbor == qh_MERGEridge || neighbor == qh_DUPLICATEridge)
          break;
      }
      if (neighbor_i == neighbor_n)
        continue;
      qh_fprintf(qh, fp, 9283, "hash %d f%d ", facet_i, facet->id);
      FOREACHvertex_(facet->vertices)
        qh_fprintf(qh, fp, 9284, "v%d ", vertex->id);
      qh_fprintf(qh, fp, 9285, "\n neighbors:");
      FOREACHneighbor_i_(qh, facet) {
        if (neighbor == qh_MERGEridge)
          id= -3;
        else if (neighbor == qh_DUPLICATEridge)
          id= -2;
        else
          id= getid_(neighbor);
        qh_fprintf(qh, fp, 9286, " %d", id);
      }
      qh_fprintf(qh, fp, 9287, "\n");
    }
  }
} /* printhashtable */

/*---------------------------------

  qh_printlists(qh)
    print out facet and vertex lists for debugging (without 'f/v' tags)

  notes:
    not in I/O to avoid bringing io_r.c in
*/
void qh_printlists(qhT *qh) {
  facetT *facet;
  vertexT *vertex;
  int count= 0;

  qh_fprintf(qh, qh->ferr, 3062, "qh_printlists: max_outside %2.2g all facets:", qh->max_outside);
  FORALLfacets{
    if (++count % 100 == 0)
      qh_fprintf(qh, qh->ferr, 8109, "\n     ");
    qh_fprintf(qh, qh->ferr, 8110, " %d", facet->id);
  }
    qh_fprintf(qh, qh->ferr, 8111, "\n  qh.visible_list f%d, newfacet_list f%d, facet_next f%d for qh_addpoint\n  qh.newvertex_list v%d all vertices:",
      getid_(qh->visible_list), getid_(qh->newfacet_list), getid_(qh->facet_next), getid_(qh->newvertex_list));
  count= 0;
  FORALLvertices{
    if (++count % 100 == 0)
      qh_fprintf(qh, qh->ferr, 8112, "\n     ");
    qh_fprintf(qh, qh->ferr, 8113, " %d", vertex->id);
  }
  qh_fprintf(qh, qh->ferr, 8114, "\n");
} /* printlists */

/*---------------------------------

  qh_replacefacetvertex(qh, facet, oldvertex, newvertex )
    replace oldvertex with newvertex in f.vertices
    vertices are inverse sorted by vertex->id

  returns:
    toporient is flipped if an odd parity, position change

  notes:
    for simplicial facets in qh_rename_adjacentvertex
    see qh_addfacetvertex
*/
void qh_replacefacetvertex(qhT *qh, facetT *facet, vertexT *oldvertex, vertexT *newvertex) {
  vertexT *vertex;
  facetT *neighbor;
  int vertex_i, vertex_n= 0;
  int old_i= -1, new_i= -1;

  trace3((qh, qh->ferr, 3038, "qh_replacefacetvertex: replace v%d with v%d in f%d\n", oldvertex->id, newvertex->id, facet->id));
  if (!facet->simplicial) {
    qh_fprintf(qh, qh->ferr, 6283, "qhull internal error (qh_replacefacetvertex): f%d is not simplicial\n", facet->id);
    qh_errexit(qh, qh_ERRqhull, facet, NULL);
  }
  FOREACHvertex_i_(qh, facet->vertices) {
    if (new_i == -1 && vertex->id < newvertex->id) {
      new_i= vertex_i;
    }else if (vertex->id == newvertex->id) {
      qh_fprintf(qh, qh->ferr, 6281, "qhull internal error (qh_replacefacetvertex): f%d already contains new v%d\n", facet->id, newvertex->id);
      qh_errexit(qh, qh_ERRqhull, facet, NULL);
    }
    if (vertex->id == oldvertex->id) {
      old_i= vertex_i;
    }
  }
  if (old_i == -1) {
    qh_fprintf(qh, qh->ferr, 6282, "qhull internal error (qh_replacefacetvertex): f%d does not contain old v%d\n", facet->id, oldvertex->id);
    qh_errexit(qh, qh_ERRqhull, facet, NULL);
  }
  if (new_i == -1) {
    new_i= vertex_n;
  }
  if (old_i < new_i)
    new_i--;
  if ((old_i & 0x1) != (new_i & 0x1))
    facet->toporient ^= 1;
  qh_setdelnthsorted(qh, facet->vertices, old_i);
  qh_setaddnth(qh, &facet->vertices, new_i, newvertex);
  neighbor= SETelemt_(facet->neighbors, old_i, facetT);
  qh_setdelnthsorted(qh, facet->neighbors, old_i);
  qh_setaddnth(qh, &facet->neighbors, new_i, neighbor);
} /* replacefacetvertex */

/*---------------------------------

  qh_resetlists(qh, stats, qh_RESETvisible )
    reset newvertex_list, newfacet_list, visible_list, NEWfacets, NEWtentative
    if stats,
      maintains statistics
    if resetVisible, 
      visible_list is restored to facet_list
      otherwise, f.visible/f.replace is retained

  returns:
    newvertex_list, newfacet_list, visible_list are NULL

  notes:
    To delete visible facets, call qh_deletevisible before qh_resetlists
*/
void qh_resetlists(qhT *qh, boolT stats, boolT resetVisible /* qh.newvertex_list newfacet_list visible_list */) {
  vertexT *vertex;
  facetT *newfacet, *visible;
  int totnew=0, totver=0;

  trace2((qh, qh->ferr, 2066, "qh_resetlists: reset newvertex_list v%d, newfacet_list f%d, visible_list f%d, facet_list f%d next f%d vertex_list v%d -- NEWfacets? %d, NEWtentative? %d, stats? %d\n",
    getid_(qh->newvertex_list), getid_(qh->newfacet_list), getid_(qh->visible_list), getid_(qh->facet_list), getid_(qh->facet_next), getid_(qh->vertex_list), qh->NEWfacets, qh->NEWtentative, stats));
  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->newfacet= False;
  qh->newvertex_list= NULL;
  qh->first_newfacet= 0;
  FORALLnew_facets {
    newfacet->newfacet= False;
    newfacet->dupridge= False;
  }
  qh->newfacet_list= NULL;
  if (resetVisible) {
    FORALLvisible_facets {
      visible->f.replace= NULL;
      visible->visible= False;
    }
    qh->num_visible= 0;
  }
  qh->visible_list= NULL; 
  qh->NEWfacets= False;
  qh->NEWtentative= False;
} /* resetlists */

/*---------------------------------

  qh_setvoronoi_all(qh)
    compute Voronoi centers for all facets
    includes upperDelaunay facets if qh.UPPERdelaunay ('Qu')

  returns:
    facet->center is the Voronoi center

  notes:
    unused/untested code: please email bradb@shore.net if this works ok for you

  use:
    FORALLvertices {...} to locate the vertex for a point.
    FOREACHneighbor_(vertex) {...} to visit the Voronoi centers for a Voronoi cell.
*/
void qh_setvoronoi_all(qhT *qh) {
  facetT *facet;

  qh_clearcenters(qh, qh_ASvoronoi);
  qh_vertexneighbors(qh);

  FORALLfacets {
    if (!facet->normal || !facet->upperdelaunay || qh->UPPERdelaunay) {
      if (!facet->center)
        facet->center= qh_facetcenter(qh, facet->vertices);
    }
  }
} /* setvoronoi_all */

#ifndef qh_NOmerge
/*---------------------------------

  qh_triangulate()
    triangulate non-simplicial facets on qh.facet_list,
    if qh->VORONOI, sets Voronoi centers of non-simplicial facets
    nop if hasTriangulation

  returns:
    all facets simplicial
    each tricoplanar facet has ->f.triowner == owner of ->center,normal,etc.
    resets qh.newfacet_list and visible_list

  notes:
    called by qh_prepare_output and user_eg2_r.c
    call after qh_check_output since may switch to Voronoi centers, and qh_checkconvex skips f.tricoplanar facets
    Output may overwrite ->f.triowner with ->f.area
    while running, 'triangulated_facet_list' is a list of
       one non-simplicial facet followed by its 'f.tricoplanar' triangulated facets
    See qh_buildcone
*/
void qh_triangulate(qhT *qh /* qh.facet_list */) {
  facetT *facet, *nextfacet, *owner;
  facetT *neighbor, *visible= NULL, *facet1, *facet2, *triangulated_facet_list= NULL;
  facetT *orig_neighbor= NULL, *otherfacet;
  vertexT *triangulated_vertex_list= NULL;
  mergeT *merge;
  mergeType mergetype;
  int neighbor_i, neighbor_n;
  boolT onlygood= qh->ONLYgood;

  if (qh->hasTriangulation)
      return;
  trace1((qh, qh->ferr, 1034, "qh_triangulate: triangulate non-simplicial facets\n"));
  if (qh->hull_dim == 2)
    return;
  if (qh->VORONOI) {  /* otherwise lose Voronoi centers [could rebuild vertex set from tricoplanar] */
    qh_clearcenters(qh, qh_ASvoronoi);
    qh_vertexneighbors(qh);
  }
  qh->ONLYgood= False; /* for makenew_nonsimplicial */
  qh->visit_id++;
  qh_initmergesets(qh /* qh.facet_mergeset,degen_mergeset,vertex_mergeset */);
  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 (!triangulated_facet_list)
      triangulated_facet_list= facet;  /* will be first triangulated facet */
    qh_triangulate_facet(qh, facet, &triangulated_vertex_list); /* qh_resetlists ! */
  }
  /* qh_checkpolygon invalid due to f.visible without qh.visible_list */
  trace2((qh, qh->ferr, 2047, "qh_triangulate: delete null facets from facetlist f%d.  A null facet has the same first (apex) and second vertices\n", getid_(triangulated_facet_list)));
  for (facet=triangulated_facet_list; facet && facet->next; facet= nextfacet) {
    nextfacet= facet->next;
    if (facet->visible)
      continue;
    if (facet->ridges) {
      if (qh_setsize(qh, facet->ridges) > 0) {
        qh_fprintf(qh, qh->ferr, 6161, "qhull internal error (qh_triangulate): ridges still defined for f%d\n", facet->id);
        qh_errexit(qh, qh_ERRqhull, facet, NULL);
      }
      qh_setfree(qh, &facet->ridges);
    }
    if (SETfirst_(facet->vertices) == SETsecond_(facet->vertices)) {
      zinc_(Ztrinull);
      qh_triangulate_null(qh, facet); /* will delete facet */
    }
  }
  trace2((qh, qh->ferr, 2048, "qh_triangulate: delete %d or more mirrored facets.  Mirrored facets have the same vertices due to a null facet\n", qh_setsize(qh, qh->degen_mergeset)));
  qh->visible_list= qh->facet_tail;
  while ((merge= (mergeT *)qh_setdellast(qh->degen_mergeset))) {
    facet1= merge->facet1;
    facet2= merge->facet2;
    mergetype= merge->mergetype;
    qh_memfree(qh, merge, (int)sizeof(mergeT));
    if (mergetype == MRGmirror) {
      zinc_(Ztrimirror);
      qh_triangulate_mirror(qh, facet1, facet2);  /* will delete both facets */
    }
  }
  qh_freemergesets(qh);
  trace2((qh, qh->ferr, 2049, "qh_triangulate: update neighbor lists for vertices from v%d\n", getid_(triangulated_vertex_list)));
  qh->newvertex_list= triangulated_vertex_list;  /* all vertices of triangulated facets */
  qh->visible_list= NULL;
  qh_update_vertexneighbors(qh /* qh.newvertex_list, empty newfacet_list and visible_list */);
  qh_resetlists(qh, False, !qh_RESETvisible /* qh.newvertex_list, empty newfacet_list and visible_list */);

  trace2((qh, qh->ferr, 2050, "qh_triangulate: identify degenerate tricoplanar facets from f%d\n", getid_(triangulated_facet_list)));
  trace2((qh, qh->ferr, 2051, "qh_triangulate: and replace facet->f.triowner with tricoplanar facets that own center, normal, etc.\n"));
  FORALLfacet_(triangulated_facet_list) {
    if (facet->tricoplanar && !facet->visible) {
      FOREACHneighbor_i_(qh, facet) {
        if (neighbor_i == 0) {  /* first iteration */
          if (neighbor->tricoplanar)
            orig_neighbor= neighbor->f.triowner;
          else
            orig_neighbor= neighbor;
        }else {
          if (neighbor->tricoplanar)
            otherfacet= neighbor->f.triowner;
          else
            otherfacet= neighbor;
          if (orig_neighbor == otherfacet) {
            zinc_(Ztridegen);
            facet->degenerate= True;
            break;
          }
        }
      }
    }
  }
  if (qh->IStracing >= 4)
    qh_printlists(qh);
  trace2((qh, qh->ferr, 2052, "qh_triangulate: delete visible facets -- non-simplicial, null, and mirrored facets\n"));
  owner= NULL;
  visible= NULL;
  for (facet=triangulated_facet_list; facet && facet->next; facet= nextfacet) { 
    /* deleting facets, triangulated_facet_list is no longer valid */
    nextfacet= facet->next;
    if (facet->visible) {
      if (facet->tricoplanar) { /* a null or mirrored facet */
        qh_delfacet(qh, facet);
        qh->num_visible--;
      }else {  /* a non-simplicial facet followed by its tricoplanars */
        if (visible && !owner) {
          /*  RBOX 200 s D5 t1001471447 | QHULL Qt C-0.01 Qx Qc Tv Qt -- f4483 had 6 vertices/neighbors and 8 ridges */
          trace2((qh, qh->ferr, 2053, "qh_triangulate: delete f%d.  All tricoplanar facets degenerate for non-simplicial facet\n",
                       visible->id));
          qh_delfacet(qh, visible);
          qh->num_visible--;
        }
        visible= facet;
        owner= NULL;
      }
    }else if (facet->tricoplanar) {
      if (facet->f.triowner != visible || visible==NULL) {
        qh_fprintf(qh, qh->ferr, 6162, "qhull internal error (qh_triangulate): tricoplanar facet f%d not owned by its visible, non-simplicial facet f%d\n", facet->id, getid_(visible));
        qh_errexit2(qh, qh_ERRqhull, facet, visible);
      }
      if (owner)
        facet->f.triowner= owner;
      else if (!facet->degenerate) {
        owner= facet;
        nextfacet= visible->next; /* rescan tricoplanar facets with owner, visible!=0 by QH6162 */
        facet->keepcentrum= True;  /* one facet owns ->normal, etc. */
        facet->coplanarset= visible->coplanarset;
        facet->outsideset= visible->outsideset;
        visible->coplanarset= NULL;
        visible->outsideset= NULL;
        if (!qh->TRInormals) { /* center and normal copied to tricoplanar facets */
          visible->center= NULL;
          visible->normal= NULL;
        }
        qh_delfacet(qh, visible);
        qh->num_visible--;
      }
    }
    facet->degenerate= False; /* reset f.degenerate set by qh_triangulate*/
  }
  if (visible && !owner) {
    trace2((qh, qh->ferr, 2054, "qh_triangulate: all tricoplanar facets degenerate for last non-simplicial facet f%d\n",
                 visible->id));
    qh_delfacet(qh, visible);
    qh->num_visible--;
  }
  qh->ONLYgood= onlygood; /* restore value */
  if (qh->CHECKfrequently)
    qh_checkpolygon(qh, qh->facet_list);
  qh->hasTriangulation= True;
} /* triangulate */


/*---------------------------------

  qh_triangulate_facet(qh, facetA, &firstVertex )
    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:
      only called by qh_triangulate
      qh_makenew_nonsimplicial uses neighbor->seen for the same
      if qh.TRInormals, newfacet->normal will need qh_free
        if qh.TRInormals and qh_AScentrum, newfacet->center will need qh_free
        keepcentrum is also set on Zwidefacet in qh_mergefacet
        freed by qh_clearcenters

  see also:
      qh_addpoint() -- add a point
      qh_makenewfacets() -- construct a cone of facets for a new vertex

  design:
      if qh_ASvoronoi,
         compute Voronoi center (facet->center)
      select first vertex (highest ID to preserve ID ordering of ->vertices)
      triangulate from vertex to ridges
      copy facet->center, normal, offset
      update vertex neighbors
*/
void qh_triangulate_facet(qhT *qh, facetT *facetA, vertexT **first_vertex) {
  facetT *newfacet;
  facetT *neighbor, **neighborp;
  vertexT *apex;
  int numnew=0;

  trace3((qh, qh->ferr, 3020, "qh_triangulate_facet: triangulate facet f%d\n", facetA->id));

  qh->first_newfacet= qh->facet_id;
  if (qh->IStracing >= 4)
    qh_printfacet(qh, qh->ferr, facetA);
  FOREACHneighbor_(facetA) {
    neighbor->seen= False;
    neighbor->coplanarhorizon= False;
  }
  if (qh->CENTERtype == qh_ASvoronoi && !facetA->center  /* matches upperdelaunay in qh_setfacetplane() */
  && fabs_(facetA->normal[qh->hull_dim -1]) >= qh->ANGLEround * qh_ZEROdelaunay) {
    facetA->center= qh_facetcenter(qh, facetA->vertices);
  }
  qh->visible_list= qh->newfacet_list= qh->facet_tail;
  facetA->visitid= qh->visit_id;
  apex= SETfirstt_(facetA->vertices, vertexT);
  qh_makenew_nonsimplicial(qh, facetA, apex, &numnew);
  qh_willdelete(qh, facetA, NULL);
  FORALLnew_facets {
    newfacet->tricoplanar= True;
    newfacet->f.trivisible= facetA;
    newfacet->degenerate= False;
    newfacet->upperdelaunay= facetA->upperdelaunay;
    newfacet->good= facetA->good;
    if (qh->TRInormals) { /* 'Q11' triangulate duplicates ->normal and ->center */
      newfacet->keepcentrum= True;
      if(facetA->normal){
        newfacet->normal= (double *)qh_memalloc(qh, qh->normal_size);
        memcpy((char *)newfacet->normal, facetA->normal, (size_t)qh->normal_size);
      }
      if (qh->CENTERtype == qh_AScentrum)
        newfacet->center= qh_getcentrum(qh, newfacet);
      else if (qh->CENTERtype == qh_ASvoronoi && facetA->center){
        newfacet->center= (double *)qh_memalloc(qh, qh->center_size);
        memcpy((char *)newfacet->center, facetA->center, (size_t)qh->center_size);
      }
    }else {
      newfacet->keepcentrum= False;
      /* one facet will have keepcentrum=True at end of qh_triangulate */
      newfacet->normal= facetA->normal;
      newfacet->center= facetA->center;
    }
    newfacet->offset= facetA->offset;
#if qh_MAXoutside
    newfacet->maxoutside= facetA->maxoutside;
#endif
  }
  qh_matchnewfacets(qh /* qh.newfacet_list */); /* ignore returned value, maxdupdist */ 
  zinc_(Ztricoplanar);
  zadd_(Ztricoplanartot, numnew);
  zmax_(Ztricoplanarmax, numnew);
  if (!(*first_vertex))
    (*first_vertex)= qh->newvertex_list;
  qh->newvertex_list= NULL;
  qh->visible_list= NULL;
  /* only update v.neighbors for qh.newfacet_list.  qh.visible_list and qh.newvertex_list are NULL */
  qh_update_vertexneighbors(qh /* qh.newfacet_list */);
  qh_resetlists(qh, False, !qh_RESETvisible /* qh.newfacet_list */);
} /* triangulate_facet */

/*---------------------------------

  qh_triangulate_link(qh, oldfacetA, facetA, oldfacetB, facetB)
    relink facetA to facetB via null oldfacetA or mirrored oldfacetA and oldfacetB
  returns:
    if neighbors are already linked, will merge as MRGmirror (qh.degen_mergeset, 4-d and up)
*/
void qh_triangulate_link(qhT *qh, facetT *oldfacetA, facetT *facetA, facetT *oldfacetB, facetT *facetB) {
  int errmirror= False;

  if (oldfacetA == oldfacetB) {
    trace3((qh, qh->ferr, 3052, "qh_triangulate_link: relink neighbors f%d and f%d of null facet f%d\n",
      facetA->id, facetB->id, oldfacetA->id));
  }else {
    trace3((qh, qh->ferr, 3021, "qh_triangulate_link: relink neighbors f%d and f%d of mirrored facets f%d and f%d\n",
      facetA->id, facetB->id, oldfacetA->id, oldfacetB->id));
  }
  if (qh_setin(facetA->neighbors, facetB)) {
    if (!qh_setin(facetB->neighbors, facetA))
      errmirror= True;
    else if (!facetA->redundant || !facetB->redundant || !qh_hasmerge(qh->degen_mergeset, MRGmirror, facetA, facetB))
      qh_appendmergeset(qh, facetA, facetB, MRGmirror, 0.0, 1.0);
  }else if (qh_setin(facetB->neighbors, facetA))
    errmirror= True;
  if (errmirror) {
    qh_fprintf(qh, qh->ferr, 6163, "qhull internal error (qh_triangulate_link): neighbors f%d and f%d do not match for null facet or mirrored facets f%d and f%d\n",
       facetA->id, facetB->id, oldfacetA->id, oldfacetB->id);
    qh_errexit2(qh, qh_ERRqhull, facetA, facetB);
  }
  qh_setreplace(qh, facetB->neighbors, oldfacetB, facetA);
  qh_setreplace(qh, facetA->neighbors, oldfacetA, facetB);
} /* triangulate_link */

/*---------------------------------

  qh_triangulate_mirror(qh, facetA, facetB)
    delete two mirrored facets identified by qh_triangulate_null() and itself
      a mirrored facet shares the same vertices of a logical ridge
  design:
    since a null facet duplicates the first two vertices, the opposing neighbors absorb the null facet
    if they are already neighbors, the opposing neighbors become MRGmirror facets
*/
void qh_triangulate_mirror(qhT *qh, facetT *facetA, facetT *facetB) {
  facetT *neighbor, *neighborB;
  int neighbor_i, neighbor_n;

  trace3((qh, qh->ferr, 3022, "qh_triangulate_mirror: delete mirrored facets f%d and f%d and link their neighbors\n",
         facetA->id, facetB->id));
  FOREACHneighbor_i_(qh, facetA) {
    neighborB= SETelemt_(facetB->neighbors, neighbor_i, facetT);
    if (neighbor == facetB && neighborB == facetA)
      continue; /* occurs twice */
    else if (neighbor->redundant && neighborB->redundant) { /* also mirrored facets (D5+) */
      if (qh_hasmerge(qh->degen_mergeset, MRGmirror, neighbor, neighborB))
        continue;
    }
    if (neighbor->visible && neighborB->visible) /* previously deleted as mirrored facets */
      continue;
    qh_triangulate_link(qh, facetA, neighbor, facetB, neighborB);
  }
  qh_willdelete(qh, facetA, NULL);
  qh_willdelete(qh, facetB, NULL);
} /* triangulate_mirror */

/*---------------------------------

  qh_triangulate_null(qh, facetA)
    remove null facetA from qh_triangulate_facet()
      a null facet has vertex #1 (apex) == vertex #2
  returns:
    adds facetA to ->visible for deletion after qh_update_vertexneighbors
    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 will be merged (MRGmirror)
*/
void qh_triangulate_null(qhT *qh, facetT *facetA) {
  facetT *neighbor, *otherfacet;

  trace3((qh, qh->ferr, 3023, "qh_triangulate_null: delete null facet f%d\n", facetA->id));
  neighbor= SETfirstt_(facetA->neighbors, facetT);
  otherfacet= SETsecondt_(facetA->neighbors, facetT);
  qh_triangulate_link(qh, facetA, neighbor, facetA, otherfacet);
  qh_willdelete(qh, facetA, NULL);
} /* triangulate_null */

#else /* qh_NOmerge */
void qh_triangulate(qhT *qh) {
  QHULL_UNUSED(qh)
}
#endif /* qh_NOmerge */

/*---------------------------------

  qh_vertexintersect(qh, verticesA, verticesB )
    intersects two vertex sets (inverse id ordered)
    vertexsetA is a temporary set at the top of qh->qhmem.tempstack

  returns:
    replaces vertexsetA with the intersection

  notes:
    only called by qh_neighbor_intersections
    if !qh.QHULLfinished, non-simplicial facets may have f.vertices with extraneous vertices
      cleaned by qh_remove_extravertices in qh_reduce_vertices
    could optimize by overwriting vertexsetA
*/
void qh_vertexintersect(qhT *qh, setT **vertexsetA, setT *vertexsetB) {
  setT *intersection;

  intersection= qh_vertexintersect_new(qh, *vertexsetA, vertexsetB);
  qh_settempfree(qh, vertexsetA);
  *vertexsetA= intersection;
  qh_settemppush(qh, intersection);
} /* vertexintersect */

/*---------------------------------

  qh_vertexintersect_new(qh, verticesA, verticesB )
    intersects two vertex sets (inverse id ordered)

  returns:
    a new set

  notes:
    called by qh_checkfacet, qh_vertexintersect, qh_rename_sharedvertex, qh_findbest_pinchedvertex, qh_neighbor_intersections
    if !qh.QHULLfinished, non-simplicial facets may have f.vertices with extraneous vertices
       cleaned by qh_remove_extravertices in qh_reduce_vertices
*/
setT *qh_vertexintersect_new(qhT *qh, setT *vertexsetA, setT *vertexsetB) {
  setT *intersection= qh_setnew(qh, qh->hull_dim - 1);
  vertexT **vertexA= SETaddr_(vertexsetA, vertexT);
  vertexT **vertexB= SETaddr_(vertexsetB, vertexT);

  while (*vertexA && *vertexB) {
    if (*vertexA  == *vertexB) {
      qh_setappend(qh, &intersection, *vertexA);
      vertexA++; vertexB++;
    }else {
      if ((*vertexA)->id > (*vertexB)->id)
        vertexA++;
      else
        vertexB++;
    }
  }
  return intersection;
} /* vertexintersect_new */

/*---------------------------------

  qh_vertexneighbors(qh)
    for each vertex in qh.facet_list,
      determine its neighboring facets

  returns:
    sets qh.VERTEXneighbors
      nop if qh.VERTEXneighbors already set
      qh_addpoint() will maintain them

  notes:
    assumes all vertex->neighbors are NULL

  design:
    for each facet
      for each vertex
        append facet to vertex->neighbors
*/
void qh_vertexneighbors(qhT *qh /* qh.facet_list */) {
  facetT *facet;
  vertexT *vertex, **vertexp;

  if (qh->VERTEXneighbors)
    return;
  trace1((qh, qh->ferr, 1035, "qh_vertexneighbors: determining neighboring facets for each vertex\n"));
  qh->vertex_visit++;
  FORALLfacets {
    if (facet->visible)
      continue;
    FOREACHvertex_(facet->vertices) {
      if (vertex->visitid != qh->vertex_visit) {
        vertex->visitid= qh->vertex_visit;
        vertex->neighbors= qh_setnew(qh, qh->hull_dim);
      }
      qh_setappend(qh, &vertex->neighbors, facet);
    }
  }
  qh->VERTEXneighbors= True;
} /* vertexneighbors */

/*---------------------------------

  qh_vertexsubset( 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 */
qhull-2020.2/src/libqhull_r/poly_r.c0000644060175106010010000015042213661631132015570 0ustar  bbarber/*
  ---------------------------------

   poly_r.c
   implements polygons and simplices

   see qh-poly_r.htm, poly_r.h and libqhull_r.h

   infrequent code is in poly2_r.c
   (all but top 50 and their callers 12/3/95)

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull_r/poly_r.c#8 $$Change: 2953 $
   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
*/

#include "qhull_ra.h"

/*======== functions in alphabetical order ==========*/

/*---------------------------------

  qh_appendfacet(qh, facet )
    appends facet to end of qh.facet_list,

  returns:
    updates qh.newfacet_list, facet_next, facet_list
    increments qh.numfacets

  notes:
    assumes qh.facet_list/facet_tail is defined (createsimplex)

  see:
    qh_removefacet()

*/
void qh_appendfacet(qhT *qh, facetT *facet) {
  facetT *tail= qh->facet_tail;

  if (tail == qh->newfacet_list) {
    qh->newfacet_list= facet;
    if (tail == qh->visible_list) /* visible_list is at or before newfacet_list */
      qh->visible_list= facet;
  }
  if (tail == qh->facet_next)
    qh->facet_next= facet;
  facet->previous= tail->previous;
  facet->next= tail;
  if (tail->previous)
    tail->previous->next= facet;
  else
    qh->facet_list= facet;
  tail->previous= facet;
  qh->num_facets++;
  trace4((qh, qh->ferr, 4044, "qh_appendfacet: append f%d to facet_list\n", facet->id));
} /* appendfacet */


/*---------------------------------

  qh_appendvertex(qh, vertex )
    appends vertex to end of qh.vertex_list,

  returns:
    sets vertex->newfacet
    updates qh.vertex_list, newvertex_list
    increments qh.num_vertices

  notes:
    assumes qh.vertex_list/vertex_tail is defined (createsimplex)

*/
void qh_appendvertex(qhT *qh, vertexT *vertex) {
  vertexT *tail= qh->vertex_tail;

  if (tail == qh->newvertex_list)
    qh->newvertex_list= vertex;
  vertex->newfacet= True;
  vertex->previous= tail->previous;
  vertex->next= tail;
  if (tail->previous)
    tail->previous->next= vertex;
  else
    qh->vertex_list= vertex;
  tail->previous= vertex;
  qh->num_vertices++;
  trace4((qh, qh->ferr, 4045, "qh_appendvertex: append v%d to qh.newvertex_list and set v.newfacet\n", vertex->id));
} /* appendvertex */


/*---------------------------------

  qh_attachnewfacets(qh)
    attach horizon facets to new facets in qh.newfacet_list
    newfacets have neighbor and ridge links to horizon but not vice versa

  returns:
    clears qh.NEWtentative
    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)

  notes:
    used for qh.NEWtentative, otherwise see qh_makenew_nonsimplicial and qh_makenew_simplicial
    qh_delridge_merge not needed (as tested by qh_checkdelridge)

  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 is non-simplicial
          for all visible neighbors of the horizon facet
            link visible neighbor to new facet
            delete visible neighbor from horizon facet
          append new facet to horizon's neighbors
          the first ridge of the new facet is the horizon ridge
          link the new facet into the horizon ridge
*/
void qh_attachnewfacets(qhT *qh /* qh.visible_list, qh.newfacet_list */) {
  facetT *newfacet= NULL, *neighbor, **neighborp, *horizon, *visible;
  ridgeT *ridge, **ridgep;

  trace3((qh, qh->ferr, 3012, "qh_attachnewfacets: delete interior ridges\n"));
  if (qh->CHECKfrequently) {
    qh_checkdelridge(qh);
  }
  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_delridge(qh, ridge); /* delete on second visit */
        }
      }
    }
  }
  trace1((qh, qh->ferr, 1017, "qh_attachnewfacets: attach horizon facets to new facets\n"));
  FORALLnew_facets {
    horizon= SETfirstt_(newfacet->neighbors, facetT);
    if (horizon->simplicial) {
      visible= NULL;
      FOREACHneighbor_(horizon) {   /* may have more than one horizon ridge */
        if (neighbor->visible) {
          if (visible) {
            if (qh_setequal_skip(newfacet->vertices, 0, horizon->vertices,
                                  SETindex_(horizon->neighbors, neighbor))) {
              visible= neighbor;
              break;
            }
          }else
            visible= neighbor;
        }
      }
      if (visible) {
        visible->f.replace= newfacet;
        qh_setreplace(qh, horizon->neighbors, visible, newfacet);
      }else {
        qh_fprintf(qh, qh->ferr, 6102, "qhull internal error (qh_attachnewfacets): could not find visible facet for horizon f%d of newfacet f%d\n",
                 horizon->id, newfacet->id);
        qh_errexit2(qh, qh_ERRqhull, horizon, newfacet);
      }
    }else { /* non-simplicial, with a ridge for newfacet */
      FOREACHneighbor_(horizon) {    /* may hold for many new facets */
        if (neighbor->visible) {
          neighbor->f.replace= newfacet;
          qh_setdelnth(qh, horizon->neighbors, SETindex_(horizon->neighbors, neighbor));
          neighborp--; /* repeat */
        }
      }
      qh_setappend(qh, &horizon->neighbors, newfacet);
      ridge= SETfirstt_(newfacet->ridges, ridgeT);
      if (ridge->top == horizon) {
        ridge->bottom= newfacet;
        ridge->simplicialbot= True;
      }else {
        ridge->top= newfacet;
        ridge->simplicialtop= True;
      }
    }
  } /* newfacets */
  trace4((qh, qh->ferr, 4094, "qh_attachnewfacets: clear f.ridges and f.neighbors for visible facets, may become invalid before qh_deletevisible\n"));
  FORALLvisible_facets {
    if (visible->ridges)
      SETfirst_(visible->ridges)= NULL; 
    SETfirst_(visible->neighbors)= NULL;
  }
  qh->NEWtentative= False;
  qh->NEWfacets= True;
  if (qh->PRINTstatistics) {
    FORALLvisible_facets {
      if (!visible->f.replace)
        zinc_(Zinsidevisible);
    }
  }
} /* attachnewfacets */

/*---------------------------------

  qh_checkflipped(qh, facet, dist, allerror )
    checks facet orientation to interior point

    if allerror set,
      tests against -qh.DISTround
    else
      tests against 0.0 since tested against -qh.DISTround before

  returns:
    False if it flipped orientation (sets facet->flipped)
    distance if non-NULL

  notes:
    called by qh_setfacetplane, qh_initialhull, and qh_checkflipped_all
*/
boolT qh_checkflipped(qhT *qh, facetT *facet, realT *distp, boolT allerror) {
  realT dist;

  if (facet->flipped && !distp)
    return False;
  zzinc_(Zdistcheck);
  qh_distplane(qh, qh->interior_point, facet, &dist);
  if (distp)
    *distp= dist;
  if ((allerror && dist >= -qh->DISTround) || (!allerror && dist > 0.0)) {
    facet->flipped= True;
    trace0((qh, qh->ferr, 19, "qh_checkflipped: facet f%d flipped, allerror? %d, distance= %6.12g during p%d\n",
              facet->id, allerror, dist, qh->furthest_id));
    if (qh->num_facets > qh->hull_dim+1) { /* qh_initialhull reverses orientation if !qh_checkflipped */
      zzinc_(Zflippedfacets);
      qh_joggle_restart(qh, "flipped facet");
    }
    return False;
  }
  return True;
} /* checkflipped */

/*---------------------------------

  qh_delfacet(qh, facet )
    removes facet from facet_list and frees up its memory

  notes:
    assumes vertices and ridges already freed or referenced elsewhere
*/
void qh_delfacet(qhT *qh, facetT *facet) {
  void **freelistp; /* used if !qh_NOmem by qh_memfree_() */

  trace3((qh, qh->ferr, 3057, "qh_delfacet: delete f%d\n", facet->id));
  if (qh->CHECKfrequently || qh->VERIFYoutput) { 
    if (!qh->NOerrexit) {
      qh_checkdelfacet(qh, facet, qh->facet_mergeset);
      qh_checkdelfacet(qh, facet, qh->degen_mergeset);
      qh_checkdelfacet(qh, facet, qh->vertex_mergeset);
    }
  }
  if (facet == qh->tracefacet)
    qh->tracefacet= NULL;
  if (facet == qh->GOODclosest)
    qh->GOODclosest= NULL;
  qh_removefacet(qh, facet);
  if (!facet->tricoplanar || facet->keepcentrum) {
    qh_memfree_(qh, facet->normal, qh->normal_size, freelistp);
    if (qh->CENTERtype == qh_ASvoronoi) {   /* braces for macro calls */
      qh_memfree_(qh, facet->center, qh->center_size, freelistp);
    }else /* AScentrum */ {
      qh_memfree_(qh, facet->center, qh->normal_size, freelistp);
    }
  }
  qh_setfree(qh, &(facet->neighbors));
  if (facet->ridges)
    qh_setfree(qh, &(facet->ridges));
  qh_setfree(qh, &(facet->vertices));
  if (facet->outsideset)
    qh_setfree(qh, &(facet->outsideset));
  if (facet->coplanarset)
    qh_setfree(qh, &(facet->coplanarset));
  qh_memfree_(qh, facet, (int)sizeof(facetT), freelistp);
} /* delfacet */


/*---------------------------------

  qh_deletevisible()
    delete visible facets and vertices

  returns:
    deletes each facet and removes from facetlist
    deletes vertices on qh.del_vertices and ridges in qh.del_ridges
    at exit, qh.visible_list empty (== qh.newfacet_list)

  notes:
    called by qh_all_vertexmerges, qh_addpoint, and qh_qhull
    ridges already deleted or moved elsewhere
    deleted vertices on qh.del_vertices
    horizon facets do not reference facets on qh.visible_list
    new facets in qh.newfacet_list
    uses   qh.visit_id;
*/
void qh_deletevisible(qhT *qh /* qh.visible_list */) {
  facetT *visible, *nextfacet;
  vertexT *vertex, **vertexp;
  int numvisible= 0, numdel= qh_setsize(qh, qh->del_vertices);

  trace1((qh, qh->ferr, 1018, "qh_deletevisible: delete %d visible facets and %d vertices\n",
         qh->num_visible, numdel));
  for (visible=qh->visible_list; visible && visible->visible;
                visible= nextfacet) { /* deleting current */
    nextfacet= visible->next;
    numvisible++;
    qh_delfacet(qh, visible);  /* f.ridges deleted or moved elsewhere, deleted f.vertices on qh.del_vertices */
  }
  if (numvisible != qh->num_visible) {
    qh_fprintf(qh, qh->ferr, 6103, "qhull internal error (qh_deletevisible): qh->num_visible %d is not number of visible facets %d\n",
             qh->num_visible, numvisible);
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  qh->num_visible= 0;
  zadd_(Zvisfacettot, numvisible);
  zmax_(Zvisfacetmax, numvisible);
  zzadd_(Zdelvertextot, numdel);
  zmax_(Zdelvertexmax, numdel);
  FOREACHvertex_(qh->del_vertices)
    qh_delvertex(qh, vertex);
  qh_settruncate(qh, qh->del_vertices, 0);
} /* deletevisible */

/*---------------------------------

  qh_facetintersect(qh, facetA, facetB, skipa, skipB, prepend )
    return vertices for intersection of two simplicial facets
    may include 1 prepended entry (if more, need to settemppush)

  returns:
    returns set of qh.hull_dim-1 + prepend vertices
    returns skipped index for each test and checks for exactly one

  notes:
    does not need settemp since set in quick memory

  see also:
    qh_vertexintersect and qh_vertexintersect_new
    use qh_setnew_delnthsorted to get nth ridge (no skip information)

  design:
    locate skipped vertex by scanning facet A's neighbors
    locate skipped vertex by scanning facet B's neighbors
    intersect the vertex sets
*/
setT *qh_facetintersect(qhT *qh, facetT *facetA, facetT *facetB,
                         int *skipA,int *skipB, int prepend) {
  setT *intersect;
  int dim= qh->hull_dim, i, j;
  facetT **neighborsA, **neighborsB;

  neighborsA= SETaddr_(facetA->neighbors, facetT);
  neighborsB= SETaddr_(facetB->neighbors, facetT);
  i= j= 0;
  if (facetB == *neighborsA++)
    *skipA= 0;
  else if (facetB == *neighborsA++)
    *skipA= 1;
  else if (facetB == *neighborsA++)
    *skipA= 2;
  else {
    for (i=3; i < dim; i++) {
      if (facetB == *neighborsA++) {
        *skipA= i;
        break;
      }
    }
  }
  if (facetA == *neighborsB++)
    *skipB= 0;
  else if (facetA == *neighborsB++)
    *skipB= 1;
  else if (facetA == *neighborsB++)
    *skipB= 2;
  else {
    for (j=3; j < dim; j++) {
      if (facetA == *neighborsB++) {
        *skipB= j;
        break;
      }
    }
  }
  if (i >= dim || j >= dim) {
    qh_fprintf(qh, qh->ferr, 6104, "qhull internal error (qh_facetintersect): f%d or f%d not in other's neighbors\n",
            facetA->id, facetB->id);
    qh_errexit2(qh, qh_ERRqhull, facetA, facetB);
  }
  intersect= qh_setnew_delnthsorted(qh, facetA->vertices, qh->hull_dim, *skipA, prepend);
  trace4((qh, qh->ferr, 4047, "qh_facetintersect: f%d skip %d matches f%d skip %d\n",
          facetA->id, *skipA, facetB->id, *skipB));
  return(intersect);
} /* facetintersect */

/*---------------------------------

  qh_gethash(qh, hashsize, set, size, firstindex, skipelem )
    return hashvalue for a set with firstindex and skipelem

  notes:
    returned hash is in [0,hashsize)
    assumes at least firstindex+1 elements
    assumes skipelem is NULL, in set, or part of hash

    hashes memory addresses which may change over different runs of the same data
    using sum for hash does badly in high d
*/
int qh_gethash(qhT *qh, int hashsize, setT *set, int size, int firstindex, void *skipelem) {
  void **elemp= SETelemaddr_(set, firstindex, void);
  ptr_intT hash= 0, elem;
  unsigned int uresult;
  int i;
#ifdef _MSC_VER                   /* Microsoft Visual C++ -- warn about 64-bit issues */
#pragma warning( push)            /* WARN64 -- ptr_intT holds a 64-bit pointer */
#pragma warning( disable : 4311)  /* 'type cast': pointer truncation from 'void*' to 'ptr_intT' */
#endif

  switch (size-firstindex) {
  case 1:
    hash= (ptr_intT)(*elemp) - (ptr_intT) skipelem;
    break;
  case 2:
    hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] - (ptr_intT) skipelem;
    break;
  case 3:
    hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
      - (ptr_intT) skipelem;
    break;
  case 4:
    hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
      + (ptr_intT)elemp[3] - (ptr_intT) skipelem;
    break;
  case 5:
    hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
      + (ptr_intT)elemp[3] + (ptr_intT)elemp[4] - (ptr_intT) skipelem;
    break;
  case 6:
    hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
      + (ptr_intT)elemp[3] + (ptr_intT)elemp[4]+ (ptr_intT)elemp[5]
      - (ptr_intT) skipelem;
    break;
  default:
    hash= 0;
    i= 3;
    do {     /* this is about 10% in 10-d */
      if ((elem= (ptr_intT)*elemp++) != (ptr_intT)skipelem) {
        hash ^= (elem << i) + (elem >> (32-i));
        i += 3;
        if (i >= 32)
          i -= 32;
      }
    }while (*elemp);
    break;
  }
  if (hashsize<0) {
    qh_fprintf(qh, qh->ferr, 6202, "qhull internal error: negative hashsize %d passed to qh_gethash [poly_r.c]\n", hashsize);
    qh_errexit2(qh, qh_ERRqhull, NULL, NULL);
  }
  uresult= (unsigned int)hash;
  uresult %= (unsigned int)hashsize;
  /* result= 0; for debugging */
  return (int)uresult;
#ifdef _MSC_VER
#pragma warning( pop)
#endif
} /* gethash */

/*---------------------------------

  qh_getreplacement(qh, visible )
    get replacement for visible facet

  returns:
    valid facet from visible.replace (may be chained)
*/
facetT *qh_getreplacement(qhT *qh, facetT *visible) {
  unsigned int count= 0;

  facetT *result= visible;
  while (result && result->visible) {
    result= result->f.replace;
    if (count++ > qh->facet_id)
      qh_infiniteloop(qh, visible);
  }
  return result;
}

/*---------------------------------

  qh_makenewfacet(qh, vertices, toporient, horizon )
    creates a toporient? facet from vertices

  returns:
    returns newfacet
      adds newfacet to qh.facet_list
      newfacet->vertices= vertices
      if horizon
        newfacet->neighbor= horizon, but not vice versa
    newvertex_list updated with vertices
*/
facetT *qh_makenewfacet(qhT *qh, setT *vertices, boolT toporient, facetT *horizon) {
  facetT *newfacet;
  vertexT *vertex, **vertexp;

  FOREACHvertex_(vertices) {
    if (!vertex->newfacet) {
      qh_removevertex(qh, vertex);
      qh_appendvertex(qh, vertex);
    }
  }
  newfacet= qh_newfacet(qh);
  newfacet->vertices= vertices;
  if (toporient)
    newfacet->toporient= True;
  if (horizon)
    qh_setappend(qh, &(newfacet->neighbors), horizon);
  qh_appendfacet(qh, newfacet);
  return(newfacet);
} /* makenewfacet */


/*---------------------------------

  qh_makenewplanes()
    make new hyperplanes for facets on qh.newfacet_list

  returns:
    all facets have hyperplanes or are marked for   merging
    doesn't create hyperplane if horizon is coplanar (will merge)
    updates qh.min_vertex if qh.JOGGLEmax

  notes:
    facet->f.samecycle is defined for facet->mergehorizon facets
*/
void qh_makenewplanes(qhT *qh /* qh.newfacet_list */) {
  facetT *newfacet;

  trace4((qh, qh->ferr, 4074, "qh_makenewplanes: make new hyperplanes for facets on qh.newfacet_list f%d\n",
    qh->newfacet_list->id));
  FORALLnew_facets {
    if (!newfacet->mergehorizon)
      qh_setfacetplane(qh, newfacet); /* updates Wnewvertexmax */
  }
  if (qh->JOGGLEmax < REALmax/2)
    minimize_(qh->min_vertex, -wwval_(Wnewvertexmax));
} /* makenewplanes */

#ifndef qh_NOmerge
/*---------------------------------

  qh_makenew_nonsimplicial(qh, visible, apex, numnew )
    make new facets for ridges of a visible facet

  returns:
    first newfacet, bumps numnew as needed
    attaches new facets if !qh->NEWtentative
    marks ridge neighbors for simplicial visible
    if (qh.NEWtentative)
      ridges on newfacet, horizon, and visible
    else
      ridge and neighbors between newfacet and horizon
      visible facet's ridges are deleted
      visible facet's f.neighbors is empty

  notes:
    called by qh_makenewfacets and qh_triangulatefacet
    qh.visit_id if visible has already been processed
    sets neighbor->seen for building f.samecycle
      assumes all 'seen' flags initially false
    qh_delridge_merge not needed (as tested by qh_checkdelridge in qh_makenewfacets)

  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)

*/
facetT *qh_makenew_nonsimplicial(qhT *qh, facetT *visible, vertexT *apex, int *numnew) {
  void **freelistp; /* used if !qh_NOmem by qh_memfree_() */
  ridgeT *ridge, **ridgep;
  facetT *neighbor, *newfacet= NULL, *samecycle;
  setT *vertices;
  boolT toporient;
  unsigned int ridgeid;

  FOREACHridge_(visible->ridges) {
    ridgeid= ridge->id;
    neighbor= otherfacet_(ridge, visible);
    if (neighbor->visible) {
      if (!qh->NEWtentative) {
        if (neighbor->visitid == qh->visit_id) {
          if (qh->traceridge == ridge)
            qh->traceridge= NULL;
          qh_setfree(qh, &(ridge->vertices));  /* delete on 2nd visit */
          qh_memfree_(qh, ridge, (int)sizeof(ridgeT), freelistp);
        }
      }
    }else {  /* neighbor is an horizon facet */
      toporient= (ridge->top == visible);
      vertices= qh_setnew(qh, qh->hull_dim); /* makes sure this is quick */
      qh_setappend(qh, &vertices, apex);
      qh_setappend_set(qh, &vertices, ridge->vertices);
      newfacet= qh_makenewfacet(qh, vertices, toporient, neighbor);
      (*numnew)++;
      if (neighbor->coplanarhorizon) {
        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->NEWtentative) {
        if (!neighbor->simplicial)
          qh_setappend(qh, &(newfacet->ridges), ridge);
      }else {  /* qh_attachnewfacets */
        if (neighbor->seen) {
          if (neighbor->simplicial) {
            qh_fprintf(qh, qh->ferr, 6105, "qhull internal error (qh_makenew_nonsimplicial): simplicial f%d sharing two ridges with f%d\n",
                   neighbor->id, visible->id);
            qh_errexit2(qh, qh_ERRqhull, neighbor, visible);
          }
          qh_setappend(qh, &(neighbor->neighbors), newfacet);
        }else
          qh_setreplace(qh, neighbor->neighbors, visible, newfacet);
        if (neighbor->simplicial) {
          qh_setdel(neighbor->ridges, ridge);
          qh_delridge(qh, ridge);
        }else {
          qh_setappend(qh, &(newfacet->ridges), ridge);
          if (toporient) {
            ridge->top= newfacet;
            ridge->simplicialtop= True;
          }else {
            ridge->bottom= newfacet;
            ridge->simplicialbot= True;
          }
        }
      }
      trace4((qh, qh->ferr, 4048, "qh_makenew_nonsimplicial: created facet f%d from v%d and r%d of horizon f%d\n",
          newfacet->id, apex->id, ridgeid, neighbor->id));
    }
    neighbor->seen= True;
  } /* for each ridge */
  return newfacet;
} /* makenew_nonsimplicial */

#else /* qh_NOmerge */
facetT *qh_makenew_nonsimplicial(qhT *qh, facetT *visible, vertexT *apex, int *numnew) {
  QHULL_UNUSED(qh)
  QHULL_UNUSED(visible)
  QHULL_UNUSED(apex)
  QHULL_UNUSED(numnew)

  return NULL;
}
#endif /* qh_NOmerge */

/*---------------------------------

  qh_makenew_simplicial(qh, visible, apex, numnew )
    make new facets for simplicial visible facet and apex

  returns:
    attaches new facets if !qh.NEWtentative
      neighbors between newfacet and horizon

  notes:
    nop if neighbor->seen or neighbor->visible(see qh_makenew_nonsimplicial)

  design:
    locate neighboring horizon facet for visible facet
    determine vertices and orientation
    create new facet
    if coplanar,
      add new facet to f.samecycle
    update horizon facet's neighbor list
*/
facetT *qh_makenew_simplicial(qhT *qh, facetT *visible, vertexT *apex, int *numnew) {
  facetT *neighbor, **neighborp, *newfacet= NULL;
  setT *vertices;
  boolT flip, toporient;
  int horizonskip= 0, visibleskip= 0;

  FOREACHneighbor_(visible) {
    if (!neighbor->seen && !neighbor->visible) {
      vertices= qh_facetintersect(qh, neighbor,visible, &horizonskip, &visibleskip, 1);
      SETfirst_(vertices)= apex;
      flip= ((horizonskip & 0x1) ^ (visibleskip & 0x1));
      if (neighbor->toporient)
        toporient= horizonskip & 0x1;
      else
        toporient= (horizonskip & 0x1) ^ 0x1;
      newfacet= qh_makenewfacet(qh, vertices, toporient, neighbor);
      (*numnew)++;
      if (neighbor->coplanarhorizon && (qh->PREmerge || qh->MERGEexact)) {
#ifndef qh_NOmerge
        newfacet->f.samecycle= newfacet;
        newfacet->mergehorizon= True;
#endif
      }
      if (!qh->NEWtentative)
        SETelem_(neighbor->neighbors, horizonskip)= newfacet;
      trace4((qh, qh->ferr, 4049, "qh_makenew_simplicial: create facet f%d top %d from v%d and horizon f%d skip %d top %d and visible f%d skip %d, flip? %d\n",
            newfacet->id, toporient, apex->id, neighbor->id, horizonskip,
              neighbor->toporient, visible->id, visibleskip, flip));
    }
  }
  return newfacet;
} /* makenew_simplicial */

/*---------------------------------

  qh_matchneighbor(qh, newfacet, newskip, hashsize, hashcount )
    either match subridge of newfacet with neighbor or add to hash_table

  returns:
    matched ridges of newfacet, except for duplicate ridges
    duplicate ridges marked by qh_DUPLICATEridge for qh_matchdupridge

  notes:
    called by qh_matchnewfacets
    assumes newfacet is simplicial
    ridge is newfacet->vertices w/o newskip vertex
    do not allocate memory (need to free hash_table cleanly)
    uses linear hash chains
    see qh_matchdupridge (poly2_r.c)

  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
          note: dupridge detected when a match 'f&d skip %d' has already been seen 
                need to mark all of the dupridges for qh_matchdupridge
          indicate a duplicate ridge by qh_DUPLICATEridge and f.dupridge
          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

  state at "indicate a duplicate ridge":
    newfacet@newskip= the argument
    facet= the hashed facet@skip that has the same vertices as newfacet@newskip
    same= true if matched vertices have the same orientation
    matchfacet= neighbor at facet@skip
    matchfacet=qh_DUPLICATEridge, matchfacet was previously detected as a dupridge of facet@skip
    ismatch if 'vertex orientation (same) matches facet/newfacet orientation (toporient)
    unknown facet will match later

  details at "indicate a duplicate ridge":
    if !ismatch and matchfacet,
      dupridge is between hashed facet@skip/matchfacet@matchskip and arg newfacet@newskip/unknown 
      set newfacet@newskip, facet@skip, and matchfacet@matchskip to qh_DUPLICATEridge
      add newfacet and matchfacet to hash_table
      if ismatch and matchfacet, 
        same as !ismatch and matchfacet -- it matches facet instead of matchfacet
      if !ismatch and !matchfacet
        dupridge between hashed facet@skip/unknown and arg newfacet@newskip/unknown 
        set newfacet@newskip and facet@skip to qh_DUPLICATEridge
        add newfacet to hash_table
      if ismatch and matchfacet==qh_DUPLICATEridge
        dupridge with already duplicated hashed facet@skip and arg newfacet@newskip/unknown
        set newfacet@newskip to qh_DUPLICATEridge
        add newfacet to hash_table
        facet's hyperplane already set
*/
void qh_matchneighbor(qhT *qh, facetT *newfacet, int newskip, int hashsize, int *hashcount) {
  boolT newfound= False;   /* True, if new facet is already in hash chain */
  boolT same, ismatch;
  int hash, scan;
  facetT *facet, *matchfacet;
  int skip, matchskip;

  hash= qh_gethash(qh, hashsize, newfacet->vertices, qh->hull_dim, 1,
                     SETelem_(newfacet->vertices, newskip));
  trace4((qh, qh->ferr, 4050, "qh_matchneighbor: newfacet f%d skip %d hash %d hashcount %d\n",
          newfacet->id, newskip, hash, *hashcount));
  zinc_(Zhashlookup);
  for (scan=hash; (facet= SETelemt_(qh->hash_table, scan, facetT));
       scan= (++scan >= hashsize ? 0 : scan)) {
    if (facet == newfacet) {
      newfound= True;
      continue;
    }
    zinc_(Zhashtests);
    if (qh_matchvertices(qh, 1, newfacet->vertices, newskip, facet->vertices, &skip, &same)) {
      if (SETelem_(newfacet->vertices, newskip) == SETelem_(facet->vertices, skip)) {
        qh_joggle_restart(qh, "two new facets with the same vertices");
        /* duplicated for multiple skips, not easily avoided */
        qh_fprintf(qh, qh->ferr, 7084, "qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f%d and f%d have the same vertices (skip %d, skip %d) and same horizon ridges to f%d and f%d\n",
          facet->id, newfacet->id, skip, newskip, SETfirstt_(facet->neighbors, facetT)->id, SETfirstt_(newfacet->neighbors, facetT)->id);
        /* will rename a vertex (QH3053).  The fault was duplicate ridges (same vertices) in different facets due to a previous rename.  Expensive to detect beforehand */
      }
      ismatch= (same == (boolT)((newfacet->toporient ^ facet->toporient)));
      matchfacet= SETelemt_(facet->neighbors, skip, facetT);
      if (ismatch && !matchfacet) {
        SETelem_(facet->neighbors, skip)= newfacet;
        SETelem_(newfacet->neighbors, newskip)= facet;
        (*hashcount)--;
        trace4((qh, qh->ferr, 4051, "qh_matchneighbor: f%d skip %d matched with new f%d skip %d\n",
           facet->id, skip, newfacet->id, newskip));
        return;
      }
      if (!qh->PREmerge && !qh->MERGEexact) {
        qh_joggle_restart(qh, "a ridge with more than two neighbors");
        qh_fprintf(qh, qh->ferr, 6107, "qhull topology error: facets f%d, f%d and f%d meet at a ridge with more than 2 neighbors.  Can not continue due to no qh.PREmerge and no 'Qx' (MERGEexact)\n",
                 facet->id, newfacet->id, getid_(matchfacet));
        qh_errexit2(qh, qh_ERRtopology, facet, newfacet);
      }
      SETelem_(newfacet->neighbors, newskip)= qh_DUPLICATEridge;
      newfacet->dupridge= True;
      qh_addhash(newfacet, qh->hash_table, hashsize, hash);
      (*hashcount)++;
      if (matchfacet != qh_DUPLICATEridge) {
        SETelem_(facet->neighbors, skip)= qh_DUPLICATEridge;
        facet->dupridge= True;
        if (matchfacet) {
          matchskip= qh_setindex(matchfacet->neighbors, facet);
          if (matchskip<0) {
              qh_fprintf(qh, qh->ferr, 6260, "qhull topology error (qh_matchneighbor): matchfacet f%d is in f%d neighbors but not vice versa.  Can not continue.\n",
                  matchfacet->id, facet->id);
              qh_errexit2(qh, qh_ERRtopology, matchfacet, facet);
          }
          SETelem_(matchfacet->neighbors, matchskip)= qh_DUPLICATEridge; /* matchskip>=0 by QH6260 */
          matchfacet->dupridge= True;
          qh_addhash(matchfacet, qh->hash_table, hashsize, hash);
          *hashcount += 2;
        }
      }
      trace4((qh, qh->ferr, 4052, "qh_matchneighbor: new f%d skip %d duplicates ridge for f%d skip %d matching f%d ismatch %d at hash %d\n",
           newfacet->id, newskip, facet->id, skip,
           (matchfacet == qh_DUPLICATEridge ? -2 : getid_(matchfacet)),
           ismatch, hash));
      return; /* end of duplicate ridge */
    }
  }
  if (!newfound)
    SETelem_(qh->hash_table, scan)= newfacet;  /* same as qh_addhash */
  (*hashcount)++;
  trace4((qh, qh->ferr, 4053, "qh_matchneighbor: no match for f%d skip %d at hash %d\n",
           newfacet->id, newskip, hash));
} /* matchneighbor */


/*---------------------------------

  qh_matchnewfacets(qh )
    match new facets in qh.newfacet_list to their newfacet neighbors
    all facets are simplicial

  returns:
    if dupridges and merging 
      returns maxdupdist (>=0.0) from vertex to opposite facet
      sets facet->dupridge
      missing neighbor links identify dupridges to be merged (qh_DUPLICATEridge)
    else  
      qh.newfacet_list with full neighbor sets
        vertices for the nth neighbor match all but the nth vertex
    if not merging and qh.FORCEoutput
      for facets with normals (i.e., with dupridges)
      sets facet->flippped for flipped normals, also prevents point partitioning

  notes:
    called by qh_buildcone* and qh_triangulate_facet
    neighbor[0] of new facets is the horizon facet
    if NEWtentative, new facets not attached to the horizon
    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:
    truncate neighbor sets to horizon facet 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
        try to match facets with the same coplanar horizon
    if not all matched
      for each new facet with a duplicate ridge
        match it with a coplanar facet, or identify a pinched vertex
    if not merging and qh.FORCEoutput
      check for flipped facets
*/
coordT qh_matchnewfacets(qhT *qh /* qh.newfacet_list */) {
  int numnew=0, hashcount=0, newskip;
  facetT *newfacet, *neighbor;
  coordT maxdupdist= 0.0, maxdist2;
  int dim= qh->hull_dim, hashsize, neighbor_i, neighbor_n;
  setT *neighbors;
#ifndef qh_NOtrace
  int facet_i, facet_n, numunused= 0;
  facetT *facet;
#endif

  trace1((qh, qh->ferr, 1019, "qh_matchnewfacets: match neighbors for new facets.\n"));
  FORALLnew_facets {
    numnew++;
    {  /* inline qh_setzero(qh, newfacet->neighbors, 1, qh->hull_dim); */
      neighbors= newfacet->neighbors;
      neighbors->e[neighbors->maxsize].i= dim+1; /*may be overwritten*/
      memset((char *)SETelemaddr_(neighbors, 1, void), 0, (size_t)(dim * SETelemsize));
    }
  }

  qh_newhashtable(qh, numnew*(qh->hull_dim-1)); /* twice what is normally needed,
                                     but every ridge could be DUPLICATEridge */
  hashsize= qh_setsize(qh, qh->hash_table);
  FORALLnew_facets {
    if (!newfacet->simplicial) {
      qh_fprintf(qh, qh->ferr, 6377, "qhull internal error (qh_matchnewfacets): expecting simplicial facets on qh.newfacet_list f%d for qh_matchneighbors, qh_matchneighbor, and qh_matchdupridge.  Got non-simplicial f%d\n",
        qh->newfacet_list->id, newfacet->id);
      qh_errexit2(qh, qh_ERRqhull, newfacet, qh->newfacet_list);
    }
    for (newskip=1; newskiphull_dim; newskip++) /* furthest/horizon already matched */
      /* hashsize>0 because hull_dim>1 and numnew>0 */
      qh_matchneighbor(qh, newfacet, newskip, hashsize, &hashcount);
#if 0   /* use the following to trap hashcount errors */
    {
      int count= 0, k;
      facetT *facet, *neighbor;

      count= 0;
      FORALLfacet_(qh->newfacet_list) {  /* newfacet already in use */
        for (k=1; k < qh->hull_dim; k++) {
          neighbor= SETelemt_(facet->neighbors, k, facetT);
          if (!neighbor || neighbor == qh_DUPLICATEridge)
            count++;
        }
        if (facet == newfacet)
          break;
      }
      if (count != hashcount) {
        qh_fprintf(qh, qh->ferr, 6266, "qhull error (qh_matchnewfacets): after adding facet %d, hashcount %d != count %d\n",
                 newfacet->id, hashcount, count);
        qh_errexit(qh, qh_ERRdebug, newfacet, NULL);
      }
    }
#endif  /* end of trap code */
  } /* end FORALLnew_facets */
  if (hashcount) { /* all neighbors matched, except for qh_DUPLICATEridge neighbors */
    qh_joggle_restart(qh, "ridge with multiple neighbors");
    if (hashcount) {
      FORALLnew_facets {
        if (newfacet->dupridge) {
          FOREACHneighbor_i_(qh, newfacet) {
            if (neighbor == qh_DUPLICATEridge) {
              maxdist2= qh_matchdupridge(qh, newfacet, neighbor_i, hashsize, &hashcount);
              maximize_(maxdupdist, maxdist2);
            }
          }
        }
      }
    }
  }
  if (hashcount) {
    qh_fprintf(qh, qh->ferr, 6108, "qhull internal error (qh_matchnewfacets): %d neighbors did not match up\n",
        hashcount);
    qh_printhashtable(qh, qh->ferr);
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
#ifndef qh_NOtrace
  if (qh->IStracing >= 3) {
    FOREACHfacet_i_(qh, qh->hash_table) {
      if (!facet)
        numunused++;
    }
    qh_fprintf(qh, qh->ferr, 3063, "qh_matchnewfacets: maxdupdist %2.2g, new facets %d, unused hash entries %d, hashsize %d\n",
             maxdupdist, numnew, numunused, qh_setsize(qh, qh->hash_table));
  }
#endif /* !qh_NOtrace */
  qh_setfree(qh, &qh->hash_table);
  if (qh->PREmerge || qh->MERGEexact) {
    if (qh->IStracing >= 4)
      qh_printfacetlist(qh, qh->newfacet_list, NULL, qh_ALL);
  }
  return maxdupdist;
} /* matchnewfacets */


/*---------------------------------

  qh_matchvertices(qh, firstindex, verticesA, skipA, verticesB, skipB, same )
    tests whether vertices match with a single skip
    starts match at firstindex since all new facets have a common vertex

  returns:
    true if matched vertices
    skip index for skipB
    sets same iff vertices have the same orientation

  notes:
    called by qh_matchneighbor and qh_matchdupridge
    assumes skipA is in A and both sets are the same size

  design:
    set up pointers
    scan both sets checking for a match
    test orientation
*/
boolT qh_matchvertices(qhT *qh, int firstindex, setT *verticesA, int skipA,
       setT *verticesB, int *skipB, boolT *same) {
  vertexT **elemAp, **elemBp, **skipBp=NULL, **skipAp;

  elemAp= SETelemaddr_(verticesA, firstindex, vertexT);
  elemBp= SETelemaddr_(verticesB, firstindex, vertexT);
  skipAp= SETelemaddr_(verticesA, skipA, vertexT);
  do if (elemAp != skipAp) {
    while (*elemAp != *elemBp++) {
      if (skipBp)
        return False;
      skipBp= elemBp;  /* one extra like FOREACH */
    }
  }while (*(++elemAp));
  if (!skipBp)
    skipBp= ++elemBp;
  *skipB= SETindex_(verticesB, skipB); /* i.e., skipBp - verticesB
                                       verticesA and verticesB are the same size, otherwise trace4 may segfault */
  *same= !((skipA & 0x1) ^ (*skipB & 0x1)); /* result is 0 or 1 */
  trace4((qh, qh->ferr, 4054, "qh_matchvertices: matched by skip %d(v%d) and skip %d(v%d) same? %d\n",
          skipA, (*skipAp)->id, *skipB, (*(skipBp-1))->id, *same));
  return(True);
} /* matchvertices */

/*---------------------------------

  qh_newfacet(qh)
    return a new facet

  returns:
    all fields initialized or cleared   (NULL)
    preallocates neighbors set
*/
facetT *qh_newfacet(qhT *qh) {
  facetT *facet;
  void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */

  qh_memalloc_(qh, (int)sizeof(facetT), freelistp, facet, facetT);
  memset((char *)facet, (size_t)0, sizeof(facetT));
  if (qh->facet_id == qh->tracefacet_id)
    qh->tracefacet= facet;
  facet->id= qh->facet_id++;
  facet->neighbors= qh_setnew(qh, qh->hull_dim);
#if !qh_COMPUTEfurthest
  facet->furthestdist= 0.0;
#endif
#if qh_MAXoutside
  if (qh->FORCEoutput && qh->APPROXhull)
    facet->maxoutside= qh->MINoutside;
  else
    facet->maxoutside= qh->DISTround; /* same value as test for QH7082 */
#endif
  facet->simplicial= True;
  facet->good= True;
  facet->newfacet= True;
  trace4((qh, qh->ferr, 4055, "qh_newfacet: created facet f%d\n", facet->id));
  return(facet);
} /* newfacet */


/*---------------------------------

  qh_newridge()
    return a new ridge
  notes:
    caller sets qh.traceridge
*/
ridgeT *qh_newridge(qhT *qh) {
  ridgeT *ridge;
  void **freelistp;   /* used if !qh_NOmem by qh_memalloc_() */

  qh_memalloc_(qh, (int)sizeof(ridgeT), freelistp, ridge, ridgeT);
  memset((char *)ridge, (size_t)0, sizeof(ridgeT));
  zinc_(Ztotridges);
  if (qh->ridge_id == UINT_MAX) {
    qh_fprintf(qh, qh->ferr, 7074, "qhull warning: more than 2^32 ridges.  Qhull results are OK.  Since the ridge ID wraps around to 0, two ridges may have the same identifier.\n");
  }
  ridge->id= qh->ridge_id++;
  trace4((qh, qh->ferr, 4056, "qh_newridge: created ridge r%d\n", ridge->id));
  return(ridge);
} /* newridge */


/*---------------------------------

  qh_pointid(qh, point )
    return id for a point,
    returns qh_IDnone(-3) if null, qh_IDinterior(-2) if interior, or qh_IDunknown(-1) if not known

  alternative code if point is in qh.first_point...
    unsigned long id;
    id= ((unsigned long)point - (unsigned long)qh.first_point)/qh.normal_size;

  notes:
    Valid points are non-negative
    WARN64 -- id truncated to 32-bits, at most 2G points
    NOerrors returned (QhullPoint::id)
    if point not in point array
      the code does a comparison of unrelated pointers.
*/
int qh_pointid(qhT *qh, pointT *point) {
  ptr_intT offset, id;

  if (!point || !qh)
    return qh_IDnone;
  else if (point == qh->interior_point)
    return qh_IDinterior;
  else if (point >= qh->first_point
  && point < qh->first_point + qh->num_points * qh->hull_dim) {
    offset= (ptr_intT)(point - qh->first_point);
    id= offset / qh->hull_dim;
  }else if ((id= qh_setindex(qh->other_points, point)) != -1)
    id += qh->num_points;
  else
    return qh_IDunknown;
  return (int)id;
} /* pointid */

/*---------------------------------

  qh_removefacet(qh, facet )
    unlinks facet from qh.facet_list,

  returns:
    updates qh.facet_list .newfacet_list .facet_next visible_list
    decrements qh.num_facets

  see:
    qh_appendfacet
*/
void qh_removefacet(qhT *qh, facetT *facet) {
  facetT *next= facet->next, *previous= facet->previous; /* next is always defined */

  if (facet == qh->newfacet_list)
    qh->newfacet_list= next;
  if (facet == qh->facet_next)
    qh->facet_next= next;
  if (facet == qh->visible_list)
    qh->visible_list= next;
  if (previous) {
    previous->next= next;
    next->previous= previous;
  }else {  /* 1st facet in qh->facet_list */
    qh->facet_list= next;
    qh->facet_list->previous= NULL;
  }
  qh->num_facets--;
  trace4((qh, qh->ferr, 4057, "qh_removefacet: removed f%d from facet_list, newfacet_list, and visible_list\n", facet->id));
} /* removefacet */


/*---------------------------------

  qh_removevertex(qh, vertex )
    unlinks vertex from qh.vertex_list,

  returns:
    updates qh.vertex_list .newvertex_list
    decrements qh.num_vertices
*/
void qh_removevertex(qhT *qh, vertexT *vertex) {
  vertexT *next= vertex->next, *previous= vertex->previous; /* next is always defined */

  trace4((qh, qh->ferr, 4058, "qh_removevertex: remove v%d from qh.vertex_list\n", vertex->id));
  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= next;
    qh->vertex_list->previous= NULL;
  }
  qh->num_vertices--;
} /* removevertex */


/*---------------------------------

  qh_update_vertexneighbors(qh )
    update vertex neighbors and delete interior vertices

  returns:
    if qh.VERTEXneighbors, 
      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 as coplanar points
    if not qh.VERTEXneighbors (not merging)
      interior vertices of visible facets added to qh.del_vertices for later partitioning as coplanar points
  
  notes
    [jan'19] split off qh_update_vertexneighbors_cone.  Optimize the remaining cases in a future release
    called by qh_triangulate_facet after triangulating a non-simplicial facet, followed by reset_lists
    called by qh_triangulate after triangulating null and mirror facets
    called by qh_all_vertexmerges after calling qh_merge_pinchedvertices

  design:
    if qh.VERTEXneighbors
      for each vertex on newvertex_list (i.e., new vertices and vertices of new facets)
        delete visible facets from vertex neighbors
      for each new facet on newfacet_list
        for each vertex of facet
          append facet to vertex neighbors
      for each visible facet on qh.visible_list
        for each vertex of facet
          if the vertex is not on a new facet and not itself deleted
            if the vertex has a not-visible neighbor (due to merging)
               remove the visible facet from the vertex's neighbors
            otherwise
               add the vertex to qh.del_vertices for later deletion

    if not qh.VERTEXneighbors (not merging)
      for each vertex of a visible facet
        if the vertex is not on a new facet and not itself deleted
           add the vertex to qh.del_vertices for later deletion
*/
void qh_update_vertexneighbors(qhT *qh /* qh.newvertex_list, newfacet_list, visible_list */) {
  facetT *newfacet= NULL, *neighbor, **neighborp, *visible;
  vertexT *vertex, **vertexp;
  int neighborcount= 0;

  if (qh->VERTEXneighbors) {
    trace3((qh, qh->ferr, 3013, "qh_update_vertexneighbors: update v.neighbors for qh.newvertex_list (v%d) and qh.newfacet_list (f%d)\n",
         getid_(qh->newvertex_list), getid_(qh->newfacet_list)));
    FORALLvertex_(qh->newvertex_list) {
      neighborcount= 0;
      FOREACHneighbor_(vertex) {
        if (neighbor->visible) {
          neighborcount++;
          SETref_(neighbor)= NULL;
        }
      }
      if (neighborcount) {
        trace4((qh, qh->ferr, 4046, "qh_update_vertexneighbors: delete %d of %d vertex neighbors for v%d.  Removes to-be-deleted, visible facets\n",
          neighborcount, qh_setsize(qh, vertex->neighbors), vertex->id));
        qh_setcompact(qh, vertex->neighbors);
      }
    }
    FORALLnew_facets {
      if (qh->first_newfacet && newfacet->id >= qh->first_newfacet) {
        FOREACHvertex_(newfacet->vertices)
          qh_setappend(qh, &vertex->neighbors, newfacet);
      }else {  /* called after qh_merge_pinchedvertices.  In 7-D, many more neighbors than new facets.  qh_setin is expensive */
        FOREACHvertex_(newfacet->vertices)
          qh_setunique(qh, &vertex->neighbors, newfacet); 
      }
    }
    trace3((qh, qh->ferr, 3058, "qh_update_vertexneighbors: delete interior vertices for qh.visible_list (f%d)\n",
        getid_(qh->visible_list)));
    FORALLvisible_facets {
      FOREACHvertex_(visible->vertices) {
        if (!vertex->newfacet && !vertex->deleted) {
          FOREACHneighbor_(vertex) { /* this can happen under merging */
            if (!neighbor->visible)
              break;
          }
          if (neighbor)
            qh_setdel(vertex->neighbors, visible);
          else {
            vertex->deleted= True;
            qh_setappend(qh, &qh->del_vertices, vertex);
            trace2((qh, qh->ferr, 2041, "qh_update_vertexneighbors: delete interior vertex p%d(v%d) of visible f%d\n",
                  qh_pointid(qh, vertex->point), vertex->id, visible->id));
          }
        }
      }
    }
  }else {  /* !VERTEXneighbors */
    trace3((qh, qh->ferr, 3058, "qh_update_vertexneighbors: delete old vertices for qh.visible_list (f%d)\n",
      getid_(qh->visible_list)));
    FORALLvisible_facets {
      FOREACHvertex_(visible->vertices) {
        if (!vertex->newfacet && !vertex->deleted) {
          vertex->deleted= True;
          qh_setappend(qh, &qh->del_vertices, vertex);
          trace2((qh, qh->ferr, 2042, "qh_update_vertexneighbors: will delete interior vertex p%d(v%d) of visible f%d\n",
                  qh_pointid(qh, vertex->point), vertex->id, visible->id));
        }
      }
    }
  }
} /* update_vertexneighbors */

/*---------------------------------

  qh_update_vertexneighbors_cone(qh )
    update vertex neighbors for a cone of new facets and delete interior vertices

  returns:
    if qh.VERTEXneighbors, 
      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 as coplanar points
    if not qh.VERTEXneighbors (not merging)
      interior vertices of visible facets added to qh.del_vertices for later partitioning as coplanar points
  
  notes
    called by qh_addpoint after create cone and before premerge

  design:
    if qh.VERTEXneighbors
      for each vertex on newvertex_list (i.e., new vertices and vertices of new facets)
        delete visible facets from vertex neighbors
      for each new facet on newfacet_list
        for each vertex of facet
          append facet to vertex neighbors
      for each visible facet on qh.visible_list
        for each vertex of facet
          if the vertex is not on a new facet and not itself deleted
            if the vertex has a not-visible neighbor (due to merging)
               remove the visible facet from the vertex's neighbors
            otherwise
               add the vertex to qh.del_vertices for later deletion

    if not qh.VERTEXneighbors (not merging)
      for each vertex of a visible facet
        if the vertex is not on a new facet and not itself deleted
           add the vertex to qh.del_vertices for later deletion

*/
void qh_update_vertexneighbors_cone(qhT *qh /* qh.newvertex_list, newfacet_list, visible_list */) {
  facetT *newfacet= NULL, *neighbor, **neighborp, *visible;
  vertexT *vertex, **vertexp;
  int delcount= 0;

  if (qh->VERTEXneighbors) {
    trace3((qh, qh->ferr, 3059, "qh_update_vertexneighbors_cone: update v.neighbors for qh.newvertex_list (v%d) and qh.newfacet_list (f%d)\n",
         getid_(qh->newvertex_list), getid_(qh->newfacet_list)));
    FORALLvertex_(qh->newvertex_list) {
      delcount= 0;
      FOREACHneighbor_(vertex) {
        if (neighbor->visible) { /* alternative design is a loop over visible facets, but needs qh_setdel() */
          delcount++;
          qh_setdelnth(qh, vertex->neighbors, SETindex_(vertex->neighbors, neighbor));
          neighborp--; /* repeat */
        }
      }
      if (delcount) {
        trace4((qh, qh->ferr, 4021, "qh_update_vertexneighbors_cone: deleted %d visible vertexneighbors of v%d\n",
          delcount, vertex->id));
      }
    }
    FORALLnew_facets {
      FOREACHvertex_(newfacet->vertices)
        qh_setappend(qh, &vertex->neighbors, newfacet);
    }
    trace3((qh, qh->ferr, 3065, "qh_update_vertexneighbors_cone: delete interior vertices, if any, for qh.visible_list (f%d)\n",
        getid_(qh->visible_list)));
    FORALLvisible_facets {
      FOREACHvertex_(visible->vertices) {
        if (!vertex->newfacet && !vertex->deleted) {
          FOREACHneighbor_(vertex) { /* this can happen under merging, qh_checkfacet QH4025 */
            if (!neighbor->visible)
              break;
          }
          if (neighbor)
            qh_setdel(vertex->neighbors, visible);
          else {
            vertex->deleted= True;
            qh_setappend(qh, &qh->del_vertices, vertex);
            trace2((qh, qh->ferr, 2102, "qh_update_vertexneighbors_cone: will delete interior vertex p%d(v%d) of visible f%d\n",
              qh_pointid(qh, vertex->point), vertex->id, visible->id));
          }
        }
      }
    }
  }else {  /* !VERTEXneighbors */
    trace3((qh, qh->ferr, 3066, "qh_update_vertexneighbors_cone: delete interior vertices for qh.visible_list (f%d)\n",
      getid_(qh->visible_list)));
    FORALLvisible_facets {
      FOREACHvertex_(visible->vertices) {
        if (!vertex->newfacet && !vertex->deleted) {
          vertex->deleted= True;
          qh_setappend(qh, &qh->del_vertices, vertex);
          trace2((qh, qh->ferr, 2059, "qh_update_vertexneighbors_cone: will delete interior vertex p%d(v%d) of visible f%d\n",
                  qh_pointid(qh, vertex->point), vertex->id, visible->id));
        }
      }
    }
  }
} /* update_vertexneighbors_cone */

qhull-2020.2/src/libqhull_r/poly_r.h0000644060175106010010000003003313665505223015575 0ustar  bbarber/*
  ---------------------------------

   poly_r.h
   header file for poly_r.c and poly2_r.c

   see qh-poly_r.htm, libqhull_r.h and poly_r.c

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull_r/poly_r.h#5 $$Change: 2963 $
   $DateTime: 2020/06/03 19:31:01 $$Author: bbarber $
*/

#ifndef qhDEFpoly
#define qhDEFpoly 1

#include "libqhull_r.h"

/*===============   constants ========================== */

/*----------------------------------

  qh_ALGORITHMfault
    use as argument to checkconvex() to report errors during buildhull
*/
#define qh_ALGORITHMfault 0

/*----------------------------------

  qh_DATAfault
    use as argument to checkconvex() to report errors during initialhull
*/
#define qh_DATAfault 1

/*----------------------------------

  qh_DUPLICATEridge
    special value for facet->neighbor to indicate a duplicate ridge

  notes:
    set by qh_matchneighbor for qh_matchdupridge
*/
#define qh_DUPLICATEridge (facetT *)1L

/*----------------------------------

  qh_MERGEridge       flag in facet
    special value for facet->neighbor to indicate a duplicate ridge that needs merging

  notes:
    set by qh_matchnewfacets..qh_matchdupridge from qh_DUPLICATEridge
    used by qh_mark_dupridges to set facet->mergeridge, facet->mergeridge2 from facet->dupridge
*/
#define qh_MERGEridge (facetT *)2L


/*============ -structures- ====================*/

/*=========== -macros- =========================*/

/*----------------------------------

  FORALLfacet_( facetlist ) { ... }
    assign 'facet' to each facet in facetlist

  notes:
    uses 'facetT *facet;'
    assumes last facet is a sentinel

  see:
    FORALLfacets
*/
#define FORALLfacet_( facetlist ) if (facetlist) for ( facet=(facetlist); facet && facet->next; facet= facet->next )

/*----------------------------------

  FORALLnew_facets { ... }
    assign 'newfacet' to each facet in qh.newfacet_list

  notes:
    uses 'facetT *newfacet;'
    at exit, newfacet==NULL
*/
#define FORALLnew_facets for ( newfacet=qh->newfacet_list; newfacet && newfacet->next; newfacet=newfacet->next )

/*----------------------------------

  FORALLvertex_( vertexlist ) { ... }
    assign 'vertex' to each vertex in vertexlist

  notes:
    uses 'vertexT *vertex;'
    at exit, vertex==NULL
*/
#define FORALLvertex_( vertexlist ) for (vertex=( vertexlist );vertex && vertex->next;vertex= vertex->next )

/*----------------------------------

  FORALLvisible_facets { ... }
    assign 'visible' to each visible facet in qh.visible_list

  notes:
    uses 'vacetT *visible;'
    at exit, visible==NULL
*/
#define FORALLvisible_facets for (visible=qh->visible_list; visible && visible->visible; visible= visible->next)

/*----------------------------------

  FORALLsame_( newfacet ) { ... }
    assign 'same' to each facet in newfacet->f.samecycle

  notes:
    uses 'facetT *same;'
    stops when it returns to newfacet
*/
#define FORALLsame_(newfacet) for (same= newfacet->f.samecycle; same != newfacet; same= same->f.samecycle)

/*----------------------------------

  FORALLsame_cycle_( newfacet ) { ... }
    assign 'same' to each facet in newfacet->f.samecycle

  notes:
    uses 'facetT *same;'
    at exit, same == NULL
*/
#define FORALLsame_cycle_(newfacet) \
     for (same= newfacet->f.samecycle; \
         same; same= (same == newfacet ?  NULL : same->f.samecycle))

/*----------------------------------

  FOREACHneighborA_( facet ) { ... }
    assign 'neighborA' to each neighbor in facet->neighbors

  FOREACHneighborA_( vertex ) { ... }
    assign 'neighborA' to each neighbor in vertex->neighbors

  declare:
    facetT *neighborA, **neighborAp;

  see:
    FOREACHsetelement_
*/
#define FOREACHneighborA_(facet)  FOREACHsetelement_(facetT, facet->neighbors, neighborA)

/*----------------------------------

  FOREACHvisible_( facets ) { ... }
    assign 'visible' to each facet in facets

  notes:
    uses 'facetT *facet, *facetp;'
    see FOREACHsetelement_
*/
#define FOREACHvisible_(facets) FOREACHsetelement_(facetT, facets, visible)

/*----------------------------------

  FOREACHnewfacet_( facets ) { ... }
    assign 'newfacet' to each facet in facets

  notes:
    uses 'facetT *newfacet, *newfacetp;'
    see FOREACHsetelement_
*/
#define FOREACHnewfacet_(facets) FOREACHsetelement_(facetT, facets, newfacet)

/*----------------------------------

  FOREACHvertexA_( vertices ) { ... }
    assign 'vertexA' to each vertex in vertices

  notes:
    uses 'vertexT *vertexA, *vertexAp;'
    see FOREACHsetelement_
*/
#define FOREACHvertexA_(vertices) FOREACHsetelement_(vertexT, vertices, vertexA)

/*----------------------------------

  FOREACHvertexreverse12_( vertices ) { ... }
    assign 'vertex' to each vertex in vertices
    reverse order of first two vertices

  notes:
    uses 'vertexT *vertex, *vertexp;'
    see FOREACHsetelement_
*/
#define FOREACHvertexreverse12_(vertices) FOREACHsetelementreverse12_(vertexT, vertices, vertex)


/*=============== prototypes poly_r.c in alphabetical order ================*/

#ifdef __cplusplus
extern "C" {
#endif

void    qh_appendfacet(qhT *qh, facetT *facet);
void    qh_appendvertex(qhT *qh, vertexT *vertex);
void    qh_attachnewfacets(qhT *qh /* qh.visible_list, qh.newfacet_list */);
boolT   qh_checkflipped(qhT *qh, facetT *facet, realT *dist, boolT allerror);
void    qh_delfacet(qhT *qh, facetT *facet);
void    qh_deletevisible(qhT *qh /* qh.visible_list, qh.horizon_list */);
setT   *qh_facetintersect(qhT *qh, facetT *facetA, facetT *facetB, int *skipAp,int *skipBp, int extra);
int     qh_gethash(qhT *qh, int hashsize, setT *set, int size, int firstindex, void *skipelem);
facetT *qh_getreplacement(qhT *qh, facetT *visible);
facetT *qh_makenewfacet(qhT *qh, setT *vertices, boolT toporient, facetT *facet);
void    qh_makenewplanes(qhT *qh /* qh.newfacet_list */);
facetT *qh_makenew_nonsimplicial(qhT *qh, facetT *visible, vertexT *apex, int *numnew);
facetT *qh_makenew_simplicial(qhT *qh, facetT *visible, vertexT *apex, int *numnew);
void    qh_matchneighbor(qhT *qh, facetT *newfacet, int newskip, int hashsize,
                          int *hashcount);
coordT  qh_matchnewfacets(qhT *qh);
boolT   qh_matchvertices(qhT *qh, int firstindex, setT *verticesA, int skipA,
                          setT *verticesB, int *skipB, boolT *same);
facetT *qh_newfacet(qhT *qh);
ridgeT *qh_newridge(qhT *qh);
int     qh_pointid(qhT *qh, pointT *point);
void    qh_removefacet(qhT *qh, facetT *facet);
void    qh_removevertex(qhT *qh, vertexT *vertex);
void    qh_update_vertexneighbors(qhT *qh);
void    qh_update_vertexneighbors_cone(qhT *qh);


/*========== -prototypes poly2_r.c in alphabetical order ===========*/

boolT   qh_addfacetvertex(qhT *qh, facetT *facet, vertexT *newvertex);
void    qh_addhash(void *newelem, setT *hashtable, int hashsize, int hash);
void    qh_check_bestdist(qhT *qh);
void    qh_check_maxout(qhT *qh);
void    qh_check_output(qhT *qh);
void    qh_check_point(qhT *qh, pointT *point, facetT *facet, realT *maxoutside, realT *maxdist, facetT **errfacet1, facetT **errfacet2, int *errcount);
void    qh_check_points(qhT *qh);
void    qh_checkconvex(qhT *qh, facetT *facetlist, int fault);
void    qh_checkfacet(qhT *qh, facetT *facet, boolT newmerge, boolT *waserrorp);
void    qh_checkflipped_all(qhT *qh, facetT *facetlist);
boolT   qh_checklists(qhT *qh, facetT *facetlist);
void    qh_checkpolygon(qhT *qh, facetT *facetlist);
void    qh_checkvertex(qhT *qh, vertexT *vertex, boolT allchecks, boolT *waserrorp);
void    qh_clearcenters(qhT *qh, qh_CENTER type);
void    qh_createsimplex(qhT *qh, setT *vertices);
void    qh_delridge(qhT *qh, ridgeT *ridge);
void    qh_delvertex(qhT *qh, vertexT *vertex);
setT   *qh_facet3vertex(qhT *qh, facetT *facet);
facetT *qh_findbestfacet(qhT *qh, pointT *point, boolT bestoutside,
           realT *bestdist, boolT *isoutside);
facetT *qh_findbestlower(qhT *qh, facetT *upperfacet, pointT *point, realT *bestdistp, int *numpart);
facetT *qh_findfacet_all(qhT *qh, pointT *point, boolT noupper, realT *bestdist, boolT *isoutside,
                          int *numpart);
int     qh_findgood(qhT *qh, facetT *facetlist, int goodhorizon);
void    qh_findgood_all(qhT *qh, facetT *facetlist);
void    qh_furthestnext(qhT *qh /* qh.facet_list */);
void    qh_furthestout(qhT *qh, facetT *facet);
void    qh_infiniteloop(qhT *qh, facetT *facet);
void    qh_initbuild(qhT *qh);
void    qh_initialhull(qhT *qh, setT *vertices);
setT   *qh_initialvertices(qhT *qh, int dim, setT *maxpoints, pointT *points, int numpoints);
vertexT *qh_isvertex(pointT *point, setT *vertices);
vertexT *qh_makenewfacets(qhT *qh, pointT *point /* qh.horizon_list, visible_list */);
coordT  qh_matchdupridge(qhT *qh, facetT *atfacet, int atskip, int hashsize, int *hashcount);
void    qh_nearcoplanar(qhT *qh /* qh.facet_list */);
vertexT *qh_nearvertex(qhT *qh, facetT *facet, pointT *point, realT *bestdistp);
int     qh_newhashtable(qhT *qh, int newsize);
vertexT *qh_newvertex(qhT *qh, pointT *point);
facetT *qh_nextfacet2d(facetT *facet, vertexT **nextvertexp);
ridgeT *qh_nextridge3d(ridgeT *atridge, facetT *facet, vertexT **vertexp);
vertexT *qh_opposite_vertex(qhT *qh, facetT *facetA,  facetT *neighbor);
void    qh_outcoplanar(qhT *qh /* qh.facet_list */);
pointT *qh_point(qhT *qh, int id);
void    qh_point_add(qhT *qh, setT *set, pointT *point, void *elem);
setT   *qh_pointfacet(qhT *qh /* qh.facet_list */);
setT   *qh_pointvertex(qhT *qh /* qh.facet_list */);
void    qh_prependfacet(qhT *qh, facetT *facet, facetT **facetlist);
void    qh_printhashtable(qhT *qh, FILE *fp);
void    qh_printlists(qhT *qh);
void    qh_replacefacetvertex(qhT *qh, facetT *facet, vertexT *oldvertex, vertexT *newvertex);
void    qh_resetlists(qhT *qh, boolT stats, boolT resetVisible /* qh.newvertex_list qh.newfacet_list qh.visible_list */);
void    qh_setvoronoi_all(qhT *qh);
void    qh_triangulate(qhT *qh /* qh.facet_list */);
void    qh_triangulate_facet(qhT *qh, facetT *facetA, vertexT **first_vertex);
void    qh_triangulate_link(qhT *qh, facetT *oldfacetA, facetT *facetA, facetT *oldfacetB, facetT *facetB);
void    qh_triangulate_mirror(qhT *qh, facetT *facetA, facetT *facetB);
void    qh_triangulate_null(qhT *qh, facetT *facetA);
void    qh_vertexintersect(qhT *qh, setT **vertexsetA,setT *vertexsetB);
setT   *qh_vertexintersect_new(qhT *qh, setT *vertexsetA,setT *vertexsetB);
void    qh_vertexneighbors(qhT *qh /* qh.facet_list */);
boolT   qh_vertexsubset(setT *vertexsetA, setT *vertexsetB);

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* qhDEFpoly */
qhull-2020.2/src/libqhull_r/qh-geom_r.htm0000644060175106010010000003324013716274264016520 0ustar  bbarber



geom_r.c, geom2_r.c -- geometric and floating point routines




Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


geom_r.c, geom2_r.c, random_r.c -- geometric and floating point routines

Geometrically, a vertex is a point with d coordinates and a facet is a halfspace. A halfspace is defined by an oriented hyperplane through the facet's vertices. A hyperplane is defined by d normalized coefficients and an offset. A point is above a facet if its distance to the facet is positive.

Qhull uses floating point coordinates for input points, vertices, halfspace equations, centrums, and an interior point.

Qhull may be configured for single precision or double precision floating point arithmetic (see realT ).

Each floating point operation may incur round-off error (see Merge). The maximum error for distance computations is determined at initialization. The roundoff error in halfspace computation is accounted for by computing the distance from vertices to the halfspace.

Copyright © 1995-2020 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to geom_r.c, geom2_r.c, geom_r.h, random_r.c, random_r.h

»geometric data types and constants

  • coordT coordinates and coefficients are stored as realT
  • pointT a point is an array of DIM3 coordinates

»mathematical macros

  • fabs_ returns the absolute value of a
  • fmax_ returns the maximum value of a and b
  • fmin_ returns the minimum value of a and b
  • maximize_ maximize a value
  • minimize_ minimize a value
  • det2_ compute a 2-d determinate
  • det3_ compute a 3-d determinate
  • dX, dY, dZ compute the difference between two coordinates

»mathematical functions

»computational geometry functions

»point array functions

»geometric facet functions

»geometric roundoff functions

  • qh_detjoggle determine default joggle for points and distance roundoff error
  • qh_detmaxoutside determine qh.MAXoutside target for qh_RATIO... tests
  • qh_detroundoff determine maximum roundoff error and other precision constants
  • qh_distround compute maximum roundoff error due to a distance computation to a normalized hyperplane
  • qh_divzero divide by a number that is nearly zero
  • qh_maxouter return maximum outer plane
  • qh_outerinner return actual outer and inner planes


Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

qhull-2020.2/src/libqhull_r/qh-globa_r.htm0000644060175106010010000001767113716274264016667 0ustar bbarber global_r.c -- global variables and their functions

Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


global_r.c -- global variables and their functions

Qhull uses a data structure, qhT, to store globally defined constants, lists, sets, and variables. It is passed as the first argument to most functions.

Copyright © 1995-2020 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to global_r.c and libqhull_r.h

»Qhull's global variables

»Global variable and initialization routines


Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

qhull-2020.2/src/libqhull_r/qh-io_r.htm0000644060175106010010000003426513716274264016210 0ustar bbarber io_r.c -- input and output operations

Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


io_r.c -- input and output operations

Qhull provides a wide range of input and output options. To organize the code, most output formats use the same driver:

    qh_printbegin( fp, format, facetlist, facets, printall );

    FORALLfacet_( facetlist )
      qh_printafacet( fp, format, facet, printall );

    FOREACHfacet_( facets )
      qh_printafacet( fp, format, facet, printall );

    qh_printend( fp, format );

Note the 'printall' flag. It selects whether or not qh_skipfacet() is tested.

Copyright © 1995-2020 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to io_r.c and io_r.h

»io_r.h constants and types

»User level functions

»Print functions for all output formats

»Text output functions

»Text utility functions

»Geomview output functions

»Geomview utility functions


Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

qhull-2020.2/src/libqhull_r/qh-mem_r.htm0000644060175106010010000001442313716274264016351 0ustar bbarber mem_r.c -- memory operations

Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


mem_r.c -- memory operations

Qhull uses quick-fit memory allocation. It maintains a set of free lists for a variety of small allocations. A small request returns a block from the best fitting free list. If the free list is empty, Qhull allocates a block from a reserved buffer.

Use 'T5' to trace memory allocations.

Copyright © 1995-2020 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to mem_r.c and mem_r.h

»mem_r.h data types and constants

  • ptr_intT for casting a void* to an integer-type
  • qhmemT global memory structure for mem_r.c
  • qh_NOmem disable memory allocation

»mem_r.h macros

»User level functions

»Initialization and termination functions


Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

qhull-2020.2/src/libqhull_r/qh-merge_r.htm0000644060175106010010000004740713716274264016702 0ustar bbarber merge_r.c -- facet merge operations

Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


merge_r.c -- facet merge operations

Qhull handles precision problems by merged facets or joggled input. Except for redundant vertices, it corrects a problem by merging two facets. When done, all facets are clearly convex. See Imprecision in Qhull for further information.

Users may joggle the input ('QJn') instead of merging facets.

Qhull detects and corrects the following problems:

  • More than two facets meeting at a ridge. When Qhull creates facets, it creates an even number of facets for each ridge. A convex hull always has two facets for each ridge. More than two facets may be created if non-adjacent facets share a subridge. This is called a dupridge. In 2-d, a dupridge would create a loop of facets. See 'pinched vertices' below for the resolution of a dupridge.
  • A facet contained in another facet. Facet merging may leave all vertices of one facet as a subset of the vertices of another facet. This is called a redundant facet.
  • A facet with fewer than three neighbors. Facet merging may leave a facet with one or two neighbors. This is called a degenerate facet.
  • A facet with flipped orientation. A facet's hyperplane may define a halfspace that does not include the interior point.This is called a flipped facet.
  • A coplanar horizon facet. A newly processed point may be coplanar with an horizon facet. Qhull creates a new facet without a hyperplane. It links new facets for the same horizon facet together. This is called a samecycle. The new facet or samecycle is merged into the horizon facet.
  • Concave facets. A facet's centrum may be above a neighboring facet. If so, the facets meet at a concave angle.
  • Coplanar facets. A facet's centrum may be coplanar with a neighboring facet (i.e., it is neither clearly below nor clearly above the facet's hyperplane). Qhull removes coplanar facets in independent sets sorted by angle.
  • Redundant vertex. A vertex may have fewer than three neighboring facets. If so, it is redundant and may be renamed to an adjacent vertex without changing the topological structure.This is called a redundant vertex.
  • Pinched vertices. Nearly adjacent vertices may allow a dupridge that connects more than two new facets. A pinched vertex is the nearest horizon vertex that is a neighbor of a dupridge vertex. In 4-D and higher, both vertices may be in the same dupridge. If the vertices are in new facets with inverse orientation, the facets cannot be merged. If so, qhull merges the pinched vertices and recreates the cone of new facets. For a discussion, see 'Nearly adjacent vertices within 1e-13' in Limitations of merged facets.

Copyright © 1995-2020 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to merge_r.c and merge_r.h

»merge_r.h data types, macros, and global sets

  • mergeT structure to identify a merge of two facets
  • FOREACHmerge_ assign 'merge' to each merge in mergeset
  • FOREACHmergeA_ assign 'mergeA' to each merge in mergeset
  • FOREACHmerge_i_ assign 'merge' and 'merge_i' to each merge in mergeset
  • qh global sets qh.facet_mergeset contains non-convex merges while qh.degen_mergeset contains degenerate and redundant facets

»merge_r.h constants

»top-level merge functions

»functions for identifying merges

»functions for determining the best merge

»functions for merging facets

»functions for merging a cycle of facets

If a point is coplanar with an horizon facet, the corresponding new facets are linked together (a samecycle) for merging.

»functions for pinched vertices of dupridges

»functions for renaming a vertex

»functions for identifying vertices for renaming

»functions for check and trace


Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

qhull-2020.2/src/libqhull_r/qh-poly_r.htm0000644060175106010010000005407413716274264016564 0ustar bbarber poly_r.c, poly2_r.c -- polyhedron operations

Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


poly_r.c, poly2_r.c -- polyhedron operations

Qhull uses dimension-free terminology. Qhull builds a polyhedron in dimension d. A polyhedron is a simplicial complex of faces with geometric information for the top and bottom-level faces. A (d-1)-face is a facet, a (d-2)-face is a ridge, and a 0-face is a vertex. For example in 3-d, a facet is a polygon and a ridge is an edge. A facet is built from a ridge (the base) and a vertex (the apex). See Qhull's data structures.

Qhull's primary data structure is a polyhedron. A polyhedron is a list of facets. Each facet has a set of neighboring facets and a set of vertices. Each facet has a hyperplane. For example, a tetrahedron has four facets. If its vertices are a, b, c, d, and its facets are 1, 2, 3, 4, the tetrahedron is

  • facet 1
    • vertices: b c d
    • neighbors: 2 3 4
  • facet 2
    • vertices: a c d
    • neighbors: 1 3 4
  • facet 3
    • vertices: a b d
    • neighbors: 1 2 4
  • facet 4
    • vertices: a b c
    • neighbors: 1 2 3

A facet may be simplicial or non-simplicial. In 3-d, a simplicial facet has three vertices and three neighbors. A nonsimplicial facet has more than three vertices and more than three neighbors. A nonsimplicial facet has a set of ridges and a centrum.

A simplicial facet has an orientation. An orientation is either top or bottom. The flag, facet->toporient, defines the orientation of the facet's vertices. For example in 3-d, 'top' is left-handed orientation (i.e., the vertex order follows the direction of the left-hand fingers when the thumb is pointing away from the center). Except for axis-parallel facets in 5-d and higher, topological orientation determines the geometric orientation of the facet's hyperplane.

A nonsimplicial facet is due to merging two or more facets. The facet's ridge set determine a simplicial decomposition of the facet. Each ridge is a 1-face (i.e., it has two vertices and two neighboring facets). The orientation of a ridge is determined by the order of the neighboring facets. The flag, facet->toporient,is ignored.

A nonsimplicial facet has a centrum for testing convexity. A centrum is a point on the facet's hyperplane that is near the center of the facet. Except for large facets, it is the arithmetic average of the facet's vertices.

A nonsimplicial facet is an approximation that is defined by offsets from the facet's hyperplane. When Qhull finishes, the outer plane is above all points while the inner plane is below the facet's vertices. This guarantees that any exact convex hull passes between the inner and outer planes. The outer plane is defined by facet->maxoutside while the inner plane is computed from the facet's vertices.

Qhull 3.1 includes triangulation of non-simplicial facets ('Qt'). These facets, called tricoplanar, share the same normal. centrum, and Voronoi center. One facet (keepcentrum) owns these data structures. While tricoplanar facets are more accurate than the simplicial facets from joggled input, they may have zero area or flipped orientation.

Copyright © 1995-2020 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to poly_r.c, poly2_r.c, poly_r.h, and libqhull_r.h

»Data types and global lists for polyhedrons

»poly_r.h constants

  • ALGORITHMfault flag to not report errors in qh_checkconvex()
  • DATAfault flag to report errors in qh_checkconvex()
  • DUPLICATEridge special value for facet->neighbor to indicate a duplicate ridge
  • MERGEridge special value for facet->neighbor to indicate a merged ridge

»Global FORALL macros

»FORALL macros

»FOREACH macros

»Indexed FOREACH macros

  • FOREACHfacet_i_ assign 'facet' and 'facet_i' to each facet in facet set
  • FOREACHneighbor_i_ assign 'neighbor' and 'neighbor_i' to each facet in facet->neighbors or vertex->neighbors
  • FOREACHpoint_i_ assign 'point' and 'point_i' to each point in points set
  • FOREACHridge_i_ assign 'ridge' and 'ridge_i' to each ridge in ridges set
  • FOREACHvertex_i_ assign 'vertex' and 'vertex_i' to each vertex in vertices set
  • FOREACHvertexreverse12_ assign 'vertex' to each vertex in vertex set; reverse the order of first two vertices

»Other macros for polyhedrons

  • getid_ return ID for a facet, ridge, or vertex
  • otherfacet_ return neighboring facet for a ridge in a facet

»Facetlist functions

»Facet functions

»Vertex, ridge, and point functions

»Hashtable functions

»Allocation and deallocation functions

»Check functions


Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

qhull-2020.2/src/libqhull_r/qh-qhull_r.htm0000644060175106010010000003145713716274264016726 0ustar bbarber libqhull_r.c -- top-level functions and basic data types

Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


libqhull_r.c -- top-level functions and basic data types

Qhull implements the Quickhull algorithm for computing the convex hull. The Quickhull algorithm combines two well-known algorithms: the 2-d quickhull algorithm and the n-d beneath-beyond algorithm. See Description of Qhull.

This section provides an index to the top-level functions and base data types. The top-level header file, libqhull_r.h, contains prototypes for these functions.

Copyright © 1995-2020 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to libqhull_r.c, libqhull_r.h, and unix_r.c

»libqhull_r.h and unix_r.c data types and constants

  • flagT Boolean flag as a bit
  • boolT boolean value, either True or False
  • CENTERtype to distinguish facet->center
  • qh_PRINT output formats for printing (qh.PRINTout)
  • qh_ALL argument flag for selecting everything
  • qh_ERR Qhull exit status codes for indicating errors
  • qh_FILEstderr Fake stderr to distinguish error output from normal output [C++ only]
  • qh_prompt version and long prompt for Qhull
  • qh_prompt2 synopsis for Qhull
  • qh_prompt3 concise prompt for Qhull
  • qh_version version stamp

»libqhull_r.h other macros

  • traceN print trace message if qh.IStracing >= N.
  • QHULL_UNUSED declare an unused variable to avoid warnings.

»Quickhull routines in call order

»Top-level routines for initializing and terminating Qhull (in other modules)

»Top-level routines for reading and modifying the input (in other modules)

»Top-level routines for calling Qhull (in other modules)

»Top-level routines for returning results (in other modules)

»Top-level routines for testing and debugging (in other modules)


Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

qhull-2020.2/src/libqhull_r/qh-set_r.htm0000644060175106010010000003224713716274264016372 0ustar bbarber qset_r.c -- set data type and operations

Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


qset_r.c -- set data type and operations

Qhull's data structures are constructed from sets. The functions and macros in qset_r.c construct, iterate, and modify these sets. They are the most frequently called functions in Qhull. For this reason, efficiency is the primary concern.

In Qhull, a set is represented by an unordered array of pointers with a maximum size and a NULL terminator (setT). Most sets correspond to mathematical sets (i.e., the pointers are unique). Some sets are sorted to enforce uniqueness. Some sets are ordered. For example, the order of vertices in a ridge determine the ridge's orientation. If you reverse the order of adjacent vertices, the orientation reverses. Some sets are not mathematical sets. They may be indexed as an array and they may include NULL pointers.

The most common operation on a set is to iterate its members. This is done with a 'FOREACH...' macro. Each set has a custom macro. For example, 'FOREACHvertex_' iterates over a set of vertices. Each vertex is assigned to the variable 'vertex' from the pointer 'vertexp'.

Most sets are constructed by appending elements to the set. The last element of a set is either NULL or the index of the terminating NULL for a partially full set. If a set is full, appending an element copies the set to a larger array.

Copyright © 1995-2020 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to qset_r.c and qset_r.h

»Data types and constants

  • SETelemsize size of a set element in bytes
  • setT a set with a maximum size and a current size
  • qh global sets global sets for temporary sets, etc.

»FOREACH macros

»Access and size macros

»Internal macros

  • SETsizeaddr_ return pointer to end element of a set (indicates current size)

»address macros

  • SETaddr_ return address of a set's elements
  • SETelemaddr_ return address of the n'th element of a set
  • SETref_ l_r.h.s. for modifying the current element in a FOREACH iteration

»Allocation and deallocation functions

»Access and predicate functions

»Add functions

»Check and print functions

»Copy, compact, and zero functions

»Delete functions

»Temporary set functions


Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

qhull-2020.2/src/libqhull_r/qh-stat_r.htm0000644060175106010010000001601013716274264016540 0ustar bbarber stat_r.c -- statistical operations

Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


stat_r.c -- statistical operations

Qhull records many statistics. These functions and macros make it inexpensive to add a statistic.

As with Qhull's global variables, the statistics data structure is accessed by a macro, 'qhstat'. If qh_QHpointer is defined, the macro is 'qh_qhstat->', otherwise the macro is 'qh_qhstat.'. Statistics may be turned off in user_r.h. If so, all but the 'zz' statistics are ignored.

Copyright © 1995-2020 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to stat_r.c and stat_r.h

»stat_r.h types

  • intrealT union of integer and real
  • qhstat global data structure for statistics

»stat_r.h constants

  • qh_KEEPstatistics 0 turns off most statistics
  • Z..., W... integer (Z) and real (W) statistics
  • ZZstat Z.../W... statistics that remain defined if qh_KEEPstatistics=0
  • ztype zdoc, zinc, etc. for definining statistics

»stat_r.h macros

  • MAYdebugx called frequently for error trapping
  • zadd_/wadd_ add value to an integer or real statistic
  • zdef_ define a statistic
  • zinc_ increment an integer statistic
  • zmax_/wmax_ update integer or real maximum statistic
  • zmin_/wmin_ update integer or real minimum statistic
  • zval_/wval_ set or return value of a statistic

»stat_r.c functions


Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

qhull-2020.2/src/libqhull_r/qh-user_r.htm0000644060175106010010000003610513716274264016552 0ustar bbarber user_r.c -- user-definable operations

Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


user_r.c -- user-definable operations

This section contains functions and constants that the user may want to change.

Copyright © 1995-2020 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to user_r.c, usermem_r.c, userprintf_r.c, userprintf_rbox_r.c and user_r.h

»Qhull library constants

»user_r.h data types and configuration macros

»definition constants

  • qh_DEFAULTbox define default box size for rbox, 'Qbb', and 'QbB' (Geomview expects 0.5)
  • qh_INFINITE on output, indicates Voronoi center at infinity
  • qh_ORIENTclock define convention for orienting facets
  • qh_RANDOMdist for testing qh.DISTround (sets qh.RANDOMfactor for qh.RANDOMdist, same as option 'Rn')

»joggle constants

»performance related constants

»memory constants

»conditional compilation

  • compiler defined symbols, e.g., _STDC_ and _cplusplus
  • qh_COMPUTEfurthest compute furthest distance to an outside point instead of storing it with the facet
  • qh_KEEPstatistics enable statistic gathering and reporting with option 'Ts'
  • qh_MAXcheckpoint report up to qh_MAXcheckpoint errors per facet in qh_check_point ('Tv')
  • qh_MAXoutside record outer plane for each facet
  • qh_NOmerge disable facet merging
  • qh_NOtrace disable tracing with option 'T4'
  • qh_QHpointer access global data with pointer or static structure
  • qh_QUICKhelp use abbreviated help messages, e.g., for degenerate inputs

»merge constants

  • qh_BESTcentrum if many vertices for facet, qh_findbestneighbor tests centrums instead of vertices
  • qh_BESTnonconvex if many neighbors for facet, qh_findbestneighbor only tests nonconvex ridges
  • qh_COPLANARratio what is qh.MINvisible?
  • qh_DIMreduceBuild max dimension for vertex reduction
  • qh_DIMmergeVertex max dimension for vertex merging
  • qh_DISToutside when is a point clearly outside of a facet for qh_findbestnew and qh_partitionall
  • qh_MAXnarrow max. cosine for qh.NARROWhull
  • qh_MAXcoplanarcentrum if 'Qx' and many merges, use f.maxoutside for coplanarity test instead of qh.centrum_radius
  • qh_MAXnarrow max. cosine in initial hull that sets qh.NARROWhull
  • qh_MAXnewcentrum when does qh_reducevertices_centrum() reset the centrum?
  • qh_MAXnewmerges when does qh_merge_nonconvex() call qh_reducevertices_centrums?
  • qh_RATIOconcavehorizon ratio of horizon vertex distance to qh.max_outside for concave, twisted new facets in qh_test_nonsimplicial_merge
  • qh_RATIOconvexmerge ratio of vertex distance to qh.min_vertex for clearly convex new facets in qh_test_nonsimplicial_merge
  • qh_RATIOcoplanarapex ratio of best distance for coplanar apex vs. vertex merge in qh_getpinchedmerges
  • qh_RATIOcoplanaroutside ratio to repartition a coplanar point as an outside point in qh_partitioncoplanar and qh_check_maxout
  • qh_RATIOmaxsimplex ratio for searching all points in qh_maxsimplex
  • qh_RATIOnearinside ratio for retaining inside points for qh_check_maxout
  • qh_RATIOpinchedsubridge ratio to qh.ONEmerge to accept vertices in qh_findbest_pinchedvertex
  • qh_RATIOtrypinched ratio to qh.ONEmerge to try qh_getpinchedmerges in qh_buildcone_mergepinched
  • qh_RATIOtwisted maximum ratio to qh.ONEmerge to merge twisted facets in qh_merge_twisted
  • qh_SEARCHdist when is facet coplanar with the best facet for qh_findbesthorizon
  • qh_USEfindbestnew when to use qh_findbestnew for qh_partitionpoint()
  • qh_WARNnarrow max. cosine in initial hull to warn about qh.NARROWhull
  • qh_WIDEcoplanar what is a wide facet
  • qh_WIDEduplicate merge ratio for errexit from qh_forcedmerges due to duplicate ridge
  • qh_WIDEridge merge ratio for selecting a forced dupridge merge
  • qh_WIDEmaxoutside precision ratio for maximum increase for qh.max_outside in qh_check_maxout
  • qh_WIDEmaxoutside2 precision ratio for maximum qh.max_outside in qh_check_maxout
  • qh_WIDEpinched merge ratio for distance between pinched vertices compared to current facet width for qh_getpinchedmerges and qh_next_vertexmerge
  • qh_ZEROdelaunay define facets that are ignored in Delaunay triangulations

»user_r.c functions

»usermem_r.c functions

  • qh_exit exit program, same as exit(). May be redefined as throw "QH10003.." by libqhullcpp/usermem_r-cpp.cpp
  • qh_fprintf_stderr print to stderr when qh.ferr is not defined.
  • qh_free free memory, same as free().
  • qh_malloc allocate memory, same as malloc()

»userprintf_r.c and userprintf_rbox,c functions

  • qh_fprintf print information from Qhull, sames as fprintf().
  • qh_fprintf_rbox print information from Rbox, sames as fprintf().


Up: Home page for Qhull (local)
Up: Qhull manual: contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTraceFunctions (local)
Up: Qhull code
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

qhull-2020.2/src/libqhull_r/qhull_r-exports.def0000644060175106010010000002115313710365751017754 0ustar bbarber; qhull_r-exports.def -- MSVC module-definition file ; ; Generated from depends.exe by cut-and-paste of exported symbols by mingw gcc ; [jan'14] 391 symbols ; ; Referenced by CMakeLists/add_library, libqhull_r.pro/DEF_FILE, ; and libqhull_r.vcxproj/Linker/Input/Module Definition File ; ; If qh_NOmerge, use qhull_r-nomerge-exports.def ; Created by -- grep -vE 'qh_all_merges|qh_appendmergeset|qh_basevertices|qh_check_dupridge|qh_checkconnect|qh_compare_facetmerge|qh_comparevisit|qh_copynonconvex|qh_degen_redundant_facet|qh_delridge_merge|qh_find_newvertex|qh_findbest_test|qh_findbestneighbor|qh_flippedmerges|qh_forcedmerges|qh_getmergeset|qh_getmergeset_initial|qh_hashridge|qh_hashridge_find|qh_makeridges|qh_mark_dupridges|qh_maydropneighbor|qh_merge_degenredundant|qh_merge_nonconvex|qh_mergecycle|qh_mergecycle_all|qh_mergecycle_facets|qh_mergecycle_neighbors|qh_mergecycle_ridges|qh_mergecycle_vneighbors|qh_mergefacet|qh_mergefacet2d|qh_mergeneighbors|qh_mergeridges|qh_mergesimplex|qh_mergevertex_del|qh_mergevertex_neighbors|qh_mergevertices|qh_nearcoplanar|qh_nearvertex|qh_neighbor_intersections|qh_newhashtable|qh_newvertex|qh_newvertices|qh_nextridge3d|qh_reducevertices|qh_redundant_vertex|qh_remove_extravertices|qh_rename_sharedvertex|qh_renameridgevertex|qh_renamevertex|qh_test_appendmerge|qh_test_degen_neighbors|qh_test_redundant_neighbors|qh_test_vneighbors|qh_tracemerge|qh_tracemerging|qh_triangulate_facet|qh_triangulate_link|qh_triangulate_mirror|qh_triangulate_null|qh_updatetested|qh_vertexridges|qh_vertexridges_facet|qh_willdelete' qhull_r-exports.def >qhull_r-nomerge-exports.def ; ; $Id: //main/2019/qhull/src/libqhull_r/qhull_r-exports.def#4 $$Change: 2967 $ ; $DateTime: 2020/06/05 16:33:18 $$Author: bbarber $ ; ; Define qhull_VERSION in CMakeLists.txt, Makefile, qhull-exports.def, qhull_p-exports.def, qhull_r-exports.def, and qhull-warn.pri VERSION 8.0 EXPORTS qh_addhash qh_addpoint qh_all_merges qh_allstatA qh_allstatB qh_allstatC qh_allstatD qh_allstatE qh_allstatE2 qh_allstatF qh_allstatG qh_allstatH qh_allstatI qh_allstatistics qh_appendfacet qh_appendmergeset qh_appendprint qh_appendvertex qh_argv_to_command qh_argv_to_command_size qh_attachnewfacets qh_backnormal qh_basevertices qh_build_withrestart qh_buildhull qh_buildtracing qh_check_bestdist qh_check_dupridge qh_check_maxout qh_check_output qh_check_point qh_check_points qh_checkconnect qh_checkconvex qh_checkdelridge qh_checkfacet qh_checkflags qh_checkflipped qh_checkflipped_all qh_checklists qh_checkpolygon qh_checkvertex qh_checkzero qh_clear_outputflags qh_clearcenters qh_clock qh_collectstatistics qh_compare_facetarea qh_compare_facetmerge qh_compare_facetvisit qh_compare_nummerge qh_comparevisit qh_copyfilename qh_copynonconvex qh_copypoints qh_countfacets qh_createsimplex qh_crossproduct qh_degen_redundant_facet qh_deletevisible qh_delfacet qh_delridge_merge qh_delvertex qh_determinant qh_detjoggle qh_detroundoff qh_detsimplex qh_detvnorm qh_detvridge qh_detvridge3 qh_dfacet qh_distnorm qh_distplane qh_distround qh_divzero qh_dvertex qh_eachvoronoi qh_eachvoronoi_all qh_errexit qh_errexit2 qh_errexit_rbox qh_errprint qh_exit qh_facet2point qh_facet3vertex qh_facetarea qh_facetarea_simplex qh_facetcenter qh_facetintersect qh_facetvertices qh_find_newvertex qh_findbest qh_findbest_test qh_findbestfacet qh_findbesthorizon qh_findbestlower qh_findbestneighbor qh_findbestnew qh_findfacet_all qh_findgood qh_findgood_all qh_findgooddist qh_findhorizon qh_flippedmerges qh_forcedmerges qh_fprintf qh_fprintf_rbox qh_fprintf_stderr qh_free qh_freebuffers qh_freebuild qh_freeqhull qh_furthestnext qh_furthestout qh_gausselim qh_geomplanes qh_getangle qh_getarea qh_getcenter qh_getcentrum qh_getdistance qh_gethash qh_getmergeset qh_getmergeset_initial qh_gram_schmidt qh_hashridge qh_hashridge_find qh_infiniteloop qh_init_A qh_init_B qh_init_qhull_command qh_initbuild qh_initflags qh_initialhull qh_initialvertices qh_initqhull_buffers qh_initqhull_globals qh_initqhull_mem qh_initqhull_outputflags qh_initqhull_start qh_initqhull_start2 qh_initstatistics qh_initthresholds qh_inthresholds qh_isvertex qh_joggle_restart qh_joggleinput qh_lib_check qh_makenew_nonsimplicial qh_makenew_simplicial qh_makenewfacet qh_makenewfacets qh_makenewplanes qh_makeridges qh_malloc qh_mark_dupridges qh_markkeep qh_markvoronoi qh_matchdupridge qh_matchneighbor qh_matchnewfacets qh_matchvertices qh_maxabsval qh_maxmin qh_maxouter qh_maxsimplex qh_maydropneighbor qh_memalloc qh_memfree qh_memfreeshort qh_meminit qh_meminitbuffers qh_memsetup qh_memsize qh_memstatistics qh_memtotal qh_merge_degenredundant qh_merge_nonconvex qh_mergecycle qh_mergecycle_all qh_mergecycle_facets qh_mergecycle_neighbors qh_mergecycle_ridges qh_mergecycle_vneighbors qh_mergefacet qh_mergefacet2d qh_mergeneighbors qh_mergeridges qh_mergesimplex qh_mergevertex_del qh_mergevertex_neighbors qh_mergevertices qh_minabsval qh_mindiff qh_nearcoplanar qh_nearvertex qh_neighbor_intersections qh_new_qhull qh_newfacet qh_newhashtable qh_newridge qh_newstats qh_newvertex qh_newvertices qh_nextfacet2d qh_nextfurthest qh_nextridge3d qh_normalize qh_normalize2 qh_nostatistic qh_option qh_order_vertexneighbors qh_orientoutside qh_out1 qh_out2n qh_out3n qh_outcoplanar qh_outerinner qh_partitionall qh_partitioncoplanar qh_partitionpoint qh_partitionvisible qh_point qh_point_add qh_pointdist qh_pointfacet qh_pointid qh_pointvertex qh_postmerge qh_premerge qh_prepare_output qh_prependfacet qh_printafacet qh_printallstatistics qh_printbegin qh_printcenter qh_printcentrum qh_printend qh_printend4geom qh_printextremes qh_printextremes_2d qh_printextremes_d qh_printfacet qh_printfacet2geom qh_printfacet2geom_points qh_printfacet2math qh_printfacet3geom_nonsimplicial qh_printfacet3geom_points qh_printfacet3geom_simplicial qh_printfacet3math qh_printfacet3vertex qh_printfacet4geom_nonsimplicial qh_printfacet4geom_simplicial qh_printfacetNvertex_nonsimplicial qh_printfacetNvertex_simplicial qh_printfacetheader qh_printfacetlist qh_printfacetridges qh_printfacets qh_printhashtable qh_printhelp_degenerate qh_printhelp_internal qh_printhelp_narrowhull qh_printhelp_singular qh_printhelp_topology qh_printhelp_wide qh_printhyperplaneintersection qh_printline3geom qh_printlists qh_printmatrix qh_printneighborhood qh_printpoint qh_printpoint3 qh_printpointid qh_printpoints qh_printpoints_out qh_printpointvect qh_printpointvect2 qh_printridge qh_printspheres qh_printstatistics qh_printstatlevel qh_printstats qh_printsummary qh_printvdiagram qh_printvdiagram2 qh_printvertex qh_printvertexlist qh_printvertices qh_printvneighbors qh_printvnorm qh_printvoronoi qh_printvridge qh_produce_output qh_produce_output2 qh_projectdim3 qh_projectinput qh_projectpoint qh_projectpoints qh_qhull qh_rand qh_randomfactor qh_randommatrix qh_rboxpoints qh_readfeasible qh_readpoints qh_reducevertices qh_redundant_vertex qh_remove_extravertices qh_removefacet qh_removevertex qh_rename_sharedvertex qh_renameridgevertex qh_renamevertex qh_resetlists qh_rotateinput qh_rotatepoints qh_roundi qh_scaleinput qh_scalelast qh_scalepoints qh_setaddnth qh_setaddsorted qh_setappend qh_setappend2ndlast qh_setappend_set qh_setcheck qh_setcompact qh_setcopy qh_setdel qh_setdelaunay qh_setdellast qh_setdelnth qh_setdelnthsorted qh_setdelsorted qh_setduplicate qh_setequal qh_setequal_except qh_setequal_skip qh_setfacetplane qh_setfeasible qh_setfree qh_setfree2 qh_setfreelong qh_sethalfspace qh_sethalfspace_all qh_sethyperplane_det qh_sethyperplane_gauss qh_setin qh_setindex qh_setlarger qh_setlarger_quick qh_setlast qh_setnew qh_setnew_delnthsorted qh_setprint qh_setreplace qh_setsize qh_settemp qh_settempfree qh_settempfree_all qh_settemppop qh_settemppush qh_settruncate qh_setunique qh_setvoronoi_all qh_setzero qh_sharpnewfacets qh_skipfacet qh_skipfilename qh_srand qh_stddev qh_strtod qh_strtol qh_test_appendmerge qh_test_degen_neighbors qh_test_redundant_neighbors qh_test_vneighbors qh_tracemerge qh_tracemerging qh_triangulate qh_triangulate_facet qh_triangulate_link qh_triangulate_mirror qh_triangulate_null qh_updatetested qh_update_vertexneighbors qh_update_vertexneighbors_cone qh_user_memsizes qh_version qh_version2 qh_vertexintersect qh_vertexintersect_new qh_vertexneighbors qh_vertexridges qh_vertexridges_facet qh_vertexsubset qh_voronoi_center qh_willdelete qh_zero qhull-2020.2/src/libqhull_r/qhull_r-nomerge-exports.def0000644060175106010010000001667613710365751021424 0ustar bbarber; qhull_r-exports.def --module-definition file ; ; Generated from depends.exe by cut-and-paste of exported symbols by mingw gcc ; [jan'14] 391 symbols ; Same as ../libqhullp/qhull-exports.def without DATA items (reentrant) ; ; Referenced by CMakeLists/add_library, libqhull_r.pro/DEF_FILE, ; and libqhull_r.vcxproj/Linker/Input/Module Definition File ; ; If qh_NOmerge, use qhull_r-nomerge-exports.def ; Created by -- grep -vE 'qh_all_merges|qh_appendmergeset|qh_basevertices|qh_check_dupridge|qh_checkconnect|qh_compare_facetmerge|qh_comparevisit|qh_copynonconvex|qh_degen_redundant_facet|qh_delridge_merge|qh_find_newvertex|qh_findbest_test|qh_findbestneighbor|qh_flippedmerges|qh_forcedmerges|qh_getmergeset|qh_getmergeset_initial|qh_hashridge|qh_hashridge_find|qh_makeridges|qh_mark_dupridges|qh_maydropneighbor|qh_merge_degenredundant|qh_merge_nonconvex|qh_mergecycle|qh_mergecycle_all|qh_mergecycle_facets|qh_mergecycle_neighbors|qh_mergecycle_ridges|qh_mergecycle_vneighbors|qh_mergefacet|qh_mergefacet2d|qh_mergeneighbors|qh_mergeridges|qh_mergesimplex|qh_mergevertex_del|qh_mergevertex_neighbors|qh_mergevertices|qh_nearcoplanar|qh_nearvertex|qh_neighbor_intersections|qh_newhashtable|qh_newvertex|qh_newvertices|qh_nextridge3d|qh_reducevertices|qh_redundant_vertex|qh_remove_extravertices|qh_rename_sharedvertex|qh_renameridgevertex|qh_renamevertex|qh_test_appendmerge|qh_test_degen_neighbors|qh_test_redundant_neighbors|qh_test_vneighbors|qh_tracemerge|qh_tracemerging|qh_triangulate_facet|qh_triangulate_link|qh_triangulate_mirror|qh_triangulate_null|qh_updatetested|qh_vertexridges|qh_vertexridges_facet|qh_willdelete' qhull_r-nomerge-exports.def >qhull_r-nomerge-exports.def ; ; $Id: //main/2019/qhull/src/libqhull_r/qhull_r-nomerge-exports.def#4 $$Change: 2967 $ ; $DateTime: 2020/06/05 16:33:18 $$Author: bbarber $ ; ; Define qhull_VERSION in CMakeLists.txt, Makefile, qhull-exports.def, qhull_p-exports.def, qhull_r-exports.def, and qhull-warn.pri VERSION 8.0 EXPORTS qh_addhash qh_addpoint qh_allstatA qh_allstatB qh_allstatC qh_allstatD qh_allstatE qh_allstatE2 qh_allstatF qh_allstatG qh_allstatH qh_allstatI qh_allstatistics qh_appendfacet qh_appendprint qh_appendvertex qh_argv_to_command qh_argv_to_command_size qh_attachnewfacets qh_backnormal qh_build_withrestart qh_buildhull qh_buildtracing qh_check_bestdist qh_check_maxout qh_check_output qh_check_point qh_check_points qh_checkconvex qh_checkdelridge qh_checkfacet qh_checkflags qh_checkflipped qh_checkflipped_all qh_checkpolygon qh_checkvertex qh_checkzero qh_clear_outputflags qh_clearcenters qh_clock qh_collectstatistics qh_compare_facetarea qh_compare_facetvisit qh_compare_nummerge qh_copyfilename qh_copypoints qh_countfacets qh_createsimplex qh_crossproduct qh_deletevisible qh_delfacet qh_delvertex qh_determinant qh_detjoggle qh_detroundoff qh_detsimplex qh_detvnorm qh_detvridge qh_detvridge3 qh_dfacet qh_distnorm qh_distplane qh_distround qh_divzero qh_dvertex qh_eachvoronoi qh_eachvoronoi_all qh_errexit qh_errexit2 qh_errexit_rbox qh_errprint qh_exit qh_facet2point qh_facet3vertex qh_facetarea qh_facetarea_simplex qh_facetcenter qh_facetintersect qh_facetvertices qh_findbest qh_findbestfacet qh_findbesthorizon qh_findbestlower qh_findbestnew qh_findfacet_all qh_findgood qh_findgood_all qh_findgooddist qh_findhorizon qh_fprintf qh_fprintf_rbox qh_fprintf_stderr qh_free qh_freebuffers qh_freebuild qh_freeqhull qh_furthestnext qh_furthestout qh_gausselim qh_geomplanes qh_getangle qh_getarea qh_getcenter qh_getcentrum qh_getdistance qh_gethash qh_gram_schmidt qh_infiniteloop qh_init_A qh_init_B qh_init_qhull_command qh_initbuild qh_initflags qh_initialhull qh_initialvertices qh_initqhull_buffers qh_initqhull_globals qh_initqhull_mem qh_initqhull_outputflags qh_initqhull_start qh_initqhull_start2 qh_initstatistics qh_initthresholds qh_inthresholds qh_isvertex qh_joggle_restart qh_joggleinput qh_lib_check qh_makenew_nonsimplicial qh_makenew_simplicial qh_makenewfacet qh_makenewfacets qh_makenewplanes qh_malloc qh_markkeep qh_markvoronoi qh_matchdupridge qh_matchneighbor qh_matchnewfacets qh_matchvertices qh_maxabsval qh_maxmin qh_maxouter qh_maxsimplex qh_memalloc qh_memfree qh_memfreeshort qh_meminit qh_meminitbuffers qh_memsetup qh_memsize qh_memstatistics qh_memtotal qh_minabsval qh_mindiff qh_new_qhull qh_newfacet qh_newridge qh_newstats qh_nextfacet2d qh_nextfurthest qh_normalize qh_normalize2 qh_nostatistic qh_option qh_order_vertexneighbors qh_orientoutside qh_out1 qh_out2n qh_out3n qh_outcoplanar qh_outerinner qh_partitionall qh_partitioncoplanar qh_partitionpoint qh_partitionvisible qh_point qh_point_add qh_pointdist qh_pointfacet qh_pointid qh_pointvertex qh_postmerge qh_premerge qh_prepare_output qh_prependfacet qh_printafacet qh_printallstatistics qh_printbegin qh_printcenter qh_printcentrum qh_printend qh_printend4geom qh_printextremes qh_printextremes_2d qh_printextremes_d qh_printfacet qh_printfacet2geom qh_printfacet2geom_points qh_printfacet2math qh_printfacet3geom_nonsimplicial qh_printfacet3geom_points qh_printfacet3geom_simplicial qh_printfacet3math qh_printfacet3vertex qh_printfacet4geom_nonsimplicial qh_printfacet4geom_simplicial qh_printfacetNvertex_nonsimplicial qh_printfacetNvertex_simplicial qh_printfacetheader qh_printfacetlist qh_printfacetridges qh_printfacets qh_printhashtable qh_printhelp_degenerate qh_printhelp_internal qh_printhelp_narrowhull qh_printhelp_singular qh_printhelp_topology qh_printhelp_wide qh_printhyperplaneintersection qh_printline3geom qh_printlists qh_printmatrix qh_printneighborhood qh_printpoint qh_printpoint3 qh_printpointid qh_printpoints qh_printpoints_out qh_printpointvect qh_printpointvect2 qh_printridge qh_printspheres qh_printstatistics qh_printstatlevel qh_printstats qh_printsummary qh_printvdiagram qh_printvdiagram2 qh_printvertex qh_printvertexlist qh_printvertices qh_printvneighbors qh_printvnorm qh_printvoronoi qh_printvridge qh_produce_output qh_produce_output2 qh_projectdim3 qh_projectinput qh_projectpoint qh_projectpoints qh_qhull qh_rand qh_randomfactor qh_randommatrix qh_rboxpoints qh_readfeasible qh_readpoints qh_removefacet qh_removevertex qh_resetlists qh_rotateinput qh_rotatepoints qh_roundi qh_scaleinput qh_scalelast qh_scalepoints qh_setaddnth qh_setaddsorted qh_setappend qh_setappend2ndlast qh_setappend_set qh_setcheck qh_setcompact qh_setcopy qh_setdel qh_setdelaunay qh_setdellast qh_setdelnth qh_setdelnthsorted qh_setdelsorted qh_setduplicate qh_setequal qh_setequal_except qh_setequal_skip qh_setfacetplane qh_setfeasible qh_setfree qh_setfree2 qh_setfreelong qh_sethalfspace qh_sethalfspace_all qh_sethyperplane_det qh_sethyperplane_gauss qh_setin qh_setindex qh_setlarger qh_setlarger_quick qh_setlast qh_setnew qh_setnew_delnthsorted qh_setprint qh_setreplace qh_setsize qh_settemp qh_settempfree qh_settempfree_all qh_settemppop qh_settemppush qh_settruncate qh_setunique qh_setvoronoi_all qh_setzero qh_sharpnewfacets qh_skipfacet qh_skipfilename qh_srand qh_stddev qh_strtod qh_strtol qh_triangulate qh_update_vertexneighbors qh_update_vertexneighbors_cone qh_user_memsizes qh_version qh_version2 qh_vertexintersect qh_vertexintersect_new qh_vertexneighbors qh_vertexsubset qh_voronoi_center qh_zero qhull-2020.2/src/libqhull_r/qhull_ra.h0000644060175106010010000001253713661631132016104 0ustar bbarber/*
  ---------------------------------

   qhull_ra.h
   all header files for compiling qhull with reentrant code
   included before C++ headers for user_r.h:QHULL_CRTDBG

   see qh-qhull.htm

   see libqhull_r.h for user-level definitions

   see user_r.h for user-definable constants

   defines internal functions for libqhull_r.c global_r.c

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull_r/qhull_ra.h#2 $$Change: 2953 $
   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $

   Notes:  grep for ((" and (" to catch fprintf("lkasdjf");
           full parens around (x?y:z)
           use '#include "libqhull_r/qhull_ra.h"' to avoid name clashes
*/

#ifndef qhDEFqhulla
#define qhDEFqhulla 1

#include "libqhull_r.h"  /* Includes user_r.h and data types */

#include "stat_r.h"
#include "random_r.h"
#include "mem_r.h"
#include "qset_r.h"
#include "geom_r.h"
#include "merge_r.h"
#include "poly_r.h"
#include "io_r.h"

#include 
#include 
#include 
#include     /* some compilers will not need float.h */
#include 
#include 
#include 
#include 
#include 
/*** uncomment here and qset_r.c
     if string.h does not define memcpy()
#include 
*/

#if qh_CLOCKtype == 2  /* defined in user_r.h from libqhull_r.h */
#include 
#include 
#include 
#endif

#ifdef _MSC_VER  /* Microsoft Visual C++ -- warning level 4 */
#pragma warning( disable : 4100)  /* unreferenced formal parameter */
#pragma warning( disable : 4127)  /* conditional expression is constant */
#pragma warning( disable : 4706)  /* assignment within conditional function */
#pragma warning( disable : 4996)  /* function was declared deprecated(strcpy, localtime, etc.) */
#endif

/* ======= -macros- =========== */

/*----------------------------------

  traceN((qh, qh->ferr, 0Nnnn, "format\n", vars));
    calls qh_fprintf if qh.IStracing >= N

    Add debugging traps to the end of qh_fprintf

  notes:
    removing tracing reduces code size but doesn't change execution speed
*/
#ifndef qh_NOtrace
#define trace0(args) {if (qh->IStracing) qh_fprintf args;}
#define trace1(args) {if (qh->IStracing >= 1) qh_fprintf args;}
#define trace2(args) {if (qh->IStracing >= 2) qh_fprintf args;}
#define trace3(args) {if (qh->IStracing >= 3) qh_fprintf args;}
#define trace4(args) {if (qh->IStracing >= 4) qh_fprintf args;}
#define trace5(args) {if (qh->IStracing >= 5) qh_fprintf args;}
#else /* qh_NOtrace */
#define trace0(args) {}
#define trace1(args) {}
#define trace2(args) {}
#define trace3(args) {}
#define trace4(args) {}
#define trace5(args) {}
#endif /* qh_NOtrace */

/*----------------------------------

  Define an unused variable to avoid compiler warnings

  Derived from Qt's corelib/global/qglobal.h

*/

#if defined(__cplusplus) && defined(__INTEL_COMPILER) && !defined(QHULL_OS_WIN)
template 
inline void qhullUnused(T &x) { (void)x; }
#  define QHULL_UNUSED(x) qhullUnused(x);
#else
#  define QHULL_UNUSED(x) (void)x;
#endif

#ifdef __cplusplus
extern "C" {
#endif

/***** -libqhull_r.c prototypes (alphabetical after qhull) ********************/

void    qh_qhull(qhT *qh);
boolT   qh_addpoint(qhT *qh, pointT *furthest, facetT *facet, boolT checkdist);
void    qh_build_withrestart(qhT *qh);
vertexT *qh_buildcone(qhT *qh, pointT *furthest, facetT *facet, int goodhorizon, facetT **retryfacet);
boolT   qh_buildcone_mergepinched(qhT *qh, vertexT *apex, facetT *facet, facetT **retryfacet);
boolT   qh_buildcone_onlygood(qhT *qh, vertexT *apex, int goodhorizon);
void    qh_buildhull(qhT *qh);
void    qh_buildtracing(qhT *qh, pointT *furthest, facetT *facet);
void    qh_errexit2(qhT *qh, int exitcode, facetT *facet, facetT *otherfacet);
void    qh_findhorizon(qhT *qh, pointT *point, facetT *facet, int *goodvisible,int *goodhorizon);
pointT *qh_nextfurthest(qhT *qh, facetT **visible);
void    qh_partitionall(qhT *qh, setT *vertices, pointT *points,int npoints);
void    qh_partitioncoplanar(qhT *qh, pointT *point, facetT *facet, realT *dist, boolT allnew);
void    qh_partitionpoint(qhT *qh, pointT *point, facetT *facet);
void    qh_partitionvisible(qhT *qh, boolT allpoints, int *numpoints);
void    qh_joggle_restart(qhT *qh, const char *reason);
void    qh_printsummary(qhT *qh, FILE *fp);

/***** -global_r.c internal prototypes (alphabetical) ***********************/

void    qh_appendprint(qhT *qh, qh_PRINT format);
void    qh_freebuild(qhT *qh, boolT allmem);
void    qh_freebuffers(qhT *qh);
void    qh_initbuffers(qhT *qh, coordT *points, int numpoints, int dim, boolT ismalloc);

/***** -stat_r.c internal prototypes (alphabetical) ***********************/

void    qh_allstatA(qhT *qh);
void    qh_allstatB(qhT *qh);
void    qh_allstatC(qhT *qh);
void    qh_allstatD(qhT *qh);
void    qh_allstatE(qhT *qh);
void    qh_allstatE2(qhT *qh);
void    qh_allstatF(qhT *qh);
void    qh_allstatG(qhT *qh);
void    qh_allstatH(qhT *qh);
void    qh_freebuffers(qhT *qh);
void    qh_initbuffers(qhT *qh, coordT *points, int numpoints, int dim, boolT ismalloc);

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* qhDEFqhulla */
qhull-2020.2/src/libqhull_r/qset_r.c0000644060175106010010000010655713661631132015573 0ustar  bbarber/*
  ---------------------------------

   qset_r.c
   implements set manipulations needed for quickhull

   see qh-set_r.htm and qset_r.h

   Be careful of strict aliasing (two pointers of different types
   that reference the same location).  The last slot of a set is
   either the actual size of the set plus 1, or the NULL terminator
   of the set (i.e., setelemT).

   Only reference qh for qhmem or qhstat.  Otherwise the matching code in qset.c will bring in qhT

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull_r/qset_r.c#8 $$Change: 2953 $
   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
*/

#include "libqhull_r.h" /* for qhT and QHULL_CRTDBG */
#include "qset_r.h"
#include "mem_r.h"
#include 
#include 
/*** uncomment here and qhull_ra.h
     if string.h does not define memcpy()
#include 
*/

#ifndef qhDEFlibqhull
typedef struct ridgeT ridgeT;
typedef struct facetT facetT;
void    qh_errexit(qhT *qh, int exitcode, facetT *, ridgeT *);
void    qh_fprintf(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... );
#  ifdef _MSC_VER  /* Microsoft Visual C++ -- warning level 4 */
#  pragma warning( disable : 4127)  /* conditional expression is constant */
#  pragma warning( disable : 4706)  /* assignment within conditional function */
#  endif
#endif

/*=============== internal macros ===========================*/

/*============ functions in alphabetical order ===================*/

/*----------------------------------

  qh_setaddnth(qh, setp, nth, newelem )
    adds newelem as n'th element of sorted or unsorted *setp

  notes:
    *setp and newelem must be defined
    *setp may be a temp set
    nth=0 is first element
    errors if nth is out of bounds

  design:
    expand *setp if empty or full
    move tail of *setp up one
    insert newelem
*/
void qh_setaddnth(qhT *qh, setT **setp, int nth, void *newelem) {
  int oldsize, i;
  setelemT *sizep;          /* avoid strict aliasing */
  setelemT *oldp, *newp;

  if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {
    qh_setlarger(qh, setp);
    sizep= SETsizeaddr_(*setp);
  }
  oldsize= sizep->i - 1;
  if (nth < 0 || nth > oldsize) {
    qh_fprintf(qh, qh->qhmem.ferr, 6171, "qhull internal error (qh_setaddnth): nth %d is out-of-bounds for set:\n", nth);
    qh_setprint(qh, qh->qhmem.ferr, "", *setp);
    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
  }
  sizep->i++;
  oldp= (setelemT *)SETelemaddr_(*setp, oldsize, void);   /* NULL */
  newp= oldp+1;
  for (i=oldsize-nth+1; i--; )  /* move at least NULL  */
    (newp--)->p= (oldp--)->p;       /* may overwrite *sizep */
  newp->p= newelem;
} /* setaddnth */


/*----------------------------------

  setaddsorted( setp, newelem )
    adds an newelem into sorted *setp

  notes:
    *setp and newelem must be defined
    *setp may be a temp set
    nop if newelem already in set

  design:
    find newelem's position in *setp
    insert newelem
*/
void qh_setaddsorted(qhT *qh, setT **setp, void *newelem) {
  int newindex=0;
  void *elem, **elemp;

  FOREACHelem_(*setp) {          /* could use binary search instead */
    if (elem < newelem)
      newindex++;
    else if (elem == newelem)
      return;
    else
      break;
  }
  qh_setaddnth(qh, setp, newindex, newelem);
} /* setaddsorted */


/*---------------------------------

  qh_setappend(qh, setp, newelem )
    append newelem to *setp

  notes:
    *setp may be a temp set
    *setp and newelem may be NULL

  design:
    expand *setp if empty or full
    append newelem to *setp

*/
void qh_setappend(qhT *qh, setT **setp, void *newelem) {
  setelemT *sizep;  /* Avoid strict aliasing.  Writing to *endp may overwrite *sizep */
  setelemT *endp;
  int count;

  if (!newelem)
    return;
  if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {
    qh_setlarger(qh, setp);
    sizep= SETsizeaddr_(*setp);
  }
  count= (sizep->i)++ - 1;
  endp= (setelemT *)SETelemaddr_(*setp, count, void);
  (endp++)->p= newelem;
  endp->p= NULL;
} /* setappend */

/*---------------------------------

  qh_setappend_set(qh, setp, setA )
    appends setA to *setp

  notes:
    *setp can not be a temp set
    *setp and setA may be NULL

  design:
    setup for copy
    expand *setp if it is too small
    append all elements of setA to *setp
*/
void qh_setappend_set(qhT *qh, setT **setp, setT *setA) {
  int sizeA, size;
  setT *oldset;
  setelemT *sizep;

  if (!setA)
    return;
  SETreturnsize_(setA, sizeA);
  if (!*setp)
    *setp= qh_setnew(qh, sizeA);
  sizep= SETsizeaddr_(*setp);
  if (!(size= sizep->i))
    size= (*setp)->maxsize;
  else
    size--;
  if (size + sizeA > (*setp)->maxsize) {
    oldset= *setp;
    *setp= qh_setcopy(qh, oldset, sizeA);
    qh_setfree(qh, &oldset);
    sizep= SETsizeaddr_(*setp);
  }
  if (sizeA > 0) {
    sizep->i= size+sizeA+1;   /* memcpy may overwrite */
    memcpy((char *)&((*setp)->e[size].p), (char *)&(setA->e[0].p), (size_t)(sizeA+1) * SETelemsize);
  }
} /* setappend_set */


/*---------------------------------

  qh_setappend2ndlast(qh, setp, newelem )
    makes newelem the next to the last element in *setp

  notes:
    *setp must have at least one element
    newelem must be defined
    *setp may be a temp set

  design:
    expand *setp if empty or full
    move last element of *setp up one
    insert newelem
*/
void qh_setappend2ndlast(qhT *qh, setT **setp, void *newelem) {
    setelemT *sizep;  /* Avoid strict aliasing.  Writing to *endp may overwrite *sizep */
    setelemT *endp, *lastp;
    int count;

    if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {
        qh_setlarger(qh, setp);
        sizep= SETsizeaddr_(*setp);
    }
    count= (sizep->i)++ - 1;
    endp= (setelemT *)SETelemaddr_(*setp, count, void); /* NULL */
    lastp= endp-1;
    *(endp++)= *lastp;
    endp->p= NULL;    /* may overwrite *sizep */
    lastp->p= newelem;
} /* setappend2ndlast */

/*---------------------------------

  qh_setcheck(qh, set, typename, id )
    check set for validity
    report errors with typename and id

  design:
    checks that maxsize, actual size, and NULL terminator agree
*/
void qh_setcheck(qhT *qh, setT *set, const char *tname, unsigned int id) {
  int maxsize, size;
  int waserr= 0;

  if (!set)
    return;
  SETreturnsize_(set, size);
  maxsize= set->maxsize;
  if (size > maxsize || !maxsize) {
    qh_fprintf(qh, qh->qhmem.ferr, 6172, "qhull internal error (qh_setcheck): actual size %d of %s%d is greater than max size %d\n",
             size, tname, id, maxsize);
    waserr= 1;
  }else if (set->e[size].p) {
    qh_fprintf(qh, qh->qhmem.ferr, 6173, "qhull internal error (qh_setcheck): %s%d(size %d max %d) is not null terminated.\n",
             tname, id, size-1, maxsize);
    waserr= 1;
  }
  if (waserr) {
    qh_setprint(qh, qh->qhmem.ferr, "ERRONEOUS", set);
    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
  }
} /* setcheck */


/*---------------------------------

  qh_setcompact(qh, set )
    remove internal NULLs from an unsorted set

  returns:
    updated set

  notes:
    set may be NULL
    it would be faster to swap tail of set into holes, like qh_setdel

  design:
    setup pointers into set
    skip NULLs while copying elements to start of set
    update the actual size
*/
void qh_setcompact(qhT *qh, setT *set) {
  int size;
  void **destp, **elemp, **endp, **firstp;

  if (!set)
    return;
  SETreturnsize_(set, size);
  destp= elemp= firstp= SETaddr_(set, void);
  endp= destp + size;
  while (1) {
    if (!(*destp++= *elemp++)) {
      destp--;
      if (elemp > endp)
        break;
    }
  }
  qh_settruncate(qh, set, (int)(destp-firstp));   /* WARN64 */
} /* setcompact */


/*---------------------------------

  qh_setcopy(qh, set, extra )
    make a copy of a sorted or unsorted set with extra slots

  returns:
    new set

  design:
    create a newset with extra slots
    copy the elements to the newset

*/
setT *qh_setcopy(qhT *qh, setT *set, int extra) {
  setT *newset;
  int size;

  if (extra < 0)
    extra= 0;
  SETreturnsize_(set, size);
  newset= qh_setnew(qh, size+extra);
  SETsizeaddr_(newset)->i= size+1;    /* memcpy may overwrite */
  memcpy((char *)&(newset->e[0].p), (char *)&(set->e[0].p), (size_t)(size+1) * SETelemsize);
  return(newset);
} /* setcopy */


/*---------------------------------

  qh_setdel(set, oldelem )
    delete oldelem from an unsorted set

  returns:
    returns oldelem if found
    returns NULL otherwise

  notes:
    set may be NULL
    oldelem must not be NULL;
    only deletes one copy of oldelem in set

  design:
    locate oldelem
    update actual size if it was full
    move the last element to the oldelem's location
*/
void *qh_setdel(setT *set, void *oldelem) {
  setelemT *sizep;
  setelemT *elemp;
  setelemT *lastp;

  if (!set)
    return NULL;
  elemp= (setelemT *)SETaddr_(set, void);
  while (elemp->p != oldelem && elemp->p)
    elemp++;
  if (elemp->p) {
    sizep= SETsizeaddr_(set);
    if (!(sizep->i)--)         /*  if was a full set */
      sizep->i= set->maxsize;  /*     *sizep= (maxsize-1)+ 1 */
    lastp= (setelemT *)SETelemaddr_(set, sizep->i-1, void);
    elemp->p= lastp->p;      /* may overwrite itself */
    lastp->p= NULL;
    return oldelem;
  }
  return NULL;
} /* setdel */


/*---------------------------------

  qh_setdellast( set )
    return last element of set or NULL

  notes:
    deletes element from set
    set may be NULL

  design:
    return NULL if empty
    if full set
      delete last element and set actual size
    else
      delete last element and update actual size
*/
void *qh_setdellast(setT *set) {
  int setsize;  /* actually, actual_size + 1 */
  int maxsize;
  setelemT *sizep;
  void *returnvalue;

  if (!set || !(set->e[0].p))
    return NULL;
  sizep= SETsizeaddr_(set);
  if ((setsize= sizep->i)) {
    returnvalue= set->e[setsize - 2].p;
    set->e[setsize - 2].p= NULL;
    sizep->i--;
  }else {
    maxsize= set->maxsize;
    returnvalue= set->e[maxsize - 1].p;
    set->e[maxsize - 1].p= NULL;
    sizep->i= maxsize;
  }
  return returnvalue;
} /* setdellast */


/*---------------------------------

  qh_setdelnth(qh, set, nth )
    deletes nth element from unsorted set
    0 is first element

  returns:
    returns the element (needs type conversion)

  notes:
    errors if nth invalid

  design:
    setup points and check nth
    delete nth element and overwrite with last element
*/
void *qh_setdelnth(qhT *qh, setT *set, int nth) {
  void *elem;
  setelemT *sizep;
  setelemT *elemp, *lastp;

  sizep= SETsizeaddr_(set);
  if ((sizep->i--)==0)         /*  if was a full set */
    sizep->i= set->maxsize;    /*    *sizep= (maxsize-1)+ 1 */
  if (nth < 0 || nth >= sizep->i) {
    qh_fprintf(qh, qh->qhmem.ferr, 6174, "qhull internal error (qh_setdelnth): nth %d is out-of-bounds for set:\n", nth);
    qh_setprint(qh, qh->qhmem.ferr, "", set);
    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
  }
  elemp= (setelemT *)SETelemaddr_(set, nth, void); /* nth valid by QH6174 */
  lastp= (setelemT *)SETelemaddr_(set, sizep->i-1, void);
  elem= elemp->p;
  elemp->p= lastp->p;      /* may overwrite itself */
  lastp->p= NULL;
  return elem;
} /* setdelnth */

/*---------------------------------

  qh_setdelnthsorted(qh, set, nth )
    deletes nth element from sorted set

  returns:
    returns the element (use type conversion)

  notes:
    errors if nth invalid

  see also:
    setnew_delnthsorted

  design:
    setup points and check nth
    copy remaining elements down one
    update actual size
*/
void *qh_setdelnthsorted(qhT *qh, setT *set, int nth) {
  void *elem;
  setelemT *sizep;
  setelemT *newp, *oldp;

  sizep= SETsizeaddr_(set);
  if (nth < 0 || (sizep->i && nth >= sizep->i-1) || nth >= set->maxsize) {
    qh_fprintf(qh, qh->qhmem.ferr, 6175, "qhull internal error (qh_setdelnthsorted): nth %d is out-of-bounds for set:\n", nth);
    qh_setprint(qh, qh->qhmem.ferr, "", set);
    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
  }
  newp= (setelemT *)SETelemaddr_(set, nth, void);
  elem= newp->p;
  oldp= newp+1;
  while (((newp++)->p= (oldp++)->p))
    ; /* copy remaining elements and NULL */
  if ((sizep->i--)==0)         /*  if was a full set */
    sizep->i= set->maxsize;  /*     *sizep= (max size-1)+ 1 */
  return elem;
} /* setdelnthsorted */


/*---------------------------------

  qh_setdelsorted( set, oldelem )
    deletes oldelem from sorted set

  returns:
    returns oldelem if it was deleted

  notes:
    set may be NULL

  design:
    locate oldelem in set
    copy remaining elements down one
    update actual size
*/
void *qh_setdelsorted(setT *set, void *oldelem) {
  setelemT *sizep;
  setelemT *newp, *oldp;

  if (!set)
    return NULL;
  newp= (setelemT *)SETaddr_(set, void);
  while(newp->p != oldelem && newp->p)
    newp++;
  if (newp->p) {
    oldp= newp+1;
    while (((newp++)->p= (oldp++)->p))
      ; /* copy remaining elements */
    sizep= SETsizeaddr_(set);
    if ((sizep->i--)==0)    /*  if was a full set */
      sizep->i= set->maxsize;  /*     *sizep= (max size-1)+ 1 */
    return oldelem;
  }
  return NULL;
} /* setdelsorted */


/*---------------------------------

  qh_setduplicate(qh, set, elemsize )
    duplicate a set of elemsize elements

  notes:
    use setcopy if retaining old elements

  design:
    create a new set
    for each elem of the old set
      create a newelem
      append newelem to newset
*/
setT *qh_setduplicate(qhT *qh, setT *set, int elemsize) {
  void          *elem, **elemp, *newElem;
  setT          *newSet;
  int           size;

  if (!(size= qh_setsize(qh, set)))
    return NULL;
  newSet= qh_setnew(qh, size);
  FOREACHelem_(set) {
    newElem= qh_memalloc(qh, elemsize);
    memcpy(newElem, elem, (size_t)elemsize);
    qh_setappend(qh, &newSet, newElem);
  }
  return newSet;
} /* setduplicate */


/*---------------------------------

  qh_setendpointer( set )
    Returns pointer to NULL terminator of a set's elements
    set can not be NULL

*/
void **qh_setendpointer(setT *set) {

  setelemT *sizep= SETsizeaddr_(set);
  int n= sizep->i;
  return (n ? &set->e[n-1].p : &sizep->p);
} /* qh_setendpointer */

/*---------------------------------

  qh_setequal( setA, setB )
    returns 1 if two sorted sets are equal, otherwise returns 0

  notes:
    either set may be NULL

  design:
    check size of each set
    setup pointers
    compare elements of each set
*/
int qh_setequal(setT *setA, setT *setB) {
  void **elemAp, **elemBp;
  int sizeA= 0, sizeB= 0;

  if (setA) {
    SETreturnsize_(setA, sizeA);
  }
  if (setB) {
    SETreturnsize_(setB, sizeB);
  }
  if (sizeA != sizeB)
    return 0;
  if (!sizeA)
    return 1;
  elemAp= SETaddr_(setA, void);
  elemBp= SETaddr_(setB, void);
  if (!memcmp((char *)elemAp, (char *)elemBp, (size_t)(sizeA * SETelemsize)))
    return 1;
  return 0;
} /* setequal */


/*---------------------------------

  qh_setequal_except( setA, skipelemA, setB, skipelemB )
    returns 1 if sorted setA and setB are equal except for skipelemA & B

  returns:
    false if either skipelemA or skipelemB are missing

  notes:
    neither set may be NULL

    if skipelemB is NULL,
      can skip any one element of setB

  design:
    setup pointers
    search for skipelemA, skipelemB, and mismatches
    check results
*/
int qh_setequal_except(setT *setA, void *skipelemA, setT *setB, void *skipelemB) {
  void **elemA, **elemB;
  int skip=0;

  elemA= SETaddr_(setA, void);
  elemB= SETaddr_(setB, void);
  while (1) {
    if (*elemA == skipelemA) {
      skip++;
      elemA++;
    }
    if (skipelemB) {
      if (*elemB == skipelemB) {
        skip++;
        elemB++;
      }
    }else if (*elemA != *elemB) {
      skip++;
      if (!(skipelemB= *elemB++))
        return 0;
    }
    if (!*elemA)
      break;
    if (*elemA++ != *elemB++)
      return 0;
  }
  if (skip != 2 || *elemB)
    return 0;
  return 1;
} /* setequal_except */


/*---------------------------------

  qh_setequal_skip( setA, skipA, setB, skipB )
    returns 1 if sorted setA and setB are equal except for elements skipA & B

  returns:
    false if different size

  notes:
    neither set may be NULL

  design:
    setup pointers
    search for mismatches while skipping skipA and skipB
*/
int qh_setequal_skip(setT *setA, int skipA, setT *setB, int skipB) {
  void **elemA, **elemB, **skipAp, **skipBp;

  elemA= SETaddr_(setA, void);
  elemB= SETaddr_(setB, void);
  skipAp= SETelemaddr_(setA, skipA, void);
  skipBp= SETelemaddr_(setB, skipB, void);
  while (1) {
    if (elemA == skipAp)
      elemA++;
    if (elemB == skipBp)
      elemB++;
    if (!*elemA)
      break;
    if (*elemA++ != *elemB++)
      return 0;
  }
  if (*elemB)
    return 0;
  return 1;
} /* setequal_skip */


/*---------------------------------

  qh_setfree(qh, setp )
    frees the space occupied by a sorted or unsorted set

  returns:
    sets setp to NULL

  notes:
    set may be NULL

  design:
    free array
    free set
*/
void qh_setfree(qhT *qh, setT **setp) {
  int size;
  void **freelistp;  /* used if !qh_NOmem by qh_memfree_() */

  if (*setp) {
    size= (int)sizeof(setT) + ((*setp)->maxsize)*SETelemsize;
    if (size <= qh->qhmem.LASTsize) {
      qh_memfree_(qh, *setp, size, freelistp);
    }else
      qh_memfree(qh, *setp, size);
    *setp= NULL;
  }
} /* setfree */


/*---------------------------------

  qh_setfree2(qh, setp, elemsize )
    frees the space occupied by a set and its elements

  notes:
    set may be NULL

  design:
    free each element
    free set
*/
void qh_setfree2(qhT *qh, setT **setp, int elemsize) {
  void          *elem, **elemp;

  FOREACHelem_(*setp)
    qh_memfree(qh, elem, elemsize);
  qh_setfree(qh, setp);
} /* setfree2 */



/*---------------------------------

  qh_setfreelong(qh, setp )
    frees a set only if it's in long memory

  returns:
    sets setp to NULL if it is freed

  notes:
    set may be NULL

  design:
    if set is large
      free it
*/
void qh_setfreelong(qhT *qh, setT **setp) {
  int size;

  if (*setp) {
    size= (int)sizeof(setT) + ((*setp)->maxsize)*SETelemsize;
    if (size > qh->qhmem.LASTsize) {
      qh_memfree(qh, *setp, size);
      *setp= NULL;
    }
  }
} /* setfreelong */


/*---------------------------------

  qh_setin( set, setelem )
    returns 1 if setelem is in a set, 0 otherwise

  notes:
    set may be NULL or unsorted

  design:
    scans set for setelem
*/
int qh_setin(setT *set, void *setelem) {
  void *elem, **elemp;

  FOREACHelem_(set) {
    if (elem == setelem)
      return 1;
  }
  return 0;
} /* setin */


/*---------------------------------

  qh_setindex(set, atelem )
    returns the index of atelem in set.
    returns -1, if not in set or maxsize wrong

  notes:
    set may be NULL and may contain nulls.
    NOerrors returned (qh_pointid, QhullPoint::id)

  design:
    checks maxsize
    scans set for atelem
*/
int qh_setindex(setT *set, void *atelem) {
  void **elem;
  int size, i;

  if (!set)
    return -1;
  SETreturnsize_(set, size);
  if (size > set->maxsize)
    return -1;
  elem= SETaddr_(set, void);
  for (i=0; i < size; i++) {
    if (*elem++ == atelem)
      return i;
  }
  return -1;
} /* setindex */


/*---------------------------------

  qh_setlarger(qh, oldsetp )
    returns a larger set that contains all elements of *oldsetp

  notes:
    if long memory,
      the new set is 2x larger
    if qhmem.LASTsize is between 1.5x and 2x
      the new set is qhmem.LASTsize
    otherwise use quick memory,
      the new set is 2x larger, rounded up to next qh_memsize
       
    if temp set, updates qh->qhmem.tempstack

  design:
    creates a new set
    copies the old set to the new set
    updates pointers in tempstack
    deletes the old set
*/
void qh_setlarger(qhT *qh, setT **oldsetp) {
  int setsize= 1, newsize;
  setT *newset, *set, **setp, *oldset;
  setelemT *sizep;
  setelemT *newp, *oldp;

  if (*oldsetp) {
    oldset= *oldsetp;
    SETreturnsize_(oldset, setsize);
    qh->qhmem.cntlarger++;
    qh->qhmem.totlarger += setsize+1;
    qh_setlarger_quick(qh, setsize, &newsize);
    newset= qh_setnew(qh, newsize);
    oldp= (setelemT *)SETaddr_(oldset, void);
    newp= (setelemT *)SETaddr_(newset, void);
    memcpy((char *)newp, (char *)oldp, (size_t)(setsize+1) * SETelemsize);
    sizep= SETsizeaddr_(newset);
    sizep->i= setsize+1;
    FOREACHset_((setT *)qh->qhmem.tempstack) {
      if (set == oldset)
        *(setp-1)= newset;
    }
    qh_setfree(qh, oldsetp);
  }else
    newset= qh_setnew(qh, 3);
  *oldsetp= newset;
} /* setlarger */


/*---------------------------------

  qh_setlarger_quick(qh, setsize, newsize )
    determine newsize for setsize
    returns True if newsize fits in quick memory

  design:
    if 2x fits into quick memory
      return True, 2x
    if x+4 does not fit into quick memory
      return False, 2x
    if x+x/3 fits into quick memory
      return True, the last quick set
    otherwise
      return False, 2x
*/
int qh_setlarger_quick(qhT *qh, int setsize, int *newsize) {
    int lastquickset;

    *newsize= 2 * setsize;
    lastquickset= (qh->qhmem.LASTsize - (int)sizeof(setT)) / SETelemsize; /* matches size computation in qh_setnew */
    if (*newsize <= lastquickset)
      return 1;
    if (setsize + 4 > lastquickset)
      return 0;
    if (setsize + setsize/3 <= lastquickset) {
      *newsize= lastquickset;
      return 1;
    }
    return 0;
} /* setlarger_quick */

/*---------------------------------

  qh_setlast( set )
    return last element of set or NULL (use type conversion)

  notes:
    set may be NULL

  design:
    return last element
*/
void *qh_setlast(setT *set) {
  int size;

  if (set) {
    size= SETsizeaddr_(set)->i;
    if (!size)
      return SETelem_(set, set->maxsize - 1);
    else if (size > 1)
      return SETelem_(set, size - 2);
  }
  return NULL;
} /* setlast */


/*---------------------------------

  qh_setnew(qh, setsize )
    creates and allocates space for a set

  notes:
    setsize means the number of elements (!including the NULL terminator)
    use qh_settemp/qh_setfreetemp if set is temporary

  design:
    allocate memory for set
    roundup memory if small set
    initialize as empty set
*/
setT *qh_setnew(qhT *qh, int setsize) {
  setT *set;
  int sizereceived; /* used if !qh_NOmem */
  int size;
  void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */

  if (!setsize)
    setsize++;
  size= (int)sizeof(setT) + setsize * SETelemsize; /* setT includes NULL terminator, see qh.LASTquickset */
  if (size>0 && size <= qh->qhmem.LASTsize) {
    qh_memalloc_(qh, size, freelistp, set, setT);
#ifndef qh_NOmem
    sizereceived= qh->qhmem.sizetable[ qh->qhmem.indextable[size]];
    if (sizereceived > size)
      setsize += (sizereceived - size)/SETelemsize;
#endif
  }else
    set= (setT *)qh_memalloc(qh, size);
  set->maxsize= setsize;
  set->e[setsize].i= 1;
  set->e[0].p= NULL;
  return(set);
} /* setnew */


/*---------------------------------

  qh_setnew_delnthsorted(qh, set, size, nth, prepend )
    creates a sorted set not containing nth element
    if prepend, the first prepend elements are undefined

  notes:
    set must be defined
    checks nth
    see also: setdelnthsorted

  design:
    create new set
    setup pointers and allocate room for prepend'ed entries
    append head of old set to new set
    append tail of old set to new set
*/
setT *qh_setnew_delnthsorted(qhT *qh, setT *set, int size, int nth, int prepend) {
  setT *newset;
  void **oldp, **newp;
  int tailsize= size - nth -1, newsize;

  if (tailsize < 0) {
    qh_fprintf(qh, qh->qhmem.ferr, 6176, "qhull internal error (qh_setnew_delnthsorted): nth %d is out-of-bounds for set:\n", nth);
    qh_setprint(qh, qh->qhmem.ferr, "", set);
    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
  }
  newsize= size-1 + prepend;
  newset= qh_setnew(qh, newsize);
  newset->e[newset->maxsize].i= newsize+1;  /* may be overwritten */
  oldp= SETaddr_(set, void);
  newp= SETaddr_(newset, void) + prepend;
  switch (nth) {
  case 0:
    break;
  case 1:
    *(newp++)= *oldp++;
    break;
  case 2:
    *(newp++)= *oldp++;
    *(newp++)= *oldp++;
    break;
  case 3:
    *(newp++)= *oldp++;
    *(newp++)= *oldp++;
    *(newp++)= *oldp++;
    break;
  case 4:
    *(newp++)= *oldp++;
    *(newp++)= *oldp++;
    *(newp++)= *oldp++;
    *(newp++)= *oldp++;
    break;
  default:
    memcpy((char *)newp, (char *)oldp, (size_t)nth * SETelemsize);
    newp += nth;
    oldp += nth;
    break;
  }
  oldp++;
  switch (tailsize) {
  case 0:
    break;
  case 1:
    *(newp++)= *oldp++;
    break;
  case 2:
    *(newp++)= *oldp++;
    *(newp++)= *oldp++;
    break;
  case 3:
    *(newp++)= *oldp++;
    *(newp++)= *oldp++;
    *(newp++)= *oldp++;
    break;
  case 4:
    *(newp++)= *oldp++;
    *(newp++)= *oldp++;
    *(newp++)= *oldp++;
    *(newp++)= *oldp++;
    break;
  default:
    memcpy((char *)newp, (char *)oldp, (size_t)tailsize * SETelemsize);
    newp += tailsize;
  }
  *newp= NULL;
  return(newset);
} /* setnew_delnthsorted */


/*---------------------------------

  qh_setprint(qh, fp, string, set )
    print set elements to fp with identifying string

  notes:
    never errors
*/
void qh_setprint(qhT *qh, FILE *fp, const char* string, setT *set) {
  int size, k;

  if (!set)
    qh_fprintf(qh, fp, 9346, "%s set is null\n", string);
  else {
    SETreturnsize_(set, size);
    qh_fprintf(qh, fp, 9347, "%s set=%p maxsize=%d size=%d elems=",
             string, set, set->maxsize, size);
    if (size > set->maxsize)
      size= set->maxsize+1;
    for (k=0; k < size; k++)
      qh_fprintf(qh, fp, 9348, " %p", set->e[k].p);
    qh_fprintf(qh, fp, 9349, "\n");
  }
} /* setprint */

/*---------------------------------

  qh_setreplace(qh, set, oldelem, newelem )
    replaces oldelem in set with newelem

  notes:
    errors if oldelem not in the set
    newelem may be NULL, but it turns the set into an indexed set (no FOREACH)

  design:
    find oldelem
    replace with newelem
*/
void qh_setreplace(qhT *qh, setT *set, void *oldelem, void *newelem) {
  void **elemp;

  elemp= SETaddr_(set, void);
  while (*elemp != oldelem && *elemp)
    elemp++;
  if (*elemp)
    *elemp= newelem;
  else {
    qh_fprintf(qh, qh->qhmem.ferr, 6177, "qhull internal error (qh_setreplace): elem %p not found in set\n",
       oldelem);
    qh_setprint(qh, qh->qhmem.ferr, "", set);
    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
  }
} /* setreplace */


/*---------------------------------

  qh_setsize(qh, set )
    returns the size of a set

  notes:
    errors if set's maxsize is incorrect
    same as SETreturnsize_(set)
    same code for qh_setsize [qset_r.c] and QhullSetBase::count
    if first element is NULL, SETempty_() is True but qh_setsize may be greater than 0

  design:
    determine actual size of set from maxsize
*/
int qh_setsize(qhT *qh, setT *set) {
  int size;
  setelemT *sizep;

  if (!set)
    return(0);
  sizep= SETsizeaddr_(set);
  if ((size= sizep->i)) {
    size--;
    if (size > set->maxsize) {
      qh_fprintf(qh, qh->qhmem.ferr, 6178, "qhull internal error (qh_setsize): current set size %d is greater than maximum size %d\n",
               size, set->maxsize);
      qh_setprint(qh, qh->qhmem.ferr, "set: ", set);
      qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
    }
  }else
    size= set->maxsize;
  return size;
} /* setsize */

/*---------------------------------

  qh_settemp(qh, setsize )
    return a stacked, temporary set of up to setsize elements

  notes:
    use settempfree or settempfree_all to release from qh->qhmem.tempstack
    see also qh_setnew

  design:
    allocate set
    append to qh->qhmem.tempstack

*/
setT *qh_settemp(qhT *qh, int setsize) {
  setT *newset;

  newset= qh_setnew(qh, setsize);
  qh_setappend(qh, &qh->qhmem.tempstack, newset);
  if (qh->qhmem.IStracing >= 5)
    qh_fprintf(qh, qh->qhmem.ferr, 8123, "qh_settemp: temp set %p of %d elements, depth %d\n",
       newset, newset->maxsize, qh_setsize(qh, qh->qhmem.tempstack));
  return newset;
} /* settemp */

/*---------------------------------

  qh_settempfree(qh, set )
    free temporary set at top of qh->qhmem.tempstack

  notes:
    nop if set is NULL
    errors if set not from previous   qh_settemp

  to locate errors:
    use 'T2' to find source and then find mis-matching qh_settemp

  design:
    check top of qh->qhmem.tempstack
    free it
*/
void qh_settempfree(qhT *qh, setT **set) {
  setT *stackedset;

  if (!*set)
    return;
  stackedset= qh_settemppop(qh);
  if (stackedset != *set) {
    qh_settemppush(qh, stackedset);
    qh_fprintf(qh, qh->qhmem.ferr, 6179, "qhull internal error (qh_settempfree): set %p(size %d) was not last temporary allocated(depth %d, set %p, size %d)\n",
             *set, qh_setsize(qh, *set), qh_setsize(qh, qh->qhmem.tempstack)+1,
             stackedset, qh_setsize(qh, stackedset));
    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
  }
  qh_setfree(qh, set);
} /* settempfree */

/*---------------------------------

  qh_settempfree_all(qh)
    free all temporary sets in qh->qhmem.tempstack

  design:
    for each set in tempstack
      free set
    free qh->qhmem.tempstack
*/
void qh_settempfree_all(qhT *qh) {
  setT *set, **setp;

  FOREACHset_(qh->qhmem.tempstack)
    qh_setfree(qh, &set);
  qh_setfree(qh, &qh->qhmem.tempstack);
} /* settempfree_all */

/*---------------------------------

  qh_settemppop(qh)
    pop and return temporary set from qh->qhmem.tempstack

  notes:
    the returned set is permanent

  design:
    pop and check top of qh->qhmem.tempstack
*/
setT *qh_settemppop(qhT *qh) {
  setT *stackedset;

  stackedset= (setT *)qh_setdellast(qh->qhmem.tempstack);
  if (!stackedset) {
    qh_fprintf(qh, qh->qhmem.ferr, 6180, "qhull internal error (qh_settemppop): pop from empty temporary stack\n");
    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
  }
  if (qh->qhmem.IStracing >= 5)
    qh_fprintf(qh, qh->qhmem.ferr, 8124, "qh_settemppop: depth %d temp set %p of %d elements\n",
       qh_setsize(qh, qh->qhmem.tempstack)+1, stackedset, qh_setsize(qh, stackedset));
  return stackedset;
} /* settemppop */

/*---------------------------------

  qh_settemppush(qh, set )
    push temporary set unto qh->qhmem.tempstack (makes it temporary)

  notes:
    duplicates settemp() for tracing

  design:
    append set to tempstack
*/
void qh_settemppush(qhT *qh, setT *set) {
  if (!set) {
    qh_fprintf(qh, qh->qhmem.ferr, 6267, "qhull error (qh_settemppush): can not push a NULL temp\n");
    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
  }
  qh_setappend(qh, &qh->qhmem.tempstack, set);
  if (qh->qhmem.IStracing >= 5)
    qh_fprintf(qh, qh->qhmem.ferr, 8125, "qh_settemppush: depth %d temp set %p of %d elements\n",
      qh_setsize(qh, qh->qhmem.tempstack), set, qh_setsize(qh, set));
} /* settemppush */


/*---------------------------------

  qh_settruncate(qh, set, size )
    truncate set to size elements

  notes:
    set must be defined

  see:
    SETtruncate_

  design:
    check size
    update actual size of set
*/
void qh_settruncate(qhT *qh, setT *set, int size) {

  if (size < 0 || size > set->maxsize) {
    qh_fprintf(qh, qh->qhmem.ferr, 6181, "qhull internal error (qh_settruncate): size %d out of bounds for set:\n", size);
    qh_setprint(qh, qh->qhmem.ferr, "", set);
    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
  }
  set->e[set->maxsize].i= size+1;   /* maybe overwritten */
  set->e[size].p= NULL;
} /* settruncate */

/*---------------------------------

  qh_setunique(qh, set, elem )
    add elem to unsorted set unless it is already in set

  notes:
    returns 1 if it is appended

  design:
    if elem not in set
      append elem to set
*/
int qh_setunique(qhT *qh, setT **set, void *elem) {

  if (!qh_setin(*set, elem)) {
    qh_setappend(qh, set, elem);
    return 1;
  }
  return 0;
} /* setunique */

/*---------------------------------

  qh_setzero(qh, set, index, size )
    zero elements from index on
    set actual size of set to size

  notes:
    set must be defined
    the set becomes an indexed set (can not use FOREACH...)

  see also:
    qh_settruncate

  design:
    check index and size
    update actual size
    zero elements starting at e[index]
*/
void qh_setzero(qhT *qh, setT *set, int idx, int size) {
  int count;

  if (idx < 0 || idx >= size || size > set->maxsize) {
    qh_fprintf(qh, qh->qhmem.ferr, 6182, "qhull internal error (qh_setzero): index %d or size %d out of bounds for set:\n", idx, size);
    qh_setprint(qh, qh->qhmem.ferr, "", set);
    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
  }
  set->e[set->maxsize].i=  size+1;  /* may be overwritten */
  count= size - idx + 1;   /* +1 for NULL terminator */
  memset((char *)SETelemaddr_(set, idx, void), 0, (size_t)count * SETelemsize);
} /* setzero */


qhull-2020.2/src/libqhull_r/qset_r.h0000644060175106010010000003647313661631132015577 0ustar  bbarber/*
  ---------------------------------

   qset_r.h
     header file for qset_r.c that implements set

   see qh-set_r.htm and qset_r.c

   only uses mem_r.c, malloc/free

   for error handling, writes message and calls
      qh_errexit(qhT *qh, qhmem_ERRqhull, NULL, NULL);

   set operations satisfy the following properties:
    - sets have a max size, the actual size (if different) is stored at the end
    - every set is NULL terminated
    - sets may be sorted or unsorted, the caller must distinguish this

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull_r/qset_r.h#4 $$Change: 2953 $
   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
*/

#ifndef qhDEFset
#define qhDEFset 1

#include 

/*================= -structures- ===============*/

#ifndef DEFsetT
#define DEFsetT 1
typedef struct setT setT;   /* a set is a sorted or unsorted array of pointers */
#endif

#ifndef DEFqhT
#define DEFqhT 1
typedef struct qhT qhT;          /* defined in libqhull_r.h */
#endif

/* [jan'15] Decided not to use countT.  Most sets are small.  The code uses signed tests */

/*------------------------------------------

setT
  a set or list of pointers with maximum size and actual size.

variations:
  unsorted, unique   -- a list of unique pointers with NULL terminator
                           user guarantees uniqueness
  sorted             -- a sorted list of unique pointers with NULL terminator
                           qset_r.c guarantees uniqueness
  unsorted           -- a list of pointers terminated with NULL
  indexed            -- an array of pointers with NULL elements

structure for set of n elements:

        --------------
        |  maxsize
        --------------
        |  e[0] - a pointer, may be NULL for indexed sets
        --------------
        |  e[1]

        --------------
        |  ...
        --------------
        |  e[n-1]
        --------------
        |  e[n] = NULL
        --------------
        |  ...
        --------------
        |  e[maxsize] - n+1 or NULL (determines actual size of set)
        --------------

*/

/*-- setelemT -- internal type to allow both pointers and indices
*/
typedef union setelemT setelemT;
union setelemT {
  void    *p;
  int   i;         /* integer used for e[maxSize] */
};

struct setT {
  int maxsize;          /* maximum number of elements (except NULL) */
  setelemT e[1];        /* array of pointers, tail is NULL */
                        /* last slot (unless NULL) is actual size+1
                           e[maxsize]==NULL or e[e[maxsize]-1]==NULL */
                        /* this may generate a warning since e[] contains
                           maxsize elements */
};

/*=========== -constants- =========================*/

/*-------------------------------------

  SETelemsize
    size of a set element in bytes
*/
#define SETelemsize ((int)sizeof(setelemT))


/*=========== -macros- =========================*/

/*-------------------------------------

   FOREACHsetelement_(type, set, variable)
     define FOREACH iterator

   declare:
     assumes *variable and **variablep are declared
     no space in "variable)" [DEC Alpha cc compiler]

   each iteration:
     variable is set element
     variablep is one beyond variable.

   to repeat an element:
     variablep--; / *repeat* /

   at exit:
     variable is NULL at end of loop

   example:
     #define FOREACHfacet_(facets) FOREACHsetelement_(facetT, facets, facet)

   notes:
     use FOREACHsetelement_i_() if need index or include NULLs
     assumes set is not modified

   WARNING:
     nested loops can't use the same variable (define another FOREACH)

     needs braces if nested inside another FOREACH
     this includes intervening blocks, e.g. FOREACH...{ if () FOREACH...} )
*/
#define FOREACHsetelement_(type, set, variable) \
        if (((variable= NULL), set)) for (\
          variable##p= (type **)&((set)->e[0].p); \
          (variable= *variable##p++);)

/*------------------------------------------

   FOREACHsetelement_i_(qh, type, set, variable)
     define indexed FOREACH iterator

   declare:
     type *variable, variable_n, variable_i;

   each iteration:
     variable is set element, may be NULL
     variable_i is index, variable_n is qh_setsize()

   to repeat an element:
     variable_i--; variable_n-- repeats for deleted element

   at exit:
     variable==NULL and variable_i==variable_n

   example:
     #define FOREACHfacet_i_(qh, facets) FOREACHsetelement_i_(qh, facetT, facets, facet)

   WARNING:
     nested loops can't use the same variable (define another FOREACH)

     needs braces if nested inside another FOREACH
     this includes intervening blocks, e.g. FOREACH...{ if () FOREACH...} )
*/
#define FOREACHsetelement_i_(qh, type, set, variable) \
        if (((variable= NULL), set)) for (\
          variable##_i= 0, variable= (type *)((set)->e[0].p), \
                   variable##_n= qh_setsize(qh, set);\
          variable##_i < variable##_n;\
          variable= (type *)((set)->e[++variable##_i].p) )

/*----------------------------------------

   FOREACHsetelementreverse_(qh, type, set, variable)-
     define FOREACH iterator in reverse order

   declare:
     assumes *variable and **variablep are declared
     also declare '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_(qh, type, set, variable) \
        if (((variable= NULL), set)) for (\
           variable##temp= qh_setsize(qh, set)-1, variable= qh_setlast(qh, set);\
           variable; variable= \
           ((--variable##temp >= 0) ? SETelemt_(set, variable##temp, type) : NULL))

/*-------------------------------------

   FOREACHsetelementreverse12_(type, set, variable)-
     define FOREACH iterator with e[1] and e[0] reversed

   declare:
     assumes *variable and **variablep are declared

   each iteration:
     variable is set element
     variablep is one after variable.

   to repeat an element:
     variablep--; / *repeat* /

   at exit:
     variable is NULL at end of loop

   example
     #define FOREACHvertexreverse12_(vertices) FOREACHsetelementreverse12_(vertexT, vertices, vertex)

   notes:
     WARNING: needs braces if nested inside another FOREACH
*/
#define FOREACHsetelementreverse12_(type, set, variable) \
        if (((variable= NULL), set)) for (\
          variable##p= (type **)&((set)->e[1].p); \
          (variable= *variable##p); \
          variable##p == ((type **)&((set)->e[0].p))?variable##p += 2: \
              (variable##p == ((type **)&((set)->e[1].p))?variable##p--:variable##p++))

/*-------------------------------------

   FOREACHelem_( set )-
     iterate elements in a set

   declare:
     void *elem, *elemp;

   each iteration:
     elem is set element
     elemp is one beyond

   to repeat an element:
     elemp--; / *repeat* /

   at exit:
     elem == NULL at end of loop

   example:
     FOREACHelem_(set) {

   notes:
     assumes set is not modified
     WARNING: needs braces if nested inside another FOREACH
*/
#define FOREACHelem_(set) FOREACHsetelement_(void, set, elem)

/*-------------------------------------

   FOREACHset_( set )-
     iterate a set of sets

   declare:
     setT *set, **setp;

   each iteration:
     set is set element
     setp is one beyond

   to repeat an element:
     setp--; / *repeat* /

   at exit:
     set == NULL at end of loop

   example
     FOREACHset_(sets) {

   notes:
     WARNING: needs braces if nested inside another FOREACH
*/
#define FOREACHset_(sets) FOREACHsetelement_(setT, sets, set)

/*-------------------------------------------

   SETindex_( set, elem )
     return index of elem in set

   notes:
     for use with FOREACH iteration
     WARN64 -- Maximum set size is 2G

   example:
     i= SETindex_(ridges, ridge)
*/
#define SETindex_(set, elem) ((int)((void **)elem##p - (void **)&(set)->e[1].p))

/*-----------------------------------------

   SETref_( elem )
     l.h.s. for modifying the current element in a FOREACH iteration

   example:
     SETref_(ridge)= anotherridge;
*/
#define SETref_(elem) (elem##p[-1])

/*-----------------------------------------

   SETelem_(set, n)
     return the n'th element of set

   notes:
      assumes that n is valid [0..size] and that set is defined
      use SETelemt_() for type cast
*/
#define SETelem_(set, n)           ((set)->e[n].p)

/*-----------------------------------------

   SETelemt_(set, n, type)
     return the n'th element of set as a type

   notes:
      assumes that n is valid [0..size] and that set is defined
*/
#define SETelemt_(set, n, type)    ((type *)((set)->e[n].p))

/*-----------------------------------------

   SETelemaddr_(set, n, type)
     return address of the n'th element of a set

   notes:
      assumes that n is valid [0..size] and set is defined
*/
#define SETelemaddr_(set, n, type) ((type **)(&((set)->e[n].p)))

/*-----------------------------------------

   SETfirst_(set)
     return first element of set

*/
#define SETfirst_(set)             ((set)->e[0].p)

/*-----------------------------------------

   SETfirstt_(set, type)
     return first element of set as a type

*/
#define SETfirstt_(set, type)      ((type *)((set)->e[0].p))

/*-----------------------------------------

   SETsecond_(set)
     return second element of set

*/
#define SETsecond_(set)            ((set)->e[1].p)

/*-----------------------------------------

   SETsecondt_(set, type)
     return second element of set as a type
*/
#define SETsecondt_(set, type)     ((type *)((set)->e[1].p))

/*-----------------------------------------

   SETaddr_(set, type)
       return address of set's elements
*/
#define SETaddr_(set,type)         ((type **)(&((set)->e[0].p)))

/*-----------------------------------------

   SETreturnsize_(set, size)
     return size of a set

   notes:
      set must be defined
      use qh_setsize(qhT *qh, set) unless speed is critical
*/
#define SETreturnsize_(set, size) (((size)= ((set)->e[(set)->maxsize].i))?(--(size)):((size)= (set)->maxsize))

/*-----------------------------------------

   SETempty_(set)
     return true(1) if set is empty (i.e., FOREACHsetelement_ is empty)

   notes:
      set may be NULL
      qh_setsize may be non-zero if first element is NULL
*/
#define SETempty_(set)            (!set || (SETfirst_(set) ? 0 : 1))

/*---------------------------------

  SETsizeaddr_(set)
    return pointer to 'actual size+1' of set (set CANNOT be NULL!!)
    Its type is setelemT* for strict aliasing
    All SETelemaddr_ must be cast to setelemT


  notes:
    *SETsizeaddr==NULL or e[*SETsizeaddr-1].p==NULL
*/
#define SETsizeaddr_(set) (&((set)->e[(set)->maxsize]))

/*-----------------------------------------

   SETtruncate_(set, size)
     truncate set to size

   see:
     qh_settruncate()

*/
#define SETtruncate_(set, size) {set->e[set->maxsize].i= size+1; /* maybe overwritten */ \
      set->e[size].p= NULL;}

/*======= prototypes in alphabetical order ============*/

#ifdef __cplusplus
extern "C" {
#endif

void  qh_setaddsorted(qhT *qh, setT **setp, void *elem);
void  qh_setaddnth(qhT *qh, setT **setp, int nth, void *newelem);
void  qh_setappend(qhT *qh, setT **setp, void *elem);
void  qh_setappend_set(qhT *qh, setT **setp, setT *setA);
void  qh_setappend2ndlast(qhT *qh, setT **setp, void *elem);
void  qh_setcheck(qhT *qh, setT *set, const char *tname, unsigned int id);
void  qh_setcompact(qhT *qh, setT *set);
setT *qh_setcopy(qhT *qh, setT *set, int extra);
void *qh_setdel(setT *set, void *elem);
void *qh_setdellast(setT *set);
void *qh_setdelnth(qhT *qh, setT *set, int nth);
void *qh_setdelnthsorted(qhT *qh, setT *set, int nth);
void *qh_setdelsorted(setT *set, void *newelem);
setT *qh_setduplicate(qhT *qh, setT *set, int elemsize);
void **qh_setendpointer(setT *set);
int   qh_setequal(setT *setA, setT *setB);
int   qh_setequal_except(setT *setA, void *skipelemA, setT *setB, void *skipelemB);
int   qh_setequal_skip(setT *setA, int skipA, setT *setB, int skipB);
void  qh_setfree(qhT *qh, setT **set);
void  qh_setfree2(qhT *qh, setT **setp, int elemsize);
void  qh_setfreelong(qhT *qh, setT **set);
int   qh_setin(setT *set, void *setelem);
int   qh_setindex(setT *set, void *setelem);
void  qh_setlarger(qhT *qh, setT **setp);
int   qh_setlarger_quick(qhT *qh, int setsize, int *newsize);
void *qh_setlast(setT *set);
setT *qh_setnew(qhT *qh, int size);
setT *qh_setnew_delnthsorted(qhT *qh, setT *set, int size, int nth, int prepend);
void  qh_setprint(qhT *qh, FILE *fp, const char* string, setT *set);
void  qh_setreplace(qhT *qh, setT *set, void *oldelem, void *newelem);
int   qh_setsize(qhT *qh, setT *set);
setT *qh_settemp(qhT *qh, int setsize);
void  qh_settempfree(qhT *qh, setT **set);
void  qh_settempfree_all(qhT *qh);
setT *qh_settemppop(qhT *qh);
void  qh_settemppush(qhT *qh, setT *set);
void  qh_settruncate(qhT *qh, setT *set, int size);
int   qh_setunique(qhT *qh, setT **set, void *elem);
void  qh_setzero(qhT *qh, setT *set, int idx, int size);

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* qhDEFset */
qhull-2020.2/src/libqhull_r/random_r.c0000644060175106010010000001470313476022031016062 0ustar  bbarber/*
  ---------------------------------

   random_r.c and utilities
     Park & Miller's minimimal standard random number generator
     argc/argv conversion

     Used by rbox.  Do not use 'qh' 
*/

#include "libqhull_r.h"
#include "random_r.h"

#include 
#include 
#include 

#ifdef _MSC_VER  /* Microsoft Visual C++ -- warning level 4 */
#pragma warning( disable : 4706)  /* assignment within conditional function */
#pragma warning( disable : 4996)  /* function was declared deprecated(strcpy, localtime, etc.) */
#endif

/*---------------------------------

  qh_argv_to_command( argc, argv, command, max_size )

    build command from argc/argv
    max_size is at least

  returns:
    a space-delimited string of options (just as typed)
    returns false if max_size is too short

  notes:
    silently removes
    makes option string easy to input and output
    matches qh_argv_to_command_size
    argc may be 0
*/
int qh_argv_to_command(int argc, char *argv[], char* command, int max_size) {
  int i, remaining;
  char *s;
  *command= '\0';  /* max_size > 0 */

  if (argc) {
    if ((s= strrchr( argv[0], '\\')) /* get filename w/o .exe extension */
    || (s= strrchr( argv[0], '/')))
        s++;
    else
        s= argv[0];
    if ((int)strlen(s) < max_size)   /* WARN64 */
        strcpy(command, s);
    else
        goto error_argv;
    if ((s= strstr(command, ".EXE"))
    ||  (s= strstr(command, ".exe")))
        *s= '\0';
  }
  for (i=1; i < argc; i++) {
    s= argv[i];
    remaining= max_size - (int)strlen(command) - (int)strlen(s) - 2;   /* WARN64 */
    if (!*s || strchr(s, ' ')) {
      char *t= command + strlen(command);
      remaining -= 2;
      if (remaining < 0) {
        goto error_argv;
      }
      *t++= ' ';
      *t++= '"';
      while (*s) {
        if (*s == '"') {
          if (--remaining < 0)
            goto error_argv;
          *t++= '\\';
        }
        *t++= *s++;
      }
      *t++= '"';
      *t= '\0';
    }else if (remaining < 0) {
      goto error_argv;
    }else {
      strcat(command, " ");
      strcat(command, s);
    }
  }
  return 1;

error_argv:
  return 0;
} /* argv_to_command */

/*---------------------------------

  qh_argv_to_command_size( argc, argv )

    return size to allocate for qh_argv_to_command()

  notes:
    only called from rbox with qh_errexit not enabled
    caller should report error if returned size is less than 1
    argc may be 0
    actual size is usually shorter
*/
int qh_argv_to_command_size(int argc, char *argv[]) {
    int count= 1; /* null-terminator if argc==0 */
    int i;
    char *s;

    for (i=0; i0 && strchr(argv[i], ' ')) {
        count += 2;  /* quote delimiters */
        for (s=argv[i]; *s; s++) {
          if (*s == '"') {
            count++;
          }
        }
      }
    }
    return count;
} /* argv_to_command_size */

/*---------------------------------

  qh_rand()
  qh_srand(qh, seed )
    generate pseudo-random number between 1 and 2^31 -2

  notes:
    For qhull and rbox, called from qh_RANDOMint(),etc. [user_r.h]

    From Park & Miller's minimal 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
*/

/* Global variables and constants */

#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 qh_rand(qhT *qh) {
    int lo, hi, test;
    int seed= qh->last_random;

    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->last_random= seed;
    /* seed= seed < qh_RANDOMmax/2 ? 0 : qh_RANDOMmax;  for testing */
    /* seed= qh_RANDOMmax;  for testing */
    return seed;
} /* rand */

void qh_srand(qhT *qh, int seed) {
    if (seed < 1)
        qh->last_random= 1;
    else if (seed >= qh_rand_m)
        qh->last_random= qh_rand_m - 1;
    else
        qh->last_random= seed;
} /* qh_srand */

/*---------------------------------

qh_randomfactor(qh, scale, offset )
  return a random factor r * scale + offset

notes:
  qh.RANDOMa/b are defined in global_r.c
  qh_RANDOMint requires 'qh'
*/
realT qh_randomfactor(qhT *qh, realT scale, realT offset) {
    realT randr;

    randr= qh_RANDOMint;
    return randr * scale + offset;
} /* randomfactor */

/*---------------------------------

  qh_randommatrix(qh, 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

  notes:
    qh_RANDOMint requires 'qh'
*/
void qh_randommatrix(qhT *qh, 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 */

/*---------------------------------

  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);     /* WARN64 */
  if (s< (*endp) && (*endp)[-1] == ' ')
    (*endp)--;
  return result;
} /* strtol */
qhull-2020.2/src/libqhull_r/random_r.h0000644060175106010010000000206213661631132016066 0ustar  bbarber/*
  ---------------------------------

  random_r.h
    header file for random and utility routines

   see qh-geom_r.htm and random_r.c

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull_r/random_r.h#3 $$Change: 2953 $
   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
*/

#ifndef qhDEFrandom
#define qhDEFrandom 1

#include "libqhull_r.h"

/*============= prototypes in alphabetical order ======= */

#ifdef __cplusplus
extern "C" {
#endif

int     qh_argv_to_command(int argc, char *argv[], char* command, int max_size);
int     qh_argv_to_command_size(int argc, char *argv[]);
int     qh_rand(qhT *qh);
void    qh_srand(qhT *qh, int seed);
realT   qh_randomfactor(qhT *qh, realT scale, realT offset);
void    qh_randommatrix(qhT *qh, realT *buffer, int dim, realT **row);
int     qh_strtol(const char *s, char **endp);
double  qh_strtod(const char *s, char **endp);

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* qhDEFrandom */



qhull-2020.2/src/libqhull_r/rboxlib_r.c0000644060175106010010000006303413505222600016241 0ustar  bbarber/*
  ---------------------------------

   rboxlib_r.c
     Generate input points

   notes:
     For documentation, see prompt[] of rbox_r.c
     50 points generated for 'rbox D4'

   WARNING:
     incorrect range if qh_RANDOMmax is defined wrong (user_r.h)
*/

#include "libqhull_r.h"  /* First for user_r.h */
#include "random_r.h"

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#ifdef _MSC_VER  /* Microsoft Visual C++ */
#pragma warning( disable : 4706)  /* assignment within conditional expression. */
#pragma warning( disable : 4996)  /* this function (strncat,sprintf,strcpy) or variable may be unsafe. */
#endif

#define MAXdim 200
#define PI 3.1415926535897932384

/* ------------------------------ prototypes ----------------*/
int qh_roundi(qhT *qh, double a);
void qh_out1(qhT *qh, double a);
void qh_out2n(qhT *qh, double a, double b);
void qh_out3n(qhT *qh, double a, double b, double c);
void qh_outcoord(qhT *qh, int iscdd, double *coord, int dim);
void qh_outcoincident(qhT *qh, int coincidentpoints, double radius, int iscdd, double *coord, int dim);
void qh_rboxpoints2(qhT *qh, char* rbox_command, double **simplex);

void    qh_fprintf_rbox(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... );
void    qh_free(void *mem);
void   *qh_malloc(size_t size);
int     qh_rand(qhT *qh);
void    qh_srand(qhT *qh, int seed);

/*---------------------------------

  qh_rboxpoints(qh, rbox_command )
    Generate points to qh.fout according to rbox options
    Report errors on qh.ferr

  returns:
    0 (qh_ERRnone) on success
    1 (qh_ERRinput) on input error
    4 (qh_ERRmem) on memory error
    5 (qh_ERRqhull) on internal error

  notes:
    To avoid using stdio, redefine qh_malloc, qh_free, and qh_fprintf_rbox (user_r.c)
    Split out qh_rboxpoints2() to avoid -Wclobbered

  design:
    Straight line code (consider defining a struct and functions):

    Parse arguments into variables
    Determine the number of points
    Generate the points
*/
int qh_rboxpoints(qhT *qh, char* rbox_command) {
  int exitcode;
  double *simplex;

  simplex= NULL;
  exitcode= setjmp(qh->rbox_errexit);
  if (exitcode) {
    /* same code for error exit and normal return.  qh.NOerrexit is set */
    if (simplex)
      qh_free(simplex);
    return exitcode;
  }
  qh_rboxpoints2(qh, rbox_command, &simplex);
  /* same code for error exit and normal return */
  if (simplex)
    qh_free(simplex);
  return qh_ERRnone;
} /* rboxpoints */

void qh_rboxpoints2(qhT *qh, char* rbox_command, double **simplex) {
  int i,j,k;
  int gendim;
  int coincidentcount=0, coincidenttotal=0, coincidentpoints=0;
  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;
  int israndom=0, istime=0;
  int isbox=0, issimplex=0, issimplex2=0, ismesh=0;
  double width=0.0, gap=0.0, radius=0.0, coincidentradius=0.0;
  double coord[MAXdim], offset, meshm=3.0, meshn=4.0, meshr=5.0;
  double *coordp, *simplexp;
  int nthroot, mult[MAXdim];
  double norm, factor, randr, rangap, tempr, 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[250], seedbuf[50];
  char *s=command, *t, *first_point=NULL;
  time_t timedata;

  *command= '\0';
  strncat(command, rbox_command, sizeof(command)-sizeof(seedbuf)-strlen(command)-1);

  while (*s && !isspace(*s))  /* skip program name */
    s++;
  while (*s) {
    while (*s && isspace(*s))
      s++;
    if (*s == '-')
      s++;
    if (!*s)
      break;
    if (isdigit(*s)) {
      numpoints= qh_strtol(s, &s);
      continue;
    }
    /* ============= read flags =============== */
    switch (*s++) {
    case 'c':
      addcube= 1;
      t= s;
      while (isspace(*t))
        t++;
      if (*t == 'G')
        cube= qh_strtod(++t, &s);
      break;
    case 'd':
      adddiamond= 1;
      t= s;
      while (isspace(*t))
        t++;
      if (*t == 'G')
        diamond= qh_strtod(++t, &s);
      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(*s)) {
        seed= qh_strtol(s, &s);
        israndom= 0;
      }else
        israndom= 1;
      break;
    case 'x':
      issimplex= 1;
      break;
    case 'y':
      issimplex2= 1;
      break;
    case 'z':
      qh->rbox_isinteger= 1;
      break;
    case 'B':
      box= qh_strtod(s, &s);
      isbox= 1;
      break;
    case 'C':
      if (*s)
        coincidentpoints=  qh_strtol(s, &s);
      if (*s == ',') {
        ++s;
        coincidentradius=  qh_strtod(s, &s);
      }
      if (*s == ',') {
        ++s;
        coincidenttotal=  qh_strtol(s, &s);
      }
      if (*s && !isspace(*s)) {
        qh_fprintf_rbox(qh, qh->ferr, 7080, "rbox error: arguments for 'Cn,r,m' are not 'int', 'float', and 'int'.  Remaining string is '%s'\n", s);
        qh_errexit_rbox(qh, qh_ERRinput);
      }
      if (coincidentpoints==0){
        qh_fprintf_rbox(qh, qh->ferr, 6268, "rbox error: missing arguments for 'Cn,r,m' where n is the number of coincident points, r is the radius (default 0.0), and m is the number of points\n");
        qh_errexit_rbox(qh, qh_ERRinput);
      }
      if (coincidentpoints<0 || coincidenttotal<0 || coincidentradius<0.0){
        qh_fprintf_rbox(qh, qh->ferr, 6269, "rbox error: negative arguments for 'Cn,m,r' where n (%d) is the number of coincident points, m (%d) is the number of points, and r (%.2g) is the radius (default 0.0)\n", coincidentpoints, coincidenttotal, coincidentradius);
        qh_errexit_rbox(qh, qh_ERRinput);
      }
      break;
    case 'D':
      dim= qh_strtol(s, &s);
      if (dim < 1
      || dim > MAXdim) {
        qh_fprintf_rbox(qh, qh->ferr, 6189, "rbox error: dimension, D%d, out of bounds (>=%d or <=0)\n", dim, MAXdim);
        qh_errexit_rbox(qh, qh_ERRinput);
      }
      break;
    case 'G':
      if (isdigit(*s))
        gap= qh_strtod(s, &s);
      else
        gap= 0.5;
      isgap= 1;
      break;
    case 'L':
      if (isdigit(*s))
        radius= qh_strtod(s, &s);
      else
        radius= 10;
      islens= 1;
      break;
    case 'M':
      ismesh= 1;
      if (*s)
        meshn= qh_strtod(s, &s);
      if (*s == ',') {
        ++s;
        meshm= qh_strtod(s, &s);
      }else
        meshm= 0.0;
      if (*s == ',') {
        ++s;
        meshr= qh_strtod(s, &s);
      }else
        meshr= sqrt(meshn*meshn + meshm*meshm);
      if (*s && !isspace(*s)) {
        qh_fprintf_rbox(qh, qh->ferr, 7069, "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':
      qh->rbox_out_offset= qh_strtod(s, &s);
      break;
    case 'P':
      if (!first_point)
        first_point= s - 1;
      addpoints++;
      while (*s && !isspace(*s))   /* read points later */
        s++;
      break;
    case 'W':
      width= qh_strtod(s, &s);
      iswidth= 1;
      break;
    case 'Z':
      if (isdigit(*s))
        radius= qh_strtod(s, &s);
      else
        radius= 1.0;
      isaxis= 1;
      break;
    default:
      qh_fprintf_rbox(qh, qh->ferr, 6352, "rbox error: unknown flag at '%s'.\nExecute 'rbox' without arguments for documentation.\n", s - 1);
      qh_errexit_rbox(qh, qh_ERRinput);
    }
    if (*s && !isspace(*s)) {
      qh_fprintf_rbox(qh, qh->ferr, 6353, "rbox error: missing space between flags at %s.\n", s);
      qh_errexit_rbox(qh, qh_ERRinput);
    }
  }

  /* ============= defaults, constants, and sizes =============== */
  if (qh->rbox_isinteger && !isbox)
    box= qh_DEFAULTzbox;
  if (addcube) {
    tempr= floor(ldexp(1.0,dim)+0.5);
    cubesize= (int)tempr;
    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) {
        qh_fprintf_rbox(qh, qh->ferr, 6190, "rbox error: can not combine 'Ln' with 'Zn'\n");
        qh_errexit_rbox(qh, qh_ERRinput);
    }
    if (radius <= 1.0) {
        qh_fprintf_rbox(qh, qh->ferr, 6191, "rbox error: lens radius %.2g should be greater than 1.0\n",
               radius);
        qh_errexit_rbox(qh, qh_ERRinput);
    }
    lensangle= asin(1.0/radius);
    lensbase= radius * cos(lensangle);
  }

  if (!numpoints) {
    if (issimplex2)
        ; /* ok */
    else if (isregular + issimplex + islens + issphere + isaxis + isspiral + iswidth + ismesh) {
        qh_fprintf_rbox(qh, qh->ferr, 6192, "rbox error: missing count\n");
        qh_errexit_rbox(qh, qh_ERRinput);
    }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)) {
    qh_fprintf_rbox(qh, qh->ferr, 6193, "rbox error: can only specify one of 'l', 's', 'x', 'Ln', or 'Mn,m,r' ('Ln s' is ok).\n");
    qh_errexit_rbox(qh, qh_ERRinput);
  }
  if (coincidentpoints>0 && (numpoints == 0 || coincidenttotal > numpoints)) {
    qh_fprintf_rbox(qh, qh->ferr, 6270, "rbox error: 'Cn,r,m' requested n coincident points for each of m points.  Either there is no points or m (%d) is greater than the number of points (%d).\n", coincidenttotal, numpoints);
    qh_errexit_rbox(qh, qh_ERRinput);
  }
  if (coincidentpoints > 0 && isregular) {
    qh_fprintf_rbox(qh, qh->ferr, 6423, "rbox error: 'Cn,r,m' is not implemented for regular points ('r')\n");
    qh_errexit_rbox(qh, qh_ERRinput);
  }

  if (coincidenttotal == 0)
    coincidenttotal= numpoints;

  /* ============= 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;
  totpoints += coincidentpoints*coincidenttotal;

  /* ============= 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 if (israndom) {
    seed= (int)time(&timedata);
    sprintf(seedbuf, " t%d", seed);  /* appends an extra t, not worth removing */
    strncat(command, seedbuf, sizeof(command) - strlen(command) - 1);
    t= strstr(command, " t ");
    if (t)
      strcpy(t+1, t+3); /* remove " t " */
  } /* else, seed explicitly set to n */
  qh_RANDOMseed_(qh, seed);

  /* ============= print header =============== */

  if (iscdd)
      qh_fprintf_rbox(qh, qh->fout, 9391, "%s\nbegin\n        %d %d %s\n",
      NOcommand ? "" : command,
      totpoints, dim+1,
      qh->rbox_isinteger ? "integer" : "real");
  else if (NOcommand)
      qh_fprintf_rbox(qh, qh->fout, 9392, "%d\n%d\n", dim, totpoints);
  else
      /* qh_fprintf_rbox special cases 9393 to append 'command' to the RboxPoints.comment() */
      qh_fprintf_rbox(qh, qh->fout, 9393, "%d %s\n%d\n", dim, command, totpoints);

  /* ============= explicit points =============== */
  if ((s= first_point)) {
    while (s && *s) { /* 'P' */
      count= 0;
      if (iscdd)
        qh_out1(qh, 1.0);
      while (*++s) {
        qh_out1(qh, qh_strtod(s, &s));
        count++;
        if (isspace(*s) || !*s)
          break;
        if (*s != ',') {
          qh_fprintf_rbox(qh, qh->ferr, 6194, "rbox error: missing comma after coordinate in %s\n\n", s);
          qh_errexit_rbox(qh, qh_ERRinput);
        }
      }
      if (count < dim) {
        for (k=dim-count; k--; )
          qh_out1(qh, 0.0);
      }else if (count > dim) {
        qh_fprintf_rbox(qh, qh->ferr, 6195, "rbox error: %d coordinates instead of %d coordinates in %s\n\n",
                  count, dim, s);
        qh_errexit_rbox(qh, qh_ERRinput);
      }
      qh_fprintf_rbox(qh, qh->fout, 9394, "\n");
      while ((s= strchr(s, 'P'))) {
        if (isspace(s[-1]))
          break;
      }
    }
  }

  /* ============= simplex distribution =============== */
  if (issimplex+issimplex2) {
    if (!(*simplex= (double *)qh_malloc( (size_t)(dim * (dim+1)) * sizeof(double)))) {
      qh_fprintf_rbox(qh, qh->ferr, 6196, "rbox error: insufficient memory for simplex\n");
      qh_errexit_rbox(qh, qh_ERRmem); /* qh_ERRmem */
    }
    simplexp= *simplex;
    if (isregular) {
      for (i=0; ifout, 9395, "\n");
      }
    }
    for (j=0; jferr, 6197, "rbox error: regular points can be used only in 2-d and 3-d\n\n");
      qh_errexit_rbox(qh, qh_ERRinput);
    }
    if (!isaxis || radius == 0.0) {
      isaxis= 1;
      radius= 1.0;
    }
    if (dim == 3) {
      if (iscdd)
        qh_out1(qh, 1.0);
      qh_out3n(qh, 0.0, 0.0, -box);
      if (!isgap) {
        if (iscdd)
          qh_out1(qh, 1.0);
        qh_out3n(qh, 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)
          qh_out1(qh, 1.0);
        qh_out2n(qh, x*box, y*box);
      }else {
        norm= sqrt(1.0 + x*x + y*y);
        if (iscdd)
          qh_out1(qh, 1.0);
        qh_out3n(qh, 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)
            qh_out1(qh, 1.0);
          qh_out3n(qh, 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)
        qh_out1(qh, 1.0);
      qh_out2n(qh, x*box, y*box);
      if (i != 0 && i != numpoints - 1) {
        if (iscdd)
          qh_out1(qh, 1.0);
        qh_out2n(qh, x*box, -y*box);
      }
    }
  }
  /* ============= regular points for 'r Ln D3' =============== */
  else if (isregular && islens && dim != 2) {
    if (dim != 3) {
      qh_fprintf_rbox(qh, qh->ferr, 6198, "rbox error: regular points can be used only in 2-d and 3-d\n\n");
      qh_errexit_rbox(qh, qh_ERRinput);
    }
    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)
        qh_out1(qh, 1.0);
      qh_out3n(qh, box*x, box*y, 0.0);
      x *= 1-gap;
      y *= 1-gap;
      if (iscdd)
        qh_out1(qh, 1.0);
      qh_out3n(qh, box*x, box*y, box * offset);
      if (iscdd)
        qh_out1(qh, 1.0);
      qh_out3n(qh, box*x, box*y, -box * offset);
    }
  }
  /* ============= apex of 'Zn' distribution + gendim =============== */
  else {
    if (isaxis) {
      gendim= dim-1;
      if (iscdd)
        qh_out1(qh, 1.0);
      for (j=0; j < gendim; j++)
        qh_out1(qh, 0.0);
      qh_out1(qh, -box);
      qh_fprintf_rbox(qh, qh->fout, 9398, "\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; jferr, 6199, "rbox error: spiral distribution is available only in 3d\n\n");
          qh_errexit_rbox(qh, qh_ERRinput);
        }
        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 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;
      }
      /* ============= scale point to box =============== */
      for (k=0; k=0; k--) {
        if (j & ( 1 << k))
          qh_out1(qh, cube);
        else
          qh_out1(qh, -cube);
      }
      qh_fprintf_rbox(qh, qh->fout, 9400, "\n");
    }
  }

  /* ============= write diamond vertices =============== */
  if (adddiamond) {
    for (j=0; j=0; k--) {
        if (j/2 != k)
          qh_out1(qh, 0.0);
        else if (j & 0x1)
          qh_out1(qh, diamond);
        else
          qh_out1(qh, -diamond);
      }
      qh_fprintf_rbox(qh, qh->fout, 9401, "\n");
    }
  }

  if (iscdd)
    qh_fprintf_rbox(qh, qh->fout, 9402, "end\nhull\n");
} /* rboxpoints2 */

/*------------------------------------------------
outxxx - output functions for qh_rboxpoints
*/
int qh_roundi(qhT *qh, double a) {
  if (a < 0.0) {
    if (a - 0.5 < INT_MIN) {
      qh_fprintf_rbox(qh, qh->ferr, 6200, "rbox input error: negative coordinate %2.2g is too large.  Reduce 'Bn'\n", a);
      qh_errexit_rbox(qh, qh_ERRinput);
    }
    return (int)(a - 0.5);
  }else {
    if (a + 0.5 > INT_MAX) {
      qh_fprintf_rbox(qh, qh->ferr, 6201, "rbox input error: coordinate %2.2g is too large.  Reduce 'Bn'\n", a);
      qh_errexit_rbox(qh, qh_ERRinput);
    }
    return (int)(a + 0.5);
  }
} /* qh_roundi */

void qh_out1(qhT *qh, double a) {

  if (qh->rbox_isinteger)
    qh_fprintf_rbox(qh, qh->fout, 9403, "%d ", qh_roundi(qh, a+qh->rbox_out_offset));
  else
    qh_fprintf_rbox(qh, qh->fout, 9404, qh_REAL_1, a+qh->rbox_out_offset);
} /* qh_out1 */

void qh_out2n(qhT *qh, double a, double b) {

  if (qh->rbox_isinteger)
    qh_fprintf_rbox(qh, qh->fout, 9405, "%d %d\n", qh_roundi(qh, a+qh->rbox_out_offset), qh_roundi(qh, b+qh->rbox_out_offset));
  else
    qh_fprintf_rbox(qh, qh->fout, 9406, qh_REAL_2n, a+qh->rbox_out_offset, b+qh->rbox_out_offset);
} /* qh_out2n */

void qh_out3n(qhT *qh, double a, double b, double c) {

  if (qh->rbox_isinteger)
    qh_fprintf_rbox(qh, qh->fout, 9407, "%d %d %d\n", qh_roundi(qh, a+qh->rbox_out_offset), qh_roundi(qh, b+qh->rbox_out_offset), qh_roundi(qh, c+qh->rbox_out_offset));
  else
    qh_fprintf_rbox(qh, qh->fout, 9408, qh_REAL_3n, a+qh->rbox_out_offset, b+qh->rbox_out_offset, c+qh->rbox_out_offset);
} /* qh_out3n */

void qh_outcoord(qhT *qh, int iscdd, double *coord, int dim) {
    double *p= coord;
    int k;

    if (iscdd)
      qh_out1(qh, 1.0);
    for (k=0; k < dim; k++)
      qh_out1(qh, *(p++));
    qh_fprintf_rbox(qh, qh->fout, 9396, "\n");
} /* qh_outcoord */

void qh_outcoincident(qhT *qh, int coincidentpoints, double radius, int iscdd, double *coord, int dim) {
  double *p;
  double randr, delta;
  int i,k;
  double randmax= qh_RANDOMmax;

  for (i=0; ifout, 9410, "\n");
  }
} /* qh_outcoincident */

/*------------------------------------------------
   Only called from qh_rboxpoints2 or qh_fprintf_rbox
   qh_fprintf_rbox is only called from qh_rboxpoints2
   The largest exitcode is '255' for compatibility with exit()
*/
void qh_errexit_rbox(qhT *qh, int exitcode)
{
    longjmp(qh->rbox_errexit, exitcode);
} /* qh_errexit_rbox */

qhull-2020.2/src/libqhull_r/stat_r.c0000644060175106010010000010034413723600334015555 0ustar  bbarber/*
  ---------------------------------

   stat_r.c
   contains all statistics that are collected for qhull

   see qh-stat_r.htm and stat_r.h

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull_r/stat_r.c#9 $$Change: 3037 $
   $DateTime: 2020/09/03 17:28:32 $$Author: bbarber $
*/

#include "qhull_ra.h"

/*========== functions in alphabetic order ================*/

/*---------------------------------

  qh_allstatA()
    define statistics in groups of 20

  notes:
    (otherwise, 'gcc -O2' uses too much memory)
    uses qhstat.next
*/
void qh_allstatA(qhT *qh) {

   /* zdef_(type,name,doc,average) */
  zzdef_(zdoc, Zdoc2, "precision statistics", -1);
  zdef_(zinc, Znewvertex, NULL, -1);
  zdef_(wadd, Wnewvertex, "ave. distance of a new vertex to a facet", Znewvertex);
  zzdef_(wmax, Wnewvertexmax, "max. distance of a new vertex to a facet", -1);
  zdef_(wmax, Wvertexmax, "max. distance of an output vertex to a facet", -1);
  zdef_(wmin, Wvertexmin, "min. distance of an output vertex to a facet", -1);
  zdef_(wmin, Wmindenom, "min. denominator in hyperplane computation", -1);

  qh->qhstat.precision= qh->qhstat.next;  /* usually call qh_joggle_restart, printed if Q0 or QJn */
  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, "dupridges with multiple neighbors", -1);
  zzdef_(zinc, Zflipridge, "dupridges with flip facet into good neighbor", -1);
  zzdef_(zinc, Zflipridge2, "dupridges with flip facet into good flip neighbor", -1);
}
void qh_allstatB(qhT *qh) {
  zzdef_(zdoc, Zdoc1, "summary information", -1);
  zdef_(zinc, Zvertices, "number of vertices in output", -1);
  zdef_(zinc, Znumfacets, "number of facets in output", -1);
  zdef_(zinc, Znonsimplicial, "number of non-simplicial facets in output", -1);
  zdef_(zinc, Znowsimplicial, "simplicial facets that were non-simplicial", -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 cosine (angle) of facet normals for all ridges", Zangle);
  zdef_(wmax, Wanglemax, "  maximum cosine of facet normals (flatest) across a ridge", -1);
  zdef_(wmin, Wanglemin, "  minimum cosine of facet normals (sharpest) across a ridge", -1);
  zdef_(wadd, Wareatot, "total area of facets", -1);
  zdef_(wmax, Wareamax, "  maximum facet area", -1);
  zdef_(wmin, Wareamin, "  minimum facet area", -1);
}
void qh_allstatC(qhT *qh) {
  zdef_(zdoc, Zdoc9, "build hull statistics", -1);
  zzdef_(zinc, Zprocessed, "points processed", -1);
  zzdef_(zinc, Zretry, "retries due to precision problems", -1);
  zdef_(wmax, Wretrymax, "  max. random joggle", -1);
  zdef_(zmax, Zmaxvertex, "max. vertices at any one time", -1);
  zdef_(zinc, Ztotvisible, "ave. visible facets per iteration", Zprocessed);
  zdef_(zinc, Zinsidevisible, "  ave. visible facets without an horizon neighbor", Zprocessed);
  zdef_(zadd, Zvisfacettot,  "  ave. facets deleted per iteration", Zprocessed);
  zdef_(zmax, Zvisfacetmax,  "    maximum", -1);
  zdef_(zadd, Zvisvertextot, "ave. visible vertices per iteration", Zprocessed);
  zdef_(zmax, Zvisvertexmax, "    maximum", -1);
  zdef_(zinc, Ztothorizon, "ave. horizon facets per iteration", Zprocessed);
  zdef_(zadd, Znewfacettot,  "ave. new or merged facets per iteration", Zprocessed);
  zdef_(zmax, Znewfacetmax,  "    maximum (includes initial simplex)", -1);
  zdef_(wadd, Wnewbalance, "average new facet balance", Zprocessed);
  zdef_(wadd, Wnewbalance2, "  standard deviation", -1);
  zdef_(wadd, Wpbalance, "average partition balance", Zpbalance);
  zdef_(wadd, Wpbalance2, "  standard deviation", -1);
  zdef_(zinc, Zpbalance,  "  count", -1);
  zdef_(zinc, Zsearchpoints, "searches of all points for initial simplex", -1);
  zdef_(zinc, Zdetfacetarea, "determinants for facet area", -1);
  zdef_(zinc, Znoarea, "  determinants not computed because vertex too low", -1);
  zdef_(zinc, Zdetsimplex, "determinants for initial hull or voronoi vertices", -1);
  zdef_(zinc, Znotmax, "points ignored (!above max_outside)", -1);
  zdef_(zinc, Zpinchedapex, "points ignored (pinched apex)", -1);
  zdef_(zinc, Znotgood, "points ignored (!above a good facet)", -1);
  zdef_(zinc, Znotgoodnew, "points ignored (didn't create a good new facet)", -1);
  zdef_(zinc, Zgoodfacet, "good facets found", -1);
  zzdef_(zinc, Znumvisibility, "distance tests for facet visibility", -1);
  zdef_(zinc, Zdistvertex, "distance tests to report minimum vertex", -1);
  zzdef_(zinc, Ztotcheck, "points checked for facets' outer planes", -1);
  zzdef_(zinc, Zcheckpart, "  ave. distance tests per check", Ztotcheck);
}
void qh_allstatD(qhT *qh) {
  zdef_(zinc, Zvisit, "resets of visit_id", -1);
  zdef_(zinc, Zvvisit, "  resets of vertex_visit", -1);
  zdef_(zmax, Zvisit2max, "  max visit_id/2", -1);
  zdef_(zmax, Zvvisit2max, "  max vertex_visit/2", -1);

  zdef_(zdoc, Zdoc4, "partitioning statistics (see previous for outer planes)", -1);
  zzdef_(zadd, Zdelvertextot, "total vertices deleted", -1);
  zdef_(zmax, Zdelvertexmax, "    maximum vertices deleted per iteration", -1);
  zdef_(zinc, Zfindbest, "calls to findbest", -1);
  zdef_(zadd, Zfindbesttot, " ave. facets tested", Zfindbest);
  zdef_(zmax, Zfindbestmax, " max. facets tested", -1);
  zdef_(zadd, Zfindcoplanar, " ave. coplanar search", Zfindbest);
  zdef_(zinc, Zfindnew, "calls to findbestnew", -1);
  zdef_(zadd, Zfindnewtot, " ave. facets tested", Zfindnew);
  zdef_(zmax, Zfindnewmax, " max. facets tested", -1);
  zdef_(zinc, Zfindnewjump, " ave. clearly better", Zfindnew);
  zdef_(zinc, Zfindnewsharp, " calls due to qh_sharpnewfacets", -1);
  zdef_(zinc, Zfindhorizon, "calls to findhorizon", -1);
  zdef_(zadd, Zfindhorizontot, " ave. facets tested", Zfindhorizon);
  zdef_(zmax, Zfindhorizonmax, " max. facets tested", -1);
  zdef_(zinc, Zfindjump,       " ave. clearly better", Zfindhorizon);
  zdef_(zinc, Znewbesthorizon, " new bestfacets during qh_findbesthorizon", -1);
  zdef_(zinc, Zpartangle, "angle tests for repartitioned coplanar points", -1);
  zdef_(zinc, Zpartcorner, "  repartitioned coplanar points above a corner facet", -1);
  zdef_(zinc, Zparthidden, "  repartitioned coplanar points above a hidden facet", -1);
  zdef_(zinc, Zparttwisted, "  repartitioned coplanar points above a twisted facet", -1);
}
void qh_allstatE(qhT *qh) {
  zdef_(zinc, Zpartinside, "inside points", -1);
  zdef_(zinc, Zpartnear, "  near inside points kept with a facet", -1);
  zdef_(zinc, Zcoplanarinside, "  inside points that were coplanar with a facet", -1);
  zdef_(zinc, Zbestlower, "calls to findbestlower", -1);
  zdef_(zinc, Zbestlowerv, "  with search of vertex neighbors", -1);
  zdef_(zinc, Zbestlowerall, "  with rare search of all facets", -1);
  zdef_(zmax, Zbestloweralln, "  facets per search of all facets", -1);
  zdef_(wadd, Wmaxout, "difference in max_outside at final check", -1);
  zzdef_(zinc, Zpartitionall, "distance tests for initial partition", -1);
  zdef_(zinc, Ztotpartition, "partitions of a point", -1);
  zzdef_(zinc, Zpartition, "distance tests for partitioning", -1);
  zzdef_(zinc, Zdistcheck, "distance tests for checking flipped facets", -1);
  zzdef_(zinc, Zdistconvex, "distance tests for checking convexity", -1);
  zdef_(zinc, Zdistgood, "distance tests for checking good point", -1);
  zdef_(zinc, Zdistio, "distance tests for output", -1);
  zdef_(zinc, Zdiststat, "distance tests for statistics", -1);
  zzdef_(zinc, Zdistplane, "total number of distance tests", -1);
  zdef_(zinc, Ztotpartcoplanar, "partitions of coplanar points or deleted vertices", -1);
  zzdef_(zinc, Zpartcoplanar, "   distance tests for these partitions", -1);
  zdef_(zinc, Zcomputefurthest, "distance tests for computing furthest", -1);
}
void qh_allstatE2(qhT *qh) {
  zdef_(zdoc, Zdoc5, "statistics for matching ridges", -1);
  zdef_(zinc, Zhashlookup, "total lookups for matching ridges of new facets", -1);
  zdef_(zinc, Zhashtests, "average number of tests to match a ridge", Zhashlookup);
  zdef_(zinc, Zhashridge, "total lookups of subridges (duplicates and boundary)", -1);
  zdef_(zinc, Zhashridgetest, "average number of tests per subridge", Zhashridge);
  zdef_(zinc, Zdupsame, "duplicated ridges in same merge cycle", -1);
  zdef_(zinc, Zdupflip, "duplicated ridges with flipped facets", -1);

  zdef_(zdoc, Zdoc6, "statistics for determining merges", -1);
  zdef_(zinc, Zangletests, "angles computed for ridge convexity", -1);
  zdef_(zinc, Zbestcentrum, "best merges used centrum instead of vertices",-1);
  zzdef_(zinc, Zbestdist, "distance tests for best merge", -1);
  zzdef_(zinc, Zcentrumtests, "distance tests for centrum convexity", -1);
  zzdef_(zinc, Zvertextests, "distance tests for vertex 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 or vertices in getmergeset", -1);
  zdef_(zinc, Zconcaveridge, "concave ridges in getmergeset", -1);
  zdef_(zinc, Zconcavecoplanarridge, "concave-coplanar ridges in getmergeset", -1);
  zdef_(zinc, Ztwistedridge, "twisted ridges in getmergeset", -1);
}
void qh_allstatF(qhT *qh) {
  zdef_(zdoc, Zdoc7, "statistics for merging", -1);
  zdef_(zinc, Zpremergetot, "merge iterations", -1);
  zdef_(zadd, Zmergeinittot, "ave. initial non-convex ridges per iteration", Zpremergetot);
  zdef_(zadd, Zmergeinitmax, "  maximum", -1);
  zdef_(zadd, Zmergesettot, "  ave. additional non-convex ridges per iteration", Zpremergetot);
  zdef_(zadd, Zmergesetmax, "  maximum additional in one pass", -1);
  zdef_(zadd, Zmergeinittot2, "initial non-convex ridges for post merging", -1);
  zdef_(zadd, Zmergesettot2, "  additional non-convex ridges", -1);
  zdef_(wmax, Wmaxoutside, "max distance of vertex or coplanar point above facet (w/roundoff)", -1);
  zdef_(wmin, Wminvertex, "max distance of 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, Zmergeintocoplanar, "new facets merged into coplanar horizon", -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, Zredundant, "merges due to redundant neighbors", -1);
  zdef_(zinc, Zredundantmerge, "  detected by qh_test_nonsimplicial_merge instead of qh_test_redundant_neighbors", -1);
  zdef_(zadd, Ztestvneighbor, "non-convex vertex neighbors", -1);
}
void qh_allstatG(qhT *qh) {
  zdef_(zinc, Zacoplanar, "merges due to angle coplanar facets", -1);
  zdef_(wadd, Wacoplanartot, "  average merge distance", Zacoplanar);
  zdef_(wmax, Wacoplanarmax, "  maximum merge distance", -1);
  zdef_(zinc, Zcoplanar, "merges due to coplanar facets", -1);
  zdef_(wadd, Wcoplanartot, "  average merge distance", Zcoplanar);
  zdef_(wmax, Wcoplanarmax, "  maximum merge distance", -1);
  zdef_(zinc, Zconcave, "merges due to concave facets", -1);
  zdef_(wadd, Wconcavetot, "  average merge distance", Zconcave);
  zdef_(wmax, Wconcavemax, "  maximum merge distance", -1);
  zdef_(zinc, Zconcavecoplanar, "merges due to concave-coplanar facets", -1);
  zdef_(wadd, Wconcavecoplanartot, "  average merge distance", Zconcavecoplanar);
  zdef_(wmax, Wconcavecoplanarmax, "  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 dupridges", -1);
  zdef_(wadd, Wduplicatetot, "  average merge distance", Zduplicate);
  zdef_(wmax, Wduplicatemax, "  maximum merge distance", -1);
  zdef_(zinc, Ztwisted, "merges due to twisted facets", -1);
  zdef_(wadd, Wtwistedtot, "  average merge distance", Ztwisted);
  zdef_(wmax, Wtwistedmax, "  maximum merge distance", -1);
}
void qh_allstatH(qhT *qh) {
  zdef_(zdoc, Zdoc8, "statistics for vertex merges", -1);
  zzdef_(zinc, Zpinchduplicate, "merge pinched vertices for a duplicate ridge", -1);
  zzdef_(zinc, Zpinchedvertex, "merge pinched vertices for a dupridge", -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, Znewvertexridge, "  found new vertex in ridge", -1);
  zdef_(zinc, Zdelridge, "deleted ridges due to renamed vertices", -1);
  zdef_(zinc, Zdropneighbor, "dropped neighbors due to renamed vertices", -1);
  zdef_(zinc, Zdropdegen, "merge 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, Zretryadd, "retry qh_addpoint after merge pinched vertex", -1);
  zdef_(zadd, Zretryaddtot, "  tot. merge pinched vertex due to dupridge", -1);
  zdef_(zmax, Zretryaddmax, "  max. merge pinched vertex for a qh_addpoint", -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, outside and coplanar sets, and qhT",-1);
  zdef_(zadd, Zmemridges, "for ridges and their vertex sets", -1);
} /* allstat */

void qh_allstatI(qhT *qh) {
  qh->qhstat.vridges= qh->qhstat.next; /* printed in qh_produce_output2 if non-zero Zridge or Zridgemid */
  zzdef_(zdoc, Zdoc11, "Voronoi ridge statistics", -1);
  zzdef_(zinc, Zridge, "non-simplicial Voronoi vertices for all ridges", -1);
  zzdef_(wadd, Wridge, "  ave. distance to ridge", Zridge);
  zzdef_(wmax, Wridgemax, "  max. distance to ridge", -1);
  zzdef_(zinc, Zridgemid, "bounded ridges", -1);
  zzdef_(wadd, Wridgemid, "  ave. distance of midpoint to ridge", Zridgemid);
  zzdef_(wmax, Wridgemidmax, "  max. distance of midpoint to ridge", -1);
  zzdef_(zinc, Zridgeok, "bounded ridges with ok normal", -1);
  zzdef_(wadd, Wridgeok, "  ave. angle to ridge", Zridgeok);
  zzdef_(wmax, Wridgeokmax, "  max. angle to ridge", -1);
  zzdef_(zinc, Zridge0, "bounded ridges with near-zero normal", -1);
  zzdef_(wadd, Wridge0, "  ave. angle to ridge", Zridge0);
  zzdef_(wmax, Wridge0max, "  max. angle to ridge", -1);

  zdef_(zdoc, Zdoc12, "Triangulation statistics ('Qt')", -1);
  zdef_(zinc, Ztricoplanar, "non-simplicial facets triangulated", -1);
  zdef_(zadd, Ztricoplanartot, "  ave. new facets created (may be deleted)", Ztricoplanar);
  zdef_(zmax, Ztricoplanarmax, "  max. new facets created", -1);
  zdef_(zinc, Ztrinull, "null new facets deleted (duplicated vertex)", -1);
  zdef_(zinc, Ztrimirror, "mirrored pairs of new facets deleted (same vertices)", -1);
  zdef_(zinc, Ztridegen, "degenerate new facets in output (same ridge)", -1);
} /* allstat */

/*---------------------------------

  qh_allstatistics()
    reset printed flag for all statistics
*/
void qh_allstatistics(qhT *qh) {
  int i;

  for(i=ZEND; i--; )
    qh->qhstat.printed[i]= False;
} /* allstatistics */

#if qh_KEEPstatistics
/*---------------------------------

  qh_collectstatistics()
    collect statistics for qh.facet_list

*/
void qh_collectstatistics(qhT *qh) {
  facetT *facet, *neighbor, **neighborp;
  vertexT *vertex, **vertexp;
  realT dotproduct, dist;
  int sizneighbors, sizridges, sizvertices, i;

  qh->old_randomdist= qh->RANDOMdist;
  qh->RANDOMdist= False;
  zval_(Zmempoints)= qh->num_points * qh->normal_size + (int)sizeof(qhT);
  zval_(Zmemfacets)= 0;
  zval_(Zmemridges)= 0;
  zval_(Zmemvertices)= 0;
  zval_(Zangle)= 0;
  wval_(Wangle)= 0.0;
  zval_(Znumridges)= 0;
  zval_(Znumfacets)= 0;
  zval_(Znumneighbors)= 0;
  zval_(Znumvertices)= 0;
  zval_(Znumvneighbors)= 0;
  zval_(Znummergetot)= 0;
  zval_(Znummergemax)= 0;
  zval_(Zvertices)= qh->num_vertices - qh_setsize(qh, qh->del_vertices);
  if (qh->MERGING || qh->APPROXhull || qh->JOGGLEmax < REALmax/2)
    wmax_(Wmaxoutside, qh->max_outside);
  if (qh->MERGING)
    wmin_(Wminvertex, qh->min_vertex);
  if (!qh_checklists(qh, qh->facet_list)) {
    qh_fprintf(qh, qh->ferr, 6373, "qhull internal error: qh_checklists failed on qh_collectstatistics\n");
    if (!qh->ERREXITcalled)
      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  FORALLfacets
    facet->seen= False;
  if (qh->DELAUNAY) {
    FORALLfacets {
      if (facet->upperdelaunay != qh->UPPERdelaunay)
        facet->seen= True; /* remove from angle statistics */
    }
  }
  FORALLfacets {
    if (facet->visible && qh->NEWfacets)
      continue;
    sizvertices= qh_setsize(qh, facet->vertices);
    sizneighbors= qh_setsize(qh, facet->neighbors);
    sizridges= qh_setsize(qh, facet->ridges);
    zinc_(Znumfacets);
    zadd_(Znumvertices, sizvertices);
    zmax_(Zmaxvertices, sizvertices);
    zadd_(Znumneighbors, sizneighbors);
    zmax_(Zmaxneighbors, sizneighbors);
    zadd_(Znummergetot, facet->nummerge);
    i= facet->nummerge; /* avoid warnings */
    zmax_(Znummergemax, i);
    if (!facet->simplicial) {
      if (sizvertices == qh->hull_dim) {
        zinc_(Znowsimplicial);
      }else {
        zinc_(Znonsimplicial);
      }
    }
    if (sizridges) {
      zadd_(Znumridges, sizridges);
      zmax_(Zmaxridges, sizridges);
    }
    zadd_(Zmemfacets, (int)sizeof(facetT) + qh->normal_size + 2*(int)sizeof(setT)
       + SETelemsize * (sizneighbors + sizvertices));
    if (facet->ridges) {
      zadd_(Zmemridges,
        (int)sizeof(setT) + SETelemsize * sizridges + sizridges *
         ((int)sizeof(ridgeT) + (int)sizeof(setT) + SETelemsize * (qh->hull_dim-1))/2);
    }
    if (facet->outsideset)
      zadd_(Zmempoints, (int)sizeof(setT) + SETelemsize * qh_setsize(qh, facet->outsideset));
    if (facet->coplanarset)
      zadd_(Zmempoints, (int)sizeof(setT) + SETelemsize * qh_setsize(qh, facet->coplanarset));
    if (facet->seen) /* Delaunay upper envelope */
      continue;
    facet->seen= True;
    FOREACHneighbor_(facet) {
      if (neighbor == qh_DUPLICATEridge || neighbor == qh_MERGEridge
          || neighbor->seen || !facet->normal || !neighbor->normal)
        continue;
      dotproduct= qh_getangle(qh, facet->normal, neighbor->normal);
      zinc_(Zangle);
      wadd_(Wangle, dotproduct);
      wmax_(Wanglemax, dotproduct)
      wmin_(Wanglemin, dotproduct)
    }
    if (facet->normal) {
      FOREACHvertex_(facet->vertices) {
        zinc_(Zdiststat);
        qh_distplane(qh, vertex->point, facet, &dist);
        wmax_(Wvertexmax, dist);
        wmin_(Wvertexmin, dist);
      }
    }
  }
  FORALLvertices {
    if (vertex->deleted)
      continue;
    zadd_(Zmemvertices, (int)sizeof(vertexT));
    if (vertex->neighbors) {
      sizneighbors= qh_setsize(qh, vertex->neighbors);
      zadd_(Znumvneighbors, sizneighbors);
      zmax_(Zmaxvneighbors, sizneighbors);
      zadd_(Zmemvertices, (int)sizeof(vertexT) + SETelemsize * sizneighbors);
    }
  }
  qh->RANDOMdist= qh->old_randomdist;
} /* collectstatistics */
#endif /* qh_KEEPstatistics */

/*---------------------------------

  qh_initstatistics(qh)
    initialize statistics

  notes:
    NOerrors -- qh_initstatistics can not use qh_errexit(), qh_fprintf, or qh.ferr
    On first call, only qhmem.ferr is defined.  qh_memalloc is not setup.
    Also invoked by QhullQh().
*/
void qh_initstatistics(qhT *qh) {
  int i;
  realT realx;
  int intx;

  qh_allstatistics(qh);
  qh->qhstat.next= 0;
  qh_allstatA(qh);
  qh_allstatB(qh);
  qh_allstatC(qh);
  qh_allstatD(qh);
  qh_allstatE(qh);
  qh_allstatE2(qh);
  qh_allstatF(qh);
  qh_allstatG(qh);
  qh_allstatH(qh);
  qh_allstatI(qh);
  if (qh->qhstat.next > (int)sizeof(qh->qhstat.id)) {
    qh_fprintf_stderr(6184, "qhull internal error (qh_initstatistics): increase size of qhstat.id[].  qhstat.next %d should be <= sizeof(qh->qhstat.id) %d\n", 
          qh->qhstat.next, (int)sizeof(qh->qhstat.id));
#if 0 /* for locating error, Znumridges should be duplicated */
    for(i=0; i < ZEND; i++) {
      int j;
      for(j=i+1; j < ZEND; j++) {
        if (qh->qhstat.id[i] == qh->qhstat.id[j]) {
          qh_fprintf_stderr(6185, "qhull error (qh_initstatistics): duplicated statistic %d at indices %d and %d\n",
              qh->qhstat.id[i], i, j);
        }
      }
    }
#endif
    qh_exit(qh_ERRqhull);  /* can not use qh_errexit() */
  }
  qh->qhstat.init[zinc].i= 0;
  qh->qhstat.init[zadd].i= 0;
  qh->qhstat.init[zmin].i= INT_MAX;
  qh->qhstat.init[zmax].i= INT_MIN;
  qh->qhstat.init[wadd].r= 0;
  qh->qhstat.init[wmin].r= REALmax;
  qh->qhstat.init[wmax].r= -REALmax;
  for(i=0; i < ZEND; i++) {
    if (qh->qhstat.type[i] > ZTYPEreal) {
      realx= qh->qhstat.init[(unsigned char)(qh->qhstat.type[i])].r;
      qh->qhstat.stats[i].r= realx;
    }else if (qh->qhstat.type[i] != zdoc) {
      intx= qh->qhstat.init[(unsigned char)(qh->qhstat.type[i])].i;
      qh->qhstat.stats[i].i= intx;
    }
  }
} /* initstatistics */

/*---------------------------------

  qh_newstats(qh )
    returns True if statistics for zdoc

  returns:
    next zdoc
*/
boolT qh_newstats(qhT *qh, int idx, int *nextindex) {
  boolT isnew= False;
  int start, i;

  if (qh->qhstat.type[qh->qhstat.id[idx]] == zdoc)
    start= idx+1;
  else
    start= idx;
  for(i= start; i < qh->qhstat.next && qh->qhstat.type[qh->qhstat.id[i]] != zdoc; i++) {
    if (!qh_nostatistic(qh, qh->qhstat.id[i]) && !qh->qhstat.printed[qh->qhstat.id[i]])
        isnew= True;
  }
  *nextindex= i;
  return isnew;
} /* newstats */

/*---------------------------------

  qh_nostatistic(qh, index )
    true if no statistic to print
*/
boolT qh_nostatistic(qhT *qh, int i) {

  if ((qh->qhstat.type[i] > ZTYPEreal
       &&qh->qhstat.stats[i].r == qh->qhstat.init[(unsigned char)(qh->qhstat.type[i])].r)
      || (qh->qhstat.type[i] < ZTYPEreal
          &&qh->qhstat.stats[i].i == qh->qhstat.init[(unsigned char)(qh->qhstat.type[i])].i))
    return True;
  return False;
} /* nostatistic */

#if qh_KEEPstatistics
/*---------------------------------

  qh_printallstatistics(qh, fp, string )
    print all statistics with header 'string'
*/
void qh_printallstatistics(qhT *qh, FILE *fp, const char *string) {

  qh_allstatistics(qh);
  qh_collectstatistics(qh);
  qh_printstatistics(qh, fp, string);
  qh_memstatistics(qh, fp);
}


/*---------------------------------

  qh_printstatistics(qh, fp, string )
    print statistics to a file with header 'string'
    skips statistics with qhstat.printed[] (reset with qh_allstatistics)

  see:
    qh_printallstatistics()
*/
void qh_printstatistics(qhT *qh, FILE *fp, const char *string) {
  int i, k;
  realT ave; /* ignored */

  if (qh->num_points != qh->num_vertices || zval_(Zpbalance) == 0) {
    wval_(Wpbalance)= 0.0;
    wval_(Wpbalance2)= 0.0;
  }else
    wval_(Wpbalance2)= qh_stddev(qh, zval_(Zpbalance), wval_(Wpbalance),
                                 wval_(Wpbalance2), &ave);
  if (zval_(Zprocessed) == 0)
    wval_(Wnewbalance2)= 0.0;
  else
    wval_(Wnewbalance2)= qh_stddev(qh, zval_(Zprocessed), wval_(Wnewbalance),
                                 wval_(Wnewbalance2), &ave);
  qh_fprintf(qh, fp, 9350, "\n\
%s\n\
qhull invoked by: %s | %s\n  %s with options:\n%s\n", 
    string, qh->rbox_command, qh->qhull_command, qh_version, qh->qhull_options);

  qh_fprintf(qh, fp, 9351, "\nprecision constants:\n\
 %6.2g max. abs. coordinate in the (transformed) input ('Qbd:n')\n\
 %6.2g max. roundoff error for distance computation ('En')\n\
 %6.2g max. roundoff error for angle computations\n\
 %6.2g min. distance for outside points ('Wn')\n\
 %6.2g min. distance for visible facets ('Vn')\n\
 %6.2g max. distance for coplanar facets ('Un')\n\
 %6.2g max. facet width for recomputing centrum and area\n\
",
  qh->MAXabs_coord, qh->DISTround, qh->ANGLEround, qh->MINoutside,
        qh->MINvisible, qh->MAXcoplanar, qh->WIDEfacet);
  if (qh->KEEPnearinside)
    qh_fprintf(qh, fp, 9352, "\
 %6.2g max. distance for near-inside points\n", qh->NEARinside);
  if (qh->premerge_cos < REALmax/2) qh_fprintf(qh, fp, 9353, "\
 %6.2g max. cosine for pre-merge angle\n", qh->premerge_cos);
  if (qh->PREmerge) qh_fprintf(qh, fp, 9354, "\
 %6.2g radius of pre-merge centrum\n", qh->premerge_centrum);
  if (qh->postmerge_cos < REALmax/2) qh_fprintf(qh, fp, 9355, "\
 %6.2g max. cosine for post-merge angle\n", qh->postmerge_cos);
  if (qh->POSTmerge) qh_fprintf(qh, fp, 9356, "\
 %6.2g radius of post-merge centrum\n", qh->postmerge_centrum);
  qh_fprintf(qh, fp, 9357, "\
 %6.2g max. distance for merging two simplicial facets\n\
 %6.2g max. roundoff error for arithmetic operations\n\
 %6.2g min. denominator for division\n\
  zero diagonal for Gauss: ", qh->ONEmerge, REALepsilon, qh->MINdenom);
  for(k=0; k < qh->hull_dim; k++)
    qh_fprintf(qh, fp, 9358, "%6.2e ", qh->NEARzero[k]);
  qh_fprintf(qh, fp, 9359, "\n\n");
  for(i=0 ; i < qh->qhstat.next; )
    qh_printstats(qh, fp, i, &i);
} /* printstatistics */
#endif /* qh_KEEPstatistics */

/*---------------------------------

  qh_printstatlevel(qh, fp, id )
    print level information for a statistic

  notes:
    nop if id >= ZEND, printed, or same as initial value
*/
void qh_printstatlevel(qhT *qh, FILE *fp, int id) {

  if (id >= ZEND || qh->qhstat.printed[id])
    return;
  if (qh->qhstat.type[id] == zdoc) {
    qh_fprintf(qh, fp, 9360, "%s\n", qh->qhstat.doc[id]);
    return;
  }
  if (qh_nostatistic(qh, id) || !qh->qhstat.doc[id])
    return;
  qh->qhstat.printed[id]= True;
  if (qh->qhstat.count[id] != -1
      && qh->qhstat.stats[(unsigned char)(qh->qhstat.count[id])].i == 0)
    qh_fprintf(qh, fp, 9361, " *0 cnt*");
  else if (qh->qhstat.type[id] >= ZTYPEreal && qh->qhstat.count[id] == -1)
    qh_fprintf(qh, fp, 9362, "%7.2g", qh->qhstat.stats[id].r);
  else if (qh->qhstat.type[id] >= ZTYPEreal && qh->qhstat.count[id] != -1)
    qh_fprintf(qh, fp, 9363, "%7.2g", qh->qhstat.stats[id].r/ qh->qhstat.stats[(unsigned char)(qh->qhstat.count[id])].i);
  else if (qh->qhstat.type[id] < ZTYPEreal && qh->qhstat.count[id] == -1)
    qh_fprintf(qh, fp, 9364, "%7d", qh->qhstat.stats[id].i);
  else if (qh->qhstat.type[id] < ZTYPEreal && qh->qhstat.count[id] != -1)
    qh_fprintf(qh, fp, 9365, "%7.3g", (realT) qh->qhstat.stats[id].i / qh->qhstat.stats[(unsigned char)(qh->qhstat.count[id])].i);
  qh_fprintf(qh, fp, 9366, " %s\n", qh->qhstat.doc[id]);
} /* printstatlevel */


/*---------------------------------

  qh_printstats(qh, fp, index, nextindex )
    print statistics for a zdoc group

  returns:
    next zdoc if non-null
*/
void qh_printstats(qhT *qh, FILE *fp, int idx, int *nextindex) {
  int j, nexti;

  if (qh_newstats(qh, idx, &nexti)) {
    qh_fprintf(qh, fp, 9367, "\n");
    for (j=idx; jqhstat.id[j]);
  }
  if (nextindex)
    *nextindex= nexti;
} /* printstats */

#if qh_KEEPstatistics

/*---------------------------------

  qh_stddev(qh, 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(qhT *qh, int num, realT tot, realT tot2, realT *ave) {
  realT stddev;

  if (num <= 0) {
    qh_fprintf(qh, qh->ferr, 7101, "qhull warning (qh_stddev): expecting num > 0.  Got num %d, tot %4.4g, tot2 %4.4g.  Returning 0.0\n",
      num, tot, tot2);
    return 0.0;
  }
  *ave= tot/num;
  stddev= sqrt(fabs(tot2/num - *ave * *ave));
  return stddev;
} /* stddev */
#else
realT qh_stddev(qhT *qh, int num, realT tot, realT tot2, realT *ave) { /* for qhull_r-exports.def */
  QHULL_UNUSED(qh)
  QHULL_UNUSED(num)
  QHULL_UNUSED(tot)
  QHULL_UNUSED(tot2)
  QHULL_UNUSED(ave)

  return 0.0;
}
#endif /* qh_KEEPstatistics */

#if !qh_KEEPstatistics
void    qh_collectstatistics(qhT *qh) {}
void    qh_printallstatistics(qhT *qh, FILE *fp, const char *string) {}
void    qh_printstatistics(qhT *qh, FILE *fp, const char *string) {}
#endif

qhull-2020.2/src/libqhull_r/stat_r.h0000644060175106010010000003166513661631132015574 0ustar  bbarber/*
  ---------------------------------

   stat_r.h
     contains all statistics that are collected for qhull

   see qh-stat_r.htm and stat_r.c

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/libqhull_r/stat_r.h#4 $$Change: 2953 $
   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $

   recompile qhull if you change this file

   Integer statistics are Z* while real statistics are W*.

   define MAYdebugx to call a routine at every statistic event

*/

#ifndef qhDEFstat
#define qhDEFstat 1

/* Depends on realT.  Do not include "libqhull_r" to avoid circular dependency */

#ifndef DEFqhT
#define DEFqhT 1
typedef struct qhT qhT;         /* Defined by libqhull_r.h */
#endif

#ifndef DEFqhstatT
#define DEFqhstatT 1
typedef struct qhstatT qhstatT; /* Defined here */
#endif

/*---------------------------------

  qh_KEEPstatistics
    0 turns off statistic reporting and gathering (except zzdef/zzinc/zzadd/zzval/wwval)

  set qh_KEEPstatistics in user_r.h to 0 to turn off statistics
*/
#ifndef qh_KEEPstatistics
#define qh_KEEPstatistics 1
#endif

/*---------------------------------

  Zxxx for integers, Wxxx for reals

  notes:
    be sure that all statistics are defined in stat_r.c
      otherwise initialization may core dump
    can pick up all statistics by:
      grep '[zw].*_[(][ZW]' *.c >z.x
    remove trailers with query">-
    remove leaders with  query-replace-regexp [ ^I]+  (
*/
#if qh_KEEPstatistics
enum qh_statistics {     /* alphabetical after Z/W */
    Zacoplanar,
    Wacoplanarmax,
    Wacoplanartot,
    Zangle,
    Wangle,
    Wanglemax,
    Wanglemin,
    Zangletests,
    Wareatot,
    Wareamax,
    Wareamin,
    Zavoidold,
    Wavoidoldmax,
    Wavoidoldtot,
    Zback0,
    Zbestcentrum,
    Zbestdist,
    Zbestlower,
    Zbestlowerall,
    Zbestloweralln,
    Zbestlowerv,
    Zcentrumtests,
    Zcheckpart,
    Zcomputefurthest,
    Zconcave,
    Wconcavemax,
    Wconcavetot,
    Zconcavecoplanar,
    Wconcavecoplanarmax,
    Wconcavecoplanartot,
    Zconcavecoplanarridge,
    Zconcaveridge,
    Zconcaveridges,
    Zcoplanar,
    Wcoplanarmax,
    Wcoplanartot,
    Zcoplanarangle,
    Zcoplanarcentrum,
    Zcoplanarhorizon,
    Zcoplanarinside,
    Zcoplanarpart,
    Zcoplanarridges,
    Wcpu,
    Zcyclefacetmax,
    Zcyclefacettot,
    Zcyclehorizon,
    Zcyclevertex,
    Zdegen,
    Wdegenmax,
    Wdegentot,
    Zdegenvertex,
    Zdelfacetdup,
    Zdelridge,
    Zdelvertextot,
    Zdelvertexmax,
    Zdetfacetarea,
    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,
    Zdupsame,
    Zflipped,
    Wflippedmax,
    Wflippedtot,
    Zflippedfacets,
    Zflipridge,
    Zflipridge2,
    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,
    Zmergeintocoplanar,
    Zmergeintohorizon,
    Zmergenew,
    Zmergesettot,
    Zmergesetmax,
    Zmergesettot2,
    Zmergesimplex,
    Zmergevertex,
    Wmindenom,
    Wminvertex,
    Zminnorm,
    Zmultiridge,
    Znearlysingular,
    Zredundant,
    Wnewbalance,
    Wnewbalance2,
    Znewbesthorizon,
    Znewfacettot,
    Znewfacetmax,
    Znewvertex,
    Wnewvertex,
    Wnewvertexmax,
    Znewvertexridge,
    Znoarea,
    Znonsimplicial,
    Znowsimplicial,
    Znotgood,
    Znotgoodnew,
    Znotmax,
    Znumfacets,
    Znummergemax,
    Znummergetot,
    Znumneighbors,
    Znumridges,
    Znumvertices,
    Znumvisibility,
    Znumvneighbors,
    Zonehorizon,
    Zpartangle,
    Zpartcoplanar,
    Zpartcorner,
    Zparthidden,
    Zpartinside,
    Zpartition,
    Zpartitionall,
    Zpartnear,
    Zparttwisted,
    Zpbalance,
    Wpbalance,
    Wpbalance2,
    Zpinchduplicate,
    Zpinchedapex,
    Zpinchedvertex,
    Zpostfacets,
    Zpremergetot,
    Zprocessed,
    Zremvertex,
    Zremvertexdel,
    Zredundantmerge,
    Zrenameall,
    Zrenamepinch,
    Zrenameshare,
    Zretry,
    Wretrymax,
    Zretryadd,
    Zretryaddmax,
    Zretryaddtot,
    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,
    Ztwisted,
    Wtwistedtot,
    Wtwistedmax,
    Ztwistedridge,
    Zvertextests,
    Wvertexmax,
    Wvertexmin,
    Zvertexridge,
    Zvertexridgetot,
    Zvertexridgemax,
    Zvertices,
    Zvisfacettot,
    Zvisfacetmax,
    Zvisit,
    Zvisit2max,
    Zvisvertextot,
    Zvisvertexmax,
    Zvvisit,
    Zvvisit2max,
    Zwidefacet,
    Zwidevertices,
    ZEND};

/*---------------------------------

  Zxxx/Wxxx statistics that remain defined if qh_KEEPstatistics=0

  notes:
    be sure to use zzdef, zzinc, etc. with these statistics (no double checking!)
*/
#else
enum qh_statistics {     /* for zzdef etc. macros */
  Zback0,
  Zbestdist,
  Zcentrumtests,
  Zcheckpart,
  Zconcaveridges,
  Zcoplanarhorizon,
  Zcoplanarpart,
  Zcoplanarridges,
  Zcyclefacettot,
  Zcyclehorizon,
  Zdelvertextot,
  Zdistcheck,
  Zdistconvex,
  Zdistplane,
  Zdistzero,
  Zdoc1,
  Zdoc2,
  Zdoc3,
  Zdoc11,
  Zflippedfacets,
  Zflipridge,
  Zflipridge2,
  Zgauss0,
  Zminnorm,
  Zmultiridge,
  Znearlysingular,
  Wnewvertexmax,
  Znumvisibility,
  Zpartcoplanar,
  Zpartition,
  Zpartitionall,
  Zpinchduplicate,
  Zpinchedvertex,
  Zprocessed,
  Zretry,
  Zridge,
  Wridge,
  Wridgemax,
  Zridge0,
  Wridge0,
  Wridge0max,
  Zridgemid,
  Wridgemid,
  Wridgemidmax,
  Zridgeok,
  Wridgeok,
  Wridgeokmax,
  Zsetplane,
  Ztotcheck,
  Ztotmerge,
  Zvertextests,
  ZEND};
#endif

/*---------------------------------

  ztype
    the type of a statistic sets its initial value.

  notes:
    The type should be the same as the macro for collecting the statistic
*/
enum ztypes {zdoc,zinc,zadd,zmax,zmin,ZTYPEreal,wadd,wmax,wmin,ZTYPEend};

/*========== macros and constants =============*/

/*----------------------------------

  MAYdebugx
    define as maydebug() to be called frequently for error trapping
*/
#define MAYdebugx

/*----------------------------------

  zzdef_, zdef_( type, name, doc, -1)
    define a statistic (assumes 'qhstat.next= 0;')

  zdef_( type, name, doc, count)
    define an averaged statistic
    printed as name/count
*/
#define zzdef_(stype,name,string,cnt) qh->qhstat.id[qh->qhstat.next++]=name; \
   qh->qhstat.doc[name]= string; qh->qhstat.count[name]= cnt; qh->qhstat.type[name]= stype
#if qh_KEEPstatistics
#define zdef_(stype,name,string,cnt) qh->qhstat.id[qh->qhstat.next++]=name; \
   qh->qhstat.doc[name]= string; qh->qhstat.count[name]= cnt; qh->qhstat.type[name]= stype
#else
#define zdef_(type,name,doc,count)
#endif

/*----------------------------------

  zzinc_( name ), zinc_( name)
    increment an integer statistic
*/
#define zzinc_(id) {MAYdebugx; qh->qhstat.stats[id].i++;}
#if qh_KEEPstatistics
#define zinc_(id) {MAYdebugx; qh->qhstat.stats[id].i++;}
#else
#define zinc_(id) {}
#endif

/*----------------------------------

  zzadd_( name, value ), zadd_( name, value ), wadd_( name, value )
    add value to an integer or real statistic
*/
#define zzadd_(id, val) {MAYdebugx; qh->qhstat.stats[id].i += (val);}
#define wwadd_(id, val) {MAYdebugx; qh->qhstat.stats[id].r += (val);}
#if qh_KEEPstatistics
#define zadd_(id, val) {MAYdebugx; qh->qhstat.stats[id].i += (val);}
#define wadd_(id, val) {MAYdebugx; qh->qhstat.stats[id].r += (val);}
#else
#define zadd_(id, val) {}
#define wadd_(id, val) {}
#endif

/*----------------------------------

  zzval_( name ), zval_( name ), wwval_( name )
    set or return value of a statistic
*/
#define zzval_(id) ((qh->qhstat.stats[id]).i)
#define wwval_(id) ((qh->qhstat.stats[id]).r)
#if qh_KEEPstatistics
#define zval_(id) ((qh->qhstat.stats[id]).i)
#define wval_(id) ((qh->qhstat.stats[id]).r)
#else
#define zval_(id) qh->qhstat.tempi
#define wval_(id) qh->qhstat.tempr
#endif

/*----------------------------------

  zmax_( id, val ), wmax_( id, value )
    maximize id with val
*/
#define wwmax_(id, val) {MAYdebugx; maximize_(qh->qhstat.stats[id].r,(val));}
#if qh_KEEPstatistics
#define zmax_(id, val) {MAYdebugx; maximize_(qh->qhstat.stats[id].i,(val));}
#define wmax_(id, val) {MAYdebugx; maximize_(qh->qhstat.stats[id].r,(val));}
#else
#define zmax_(id, val) {}
#define wmax_(id, val) {}
#endif

/*----------------------------------

  zmin_( id, val ), wmin_( id, value )
    minimize id with val
*/
#if qh_KEEPstatistics
#define zmin_(id, val) {MAYdebugx; minimize_(qh->qhstat.stats[id].i,(val));}
#define wmin_(id, val) {MAYdebugx; minimize_(qh->qhstat.stats[id].r,(val));}
#else
#define zmin_(id, val) {}
#define wmin_(id, val) {}
#endif

/*================== stat_r.h types ==============*/


/*----------------------------------

  intrealT
    union of integer and real, used for statistics
*/
typedef union intrealT intrealT;    /* union of int and realT */
union intrealT {
    int i;
    realT r;
};

/*----------------------------------

  qhstat
    Data structure for statistics, similar to qh and qhrbox

    Allocated as part of qhT (libqhull_r.h)
*/

struct qhstatT {
  intrealT   stats[ZEND];     /* integer and real statistics */
  unsigned char id[ZEND+10];  /* id's in print order */
  const char *doc[ZEND];      /* array of documentation strings */
  short int  count[ZEND];     /* -1 if none, else index of count to use */
  char       type[ZEND];      /* type, see ztypes above */
  char       printed[ZEND];   /* true, if statistic has been printed */
  intrealT   init[ZTYPEend];  /* initial values by types, set initstatistics */

  int        next;            /* next index for zdef_ */
  int        precision;       /* index for precision problems, printed on qh_errexit and qh_produce_output2/Q0/QJn */
  int        vridges;         /* index for Voronoi ridges, printed on qh_produce_output2 */
  int        tempi;
  realT      tempr;
};

/*========== function prototypes ===========*/

#ifdef __cplusplus
extern "C" {
#endif

void    qh_allstatA(qhT *qh);
void    qh_allstatB(qhT *qh);
void    qh_allstatC(qhT *qh);
void    qh_allstatD(qhT *qh);
void    qh_allstatE(qhT *qh);
void    qh_allstatE2(qhT *qh);
void    qh_allstatF(qhT *qh);
void    qh_allstatG(qhT *qh);
void    qh_allstatH(qhT *qh);
void    qh_allstatI(qhT *qh);
void    qh_allstatistics(qhT *qh);
void    qh_collectstatistics(qhT *qh);
void    qh_initstatistics(qhT *qh);
boolT   qh_newstats(qhT *qh, int idx, int *nextindex);
boolT   qh_nostatistic(qhT *qh, int i);
void    qh_printallstatistics(qhT *qh, FILE *fp, const char *string);
void    qh_printstatistics(qhT *qh, FILE *fp, const char *string);
void    qh_printstatlevel(qhT *qh, FILE *fp, int id);
void    qh_printstats(qhT *qh, FILE *fp, int idx, int *nextindex);
realT   qh_stddev(qhT *qh, int num, realT tot, realT tot2, realT *ave);

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif   /* qhDEFstat */
qhull-2020.2/src/libqhull_r/usermem_r.c0000644060175106010010000000530313505241174016257 0ustar  bbarber/*
  ---------------------------------

   usermem_r.c
   user redefinable functions -- qh_exit, qh_free, and qh_malloc

   See README.txt.

   If you redefine one of these functions you must redefine all of them.
   If you recompile and load this file, then usermem.o will not be loaded
   from qhull.a or qhull.lib

   See libqhull_r.h for data structures, macros, and user-callable functions.
   See user_r.c for qhull-related, redefinable functions
   see user_r.h for user-definable constants
   See userprintf_r.c for qh_fprintf and userprintf_rbox_r.c for qh_fprintf_rbox

   Please report any errors that you fix to qhull@qhull.org
*/

#include "libqhull_r.h"

#include 
#include 

/*---------------------------------

  qh_exit( exitcode )
    exit program
    the exitcode must be 255 or less.  Zero indicates success.
    Note: Exit status ('$?') in bash reports 256 as 0

  notes:
    qh_exit() is called when qh_errexit() and longjmp() are not available.

    This is the only use of exit() in Qhull
    To replace qh_exit with 'throw', see libqhullcpp/usermem_r-cpp.cpp
*/
void qh_exit(int exitcode) {
    exit(exitcode);
} /* exit */

/*---------------------------------

  qh_fprintf_stderr( msgcode, format, list of args )
    fprintf to stderr with msgcode (non-zero)

  notes:
    qh_fprintf_stderr() is called when qh.ferr is not defined, usually due to an initialization error
    if msgcode is a MSG_ERROR (6000), caller should set qh.last_errcode (like qh_fprintf) or variable 'last_errcode'
    
    It is typically followed by qh_errexit().

    Redefine this function to avoid using stderr

    Use qh_fprintf [userprintf_r.c] for normal printing
*/
void qh_fprintf_stderr(int msgcode, const char *fmt, ... ) {
    va_list args;

    va_start(args, fmt);
    if(msgcode)
      fprintf(stderr, "QH%.4d ", msgcode);
    vfprintf(stderr, fmt, args);
    va_end(args);
} /* fprintf_stderr */

/*---------------------------------

  qh_free(qh, mem )
    free memory

  notes:
    same as free()
    No calls to qh_errexit() 
*/
void qh_free(void *mem) {
    free(mem);
} /* free */

/*---------------------------------

    qh_malloc( mem )
      allocate memory

    notes:
      same as malloc()
*/
void *qh_malloc(size_t size) {
    return malloc(size);
} /* malloc */


qhull-2020.2/src/libqhull_r/userprintf_r.c0000644060175106010010000000655613505221511017007 0ustar  bbarber/*
  ---------------------------------

  userprintf_r.c
  user redefinable function -- qh_fprintf

  see README.txt  see COPYING.txt for copyright information.

  If you recompile and load this file, then userprintf_r.o will not be loaded
  from qhull_r.a or qhull_r.lib

  See libqhull_r.h for data structures, macros, and user-callable functions.
  See user_r.c for qhull-related, redefinable functions
  see user_r.h for user-definable constants
  See usermem_r.c for qh_exit(), qh_free(), and qh_malloc()
  see Qhull.cpp and RboxPoints.cpp for examples.

  qh_printf is a good location for debugging traps, checked on each log line

  Please report any errors that you fix to qhull@qhull.org
*/

#include "libqhull_r.h"
#include "poly_r.h" /* for qh.tracefacet */

#include 
#include 
#include 

/*---------------------------------

  qh_fprintf(qh, fp, msgcode, format, list of args )
    print arguments to *fp according to format
    Use qh_fprintf_rbox() for rboxlib_r.c

  notes:
    sets qh.last_errcode if msgcode is error 6000..6999
    same as fprintf()
    fgets() is not trapped like fprintf()
    exit qh_fprintf via qh_errexit()
    may be called for errors in qh_initstatistics and qh_meminit
*/

void qh_fprintf(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... ) {
  va_list args;
  facetT *neighbor, **neighborp;

  if (!fp) {
    if(!qh){
      qh_fprintf_stderr(6241, "qhull internal error (userprintf_r.c): fp and qh not defined for qh_fprintf '%s'\n", fmt);
      qh->last_errcode= 6241;
      qh_exit(qh_ERRqhull);  /* can not use qh_errexit() */
    }
    /* could use qh->qhmem.ferr, but probably better to be cautious */
    qh_fprintf_stderr(6028, "qhull internal error (userprintf_r.c): fp is 0.  Wrong qh_fprintf was called.\n");
    qh->last_errcode= 6028;
    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  }
  if ((qh && qh->ANNOTATEoutput) || msgcode < MSG_TRACE4) {
    fprintf(fp, "[QH%.4d]", msgcode);
  }else if (msgcode >= MSG_ERROR && msgcode < MSG_STDERR ) {
    fprintf(fp, "QH%.4d ", msgcode);
  }
  va_start(args, fmt);
  vfprintf(fp, fmt, args);
  va_end(args);
    
  if (qh) {
    if (msgcode >= MSG_ERROR && msgcode < MSG_WARNING)
      qh->last_errcode= msgcode;
    /* Place debugging traps here. Use with trace option 'Tn' 
       Set qh.tracefacet_id, qh.traceridge_id, and/or qh.tracevertex_id in global_r.c
    */
    if (False) { /* in production skip test for debugging traps */
      if (qh->tracefacet && qh->tracefacet->tested) {
        if (qh_setsize(qh, qh->tracefacet->neighbors) < qh->hull_dim)
          qh_errexit(qh, qh_ERRdebug, qh->tracefacet, qh->traceridge);
        FOREACHneighbor_(qh->tracefacet) {
          if (neighbor != qh_DUPLICATEridge && neighbor != qh_MERGEridge && neighbor->visible)
            qh_errexit2(qh, qh_ERRdebug, qh->tracefacet, neighbor);
        }
      } 
      if (qh->traceridge && qh->traceridge->top->id == 234342223) {
        qh_errexit(qh, qh_ERRdebug, qh->tracefacet, qh->traceridge);
      }
      if (qh->tracevertex && qh_setsize(qh, qh->tracevertex->neighbors)>3434334) {
        qh_errexit(qh, qh_ERRdebug, qh->tracefacet, qh->traceridge);
      }
    }
    if (qh->FLUSHprint)
      fflush(fp);
  }
} /* qh_fprintf */

qhull-2020.2/src/libqhull_r/userprintf_rbox_r.c0000644060175106010010000000323713505241503020035 0ustar  bbarber/*
  ---------------------------------

   userprintf_rbox_r.c
   user redefinable function -- qh_fprintf_rbox

   see README.txt  see COPYING.txt for copyright information.

   If you recompile and load this file, then userprintf_rbox_r.o will not be loaded
   from qhull.a or qhull.lib

   See libqhull_r.h for data structures, macros, and user-callable functions.
   See user_r.c for qhull-related, redefinable functions
   see user_r.h for user-definable constants
   See usermem_r.c for qh_exit(), qh_free(), and qh_malloc()
   see Qhull.cpp and RboxPoints.cpp for examples.

   Please report any errors that you fix to qhull@qhull.org
*/

#include "libqhull_r.h"

#include 
#include 
#include 

/*---------------------------------

   qh_fprintf_rbox(qh, fp, msgcode, format, list of args )
     print arguments to *fp according to format
     Use qh_fprintf_rbox() for rboxlib_r.c

   notes:
     same as fprintf()
     fgets() is not trapped like fprintf()
     exit qh_fprintf_rbox via qh_errexit_rbox()
*/

void qh_fprintf_rbox(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... ) {
    va_list args;

    if (!fp) {
      qh_fprintf_stderr(6231, "qhull internal error (userprintf_rbox_r.c): fp is 0.  Wrong qh_fprintf_rbox called.\n");
      qh_errexit_rbox(qh, qh_ERRqhull);
    }
    if (msgcode >= MSG_ERROR && msgcode < MSG_STDERR)
      fprintf(fp, "QH%.4d ", msgcode);
    va_start(args, fmt);
    vfprintf(fp, fmt, args);
    va_end(args);
} /* qh_fprintf_rbox */

qhull-2020.2/src/libqhull_r/user_r.c0000644060175106010010000005714313662550344015577 0ustar  bbarber/*
  ---------------------------------

   user_r.c
   user redefinable functions

   see user2_r.c for qh_fprintf, qh_malloc, qh_free

   see README.txt  see COPYING.txt for copyright information.

   see libqhull_r.h for data structures, macros, and user-callable functions.

   see user_eg_r.c, user_eg2_r.c, and unix_r.c for examples.

   see user_r.h for user-definable constants

      use qh_NOmem in mem_r.h to turn off memory management
      use qh_NOmerge in user_r.h to turn off facet merging
      set qh_KEEPstatistics in user_r.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@qhull.org

   Qhull-template 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_r.c for an
   example.  We recommend keeping io.o for the extra debugging
   information it supplies.
*/

#include "qhull_ra.h"

#include 

/*---------------------------------

  Qhull-template
    Template for calling qhull from inside your program

  returns:
    exit code(see qh_ERR... in libqhull_r.h)
    all memory freed

  notes:
    This can be called any number of times.
*/
#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 html/qh-quick.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 */

  qhT qh_qh;                /* Qhull's data structure.  First argument of most calls */
  qhT *qh= &qh_qh;          /* Alternatively -- qhT *qh= (qhT *)malloc(sizeof(qhT)) */

  QHULL_LIB_CHECK /* Check for compatible library */

  qh_zero(qh, errfile);

  /* initialize dim, numpoints, points[], ismalloc here */
  exitcode= qh_new_qhull(qh, 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, !qh_ALL);
  qh_memfreeshort(qh, &curlong, &totlong);
  if (curlong || totlong)
    qh_fprintf(qh, errfile, 7079, "qhull internal warning (main): did not free %d bytes of long memory(%d pieces)\n", totlong, curlong);
}
#endif

/*---------------------------------

  qh_new_qhull(qh, dim, numpoints, points, ismalloc, qhull_cmd, outfile, errfile )
    Run qhull
    Before first call, either call qh_zero(qh, errfile), or set qh to all zero.

  returns:
    results in qh
    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().
    do not call qh_init_A (global_r.c)

    Default errfile is stderr, 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')

  see:
    Qhull-template at the beginning of this file.
    An example of using qh_new_qhull is user_eg_r.c
*/
int qh_new_qhull(qhT *qh, int dim, int numpoints, coordT *points, boolT ismalloc,
                char *qhull_cmd, FILE *outfile, FILE *errfile) {
  /* gcc may issue a "might be clobbered" warning for dim, points, and ismalloc [-Wclobbered].
     These parameters are not referenced after a longjmp() and hence not clobbered.
     See http://stackoverflow.com/questions/7721854/what-sense-do-these-clobbered-variable-warnings-make */
  int exitcode, hulldim;
  boolT new_ismalloc;
  coordT *new_points;

  if(!errfile){
    errfile= stderr;
  }
  if (!qh->qhmem.ferr) {
    qh_meminit(qh, errfile);
  } else {
    qh_memcheck(qh);
  }
  if (strncmp(qhull_cmd, "qhull ", (size_t)6) && strcmp(qhull_cmd, "qhull") != 0) {
    qh_fprintf(qh, errfile, 6186, "qhull error (qh_new_qhull): start qhull_cmd argument with \"qhull \" or set to \"qhull\"\n");
    return qh_ERRinput;
  }
  qh_initqhull_start(qh, NULL, outfile, errfile);
  if(numpoints==0 && points==NULL){
      trace1((qh, qh->ferr, 1047, "qh_new_qhull: initialize Qhull\n"));
      return 0;
  }
  trace1((qh, qh->ferr, 1044, "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(qh, 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(qh, hulldim);
      new_points= qh_sethalfspace_all(qh, dim, numpoints, points, qh->feasible_point);
      new_ismalloc= True;
      if (ismalloc)
        qh_free(points);
    }else {
      hulldim= dim;
      new_points= points;
      new_ismalloc= ismalloc;
    }
    qh_init_B(qh, new_points, numpoints, hulldim, new_ismalloc);
    qh_qhull(qh);
    qh_check_output(qh);
    if (outfile) {
      qh_produce_output(qh);
    }else {
      qh_prepare_output(qh);
    }
    if (qh->VERIFYoutput && !qh->FORCEoutput && !qh->STOPadd && !qh->STOPcone && !qh->STOPpoint)
      qh_check_points(qh);
  }
  qh->NOerrexit= True;
  return exitcode;
} /* new_qhull */

/*---------------------------------

  qh_errexit(qh, 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 libqhull_r.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(qhT *qh, int exitcode, facetT *facet, ridgeT *ridge) {

  qh->tracefacet= NULL;  /* avoid infinite recursion through qh_fprintf */
  qh->traceridge= NULL;
  qh->tracevertex= NULL;
  if (qh->ERREXITcalled) {
    qh_fprintf(qh, qh->ferr, 8126, "\nqhull error while handling previous error in qh_errexit.  Exit program\n");
    qh_exit(qh_ERRother);
  }
  qh->ERREXITcalled= True;
  if (!qh->QHULLfinished)
    qh->hulltime= qh_CPUclock - qh->hulltime;
  qh_errprint(qh, "ERRONEOUS", facet, NULL, ridge, NULL);
  qh_option(qh, "_maxoutside", NULL, &qh->MAXoutside);
  qh_fprintf(qh, qh->ferr, 8127, "\nWhile executing: %s | %s\n", qh->rbox_command, qh->qhull_command);
  qh_fprintf(qh, qh->ferr, 8128, "Options selected for Qhull %s:\n%s\n", qh_version, qh->qhull_options);
  if (qh->furthest_id >= 0) {
    qh_fprintf(qh, qh->ferr, 8129, "Last point added to hull was p%d.", qh->furthest_id);
    if (zzval_(Ztotmerge))
      qh_fprintf(qh, qh->ferr, 8130, "  Last merge was #%d.", zzval_(Ztotmerge));
    if (qh->QHULLfinished)
      qh_fprintf(qh, qh->ferr, 8131, "\nQhull has finished constructing the hull.");
    else if (qh->POSTmerging)
      qh_fprintf(qh, qh->ferr, 8132, "\nQhull has started post-merging.");
    qh_fprintf(qh, qh->ferr, 8133, "\n");
  }
  if (qh->FORCEoutput && (qh->QHULLfinished || (!facet && !ridge)))
    qh_produce_output(qh);
  else if (exitcode != qh_ERRinput) {
    if (exitcode != qh_ERRsingular && zzval_(Zsetplane) > qh->hull_dim+1) {
      qh_fprintf(qh, qh->ferr, 8134, "\nAt error exit:\n");
      qh_printsummary(qh, qh->ferr);
      if (qh->PRINTstatistics) {
        qh_collectstatistics(qh);
        qh_allstatistics(qh);
        qh_printstatistics(qh, qh->ferr, "at error exit");
        qh_memstatistics(qh, qh->ferr);
      }
    }
    if (qh->PRINTprecision)
      qh_printstats(qh, qh->ferr, qh->qhstat.precision, NULL);
  }
  if (!exitcode)
    exitcode= qh_ERRother;
  else if (exitcode == qh_ERRprec && !qh->PREmerge)
    qh_printhelp_degenerate(qh, qh->ferr);
  else if (exitcode == qh_ERRqhull)
    qh_printhelp_internal(qh, qh->ferr);
  else if (exitcode == qh_ERRsingular)
    qh_printhelp_singular(qh, qh->ferr);
  else if (exitcode == qh_ERRdebug)
    qh_fprintf(qh, qh->ferr, 8016, "qhull exit due to qh_ERRdebug\n");
  else if (exitcode == qh_ERRtopology || exitcode == qh_ERRwide || exitcode == qh_ERRprec) {
    if (qh->NOpremerge && !qh->MERGING)
      qh_printhelp_degenerate(qh, qh->ferr);
    else if (exitcode == qh_ERRtopology)
      qh_printhelp_topology(qh, qh->ferr);
    else if (exitcode == qh_ERRwide)
      qh_printhelp_wide(qh, qh->ferr);
  }else if (exitcode > 255) {
    qh_fprintf(qh, qh->ferr, 6426, "qhull internal error (qh_errexit): exit code %d is greater than 255.  Invalid argument for exit().  Replaced with 255\n", exitcode);
    exitcode= 255;
  }
  if (qh->NOerrexit) {
    qh_fprintf(qh, qh->ferr, 6187, "qhull internal error (qh_errexit): either error while reporting error QH%d, or qh.NOerrexit not cleared after setjmp(). Exit program with error status %d\n",
         qh->last_errcode, exitcode);
    qh_exit(exitcode);
  }
  qh->ERREXITcalled= False;
  qh->NOerrexit= True;
  qh->ALLOWrestart= False;  /* longjmp will undo qh_build_withrestart */
  longjmp(qh->errexit, exitcode);
} /* errexit */

/*---------------------------------

  qh_errprint(qh, 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(qhT *qh, const char *string, facetT *atfacet, facetT *otherfacet, ridgeT *atridge, vertexT *atvertex) {
  int i;

  if (atvertex) {
    qh_fprintf(qh, qh->ferr, 8138, "%s VERTEX:\n", string);
    qh_printvertex(qh, qh->ferr, atvertex);
  }
  if (atridge) {
    qh_fprintf(qh, qh->ferr, 8137, "%s RIDGE:\n", string);
    qh_printridge(qh, qh->ferr, atridge);
    if (!atfacet)
      atfacet= atridge->top;
    if (!otherfacet)
      otherfacet= otherfacet_(atridge, atfacet);
    if (atridge->top && atridge->top != atfacet && atridge->top != otherfacet)
      qh_printfacet(qh, qh->ferr, atridge->top);
    if (atridge->bottom && atridge->bottom != atfacet && atridge->bottom != otherfacet)
      qh_printfacet(qh, qh->ferr, atridge->bottom);
  }
  if (atfacet) {
    qh_fprintf(qh, qh->ferr, 8135, "%s FACET:\n", string);
    qh_printfacet(qh, qh->ferr, atfacet);
  }
  if (otherfacet) {
    qh_fprintf(qh, qh->ferr, 8136, "%s OTHER FACET:\n", string);
    qh_printfacet(qh, qh->ferr, otherfacet);
  }
  if (qh->fout && qh->FORCEoutput && atfacet && !qh->QHULLfinished && !qh->IStracing) {
    qh_fprintf(qh, qh->ferr, 8139, "ERRONEOUS and NEIGHBORING FACETS to output\n");
    for (i=0; i < qh_PRINTEND; i++)  /* use fout for geomview output */
      qh_printneighborhood(qh, qh->fout, qh->PRINTout[i], atfacet, otherfacet,
                            !qh_ALL);
  }
} /* errprint */


/*---------------------------------

  qh_printfacetlist(qh, 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(qhT *qh, facetT *facetlist, setT *facets, boolT printall) {
  facetT *facet, **facetp;

  if (facetlist)
    qh_checklists(qh, facetlist);
  qh_fprintf(qh, qh->ferr, 9424, "printfacetlist: vertices\n");
  qh_printbegin(qh, qh->ferr, qh_PRINTfacets, facetlist, facets, printall);
  if (facetlist) {
    qh_fprintf(qh, qh->ferr, 9413, "printfacetlist: facetlist\n");
    FORALLfacet_(facetlist)
      qh_printafacet(qh, qh->ferr, qh_PRINTfacets, facet, printall);
  }
  if (facets) {
    qh_fprintf(qh, qh->ferr, 9414, "printfacetlist: %d facets\n", qh_setsize(qh, facets));
    FOREACHfacet_(facets)
      qh_printafacet(qh, qh->ferr, qh_PRINTfacets, facet, printall);
  }
  qh_fprintf(qh, qh->ferr, 9412, "printfacetlist: end\n");
  qh_printend(qh, qh->ferr, qh_PRINTfacets, facetlist, facets, printall);
} /* printfacetlist */


/*---------------------------------

  qh_printhelp_degenerate(qh, fp )
    prints descriptive message for precision error with qh_ERRprec

  notes:
    no message if qh_QUICKhelp
*/
void qh_printhelp_degenerate(qhT *qh, FILE *fp) {

  if (qh->MERGEexact || qh->PREmerge || qh->JOGGLEmax < REALmax/2)
    qh_fprintf(qh, fp, 9368, "\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@qhull.org\n");
  else if (!qh_QUICKhelp) {
    qh_fprintf(qh, fp, 9369, "\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
    qh_fprintf(qh, fp, 9370, "\
\n\
Qhull is currently using single precision arithmetic.  The following\n\
will probably remove the precision problems:\n\
  - recompile qhull for realT precision(#define REALfloat 0 in user_r.h).\n");
#endif
    if (qh->DELAUNAY && !qh->SCALElast && qh->MAXabs_coord > 1e4)
      qh_fprintf(qh, fp, 9371, "\
\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)
      qh_fprintf(qh, fp, 9372, "\
When computing the Delaunay triangulation:\n\
  - use 'Qz' to add a point at-infinity.  This reduces precision problems.\n");

    qh_fprintf(qh, fp, 9373, "\
\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);
    qh_fprintf(qh, fp, 9374, "\
\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 */

/*---------------------------------

  qh_printhelp_internal(qh, fp )
    prints descriptive message for qhull internal error with qh_ERRqhull

  notes:
    no message if qh_QUICKhelp
*/
void qh_printhelp_internal(qhT *qh, FILE *fp) {

  if (!qh_QUICKhelp) {
    qh_fprintf(qh, fp, 9426, "\n\
A Qhull internal error has occurred.  Please send the input and output to\n\
qhull_bug@qhull.org. If you can duplicate the error with logging ('T4z'), please\n\
include the log file.\n");
  }
} /* printhelp_internal */

/*---------------------------------

  qh_printhelp_narrowhull(qh, minangle )
    Warn about a narrow hull

  notes:
    Alternatively, reduce qh_WARNnarrow in user_r.h

*/
void qh_printhelp_narrowhull(qhT *qh, FILE *fp, realT minangle) {

    qh_fprintf(qh, fp, 7089, "qhull precision warning: The initial hull is narrow.  Is the input lower\n\
dimensional (e.g., a square in 3-d instead of a cube)?  Cosine of the minimum\n\
angle is %.16f.  If so, Qhull may produce a wide facet.\n\
Options 'Qs' (search all points), 'Qbb' (scale last coordinate), or\n\
'QbB' (scale to unit box) may remove this warning.\n\
See 'Limitations' in qh-impre.htm.  Use 'Pp' to skip this warning.\n",
          -minangle);   /* convert from angle between normals to angle between facets */
} /* printhelp_narrowhull */

/*---------------------------------

  qh_printhelp_singular(qh, fp )
    prints descriptive message for singular input
*/
void qh_printhelp_singular(qhT *qh, FILE *fp) {
  facetT *facet;
  vertexT *vertex, **vertexp;
  realT min, max, *coord, dist;
  int i,k;

  qh_fprintf(qh, fp, 9376, "\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(qh, fp, "", qh->facet_list, NULL, qh_ALL);
  if (!qh_QUICKhelp)
    qh_fprintf(qh, fp, 9377, "\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(qh, fp, "center point", qh->hull_dim, qh->interior_point, qh_IDunknown);
  qh_fprintf(qh, fp, 9378, "\n");
  FORALLfacets {
    qh_fprintf(qh, fp, 9379, "facet");
    FOREACHvertex_(facet->vertices)
      qh_fprintf(qh, fp, 9380, " p%d", qh_pointid(qh, vertex->point));
    zinc_(Zdistio);
    qh_distplane(qh, qh->interior_point, facet, &dist);
    qh_fprintf(qh, fp, 9381, " distance= %4.2g\n", dist);
  }
  if (!qh_QUICKhelp) {
    if (qh->HALFspace)
      qh_fprintf(qh, fp, 9382, "\n\
These points are the dual of the given halfspaces.  They indicate that\n\
the intersection is degenerate.\n");
    qh_fprintf(qh, fp, 9383,"\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)
      qh_fprintf(qh, fp, 9384, "\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");
  }
  qh_fprintf(qh, fp, 9385, "\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);
    }
    qh_fprintf(qh, fp, 9386, "  %d:  %8.4g  %8.4g  difference= %4.4g\n", k, min, max, max-min);
  }
  if (!qh_QUICKhelp) {
    qh_fprintf(qh, fp, 9387, "\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
    qh_fprintf(qh, fp, 9388, "\
  - recompile qhull for realT precision(#define REALfloat 0 in libqhull_r.h).\n");
#endif
    qh_fprintf(qh, fp, 9389, "\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\
");
  }
} /* printhelp_singular */

/*---------------------------------

  qh_printhelp_topology(qh, fp )
    prints descriptive message for qhull topology error with qh_ERRtopology

  notes:
    no message if qh_QUICKhelp
*/
void qh_printhelp_topology(qhT *qh, FILE *fp) {

  if (!qh_QUICKhelp) {
    qh_fprintf(qh, fp, 9427, "\n\
A Qhull topology error has occurred.  Qhull did not recover from facet merges and vertex merges.\n\
This usually occurs when the input is nearly degenerate and substantial merging has occurred.\n\
See http://www.qhull.org/html/qh-impre.htm#limit\n");
  }
} /* printhelp_topology */

/*---------------------------------

  qh_printhelp_wide(qh, fp )
    prints descriptive message for qhull wide facet with qh_ERRwide

  notes:
    no message if qh_QUICKhelp
*/
void qh_printhelp_wide(qhT *qh, FILE *fp) {

  if (!qh_QUICKhelp) {
    qh_fprintf(qh, fp, 9428, "\n\
A wide merge error has occurred.  Qhull has produced a wide facet due to facet merges and vertex merges.\n\
This usually occurs when the input is nearly degenerate and substantial merging has occurred.\n\
See http://www.qhull.org/html/qh-impre.htm#limit\n");
  }
} /* printhelp_wide */

/*---------------------------------

  qh_user_memsizes(qh)
    allocate up to 10 additional, quick allocation sizes

  notes:
    increase maximum number of allocations in qh_initqhull_mem()
*/
void qh_user_memsizes(qhT *qh) {

  QHULL_UNUSED(qh)
  /* qh_memsize(qh, size); */
} /* user_memsizes */


qhull-2020.2/src/libqhull_r/user_r.h0000644060175106010010000010744213661102136015571 0ustar  bbarber/*
  ---------------------------------

   user_r.h
   user redefinable constants

   for each source file, user_r.h is included first

   see qh-user_r.htm.  see COPYING for copyright information.

   See user_r.c for sample code.

   before reading any code, review libqhull_r.h for data structure definitions

Sections:
   ============= qhull library constants ======================
   ============= data types and configuration macros ==========
   ============= performance related constants ================
   ============= memory constants =============================
   ============= joggle constants =============================
   ============= conditional compilation ======================
   ============= merge constants ==============================
   ============= Microsoft DevStudio ==========================

Code flags --
  NOerrors -- the code does not call qh_errexit()
  WARN64 -- the code may be incompatible with 64-bit pointers

*/

#include 
#include 
#include 

#ifndef qhDEFuser
#define qhDEFuser 1

/* Derived from Qt's corelib/global/qglobal.h */
#if !defined(SAG_COM) && !defined(__CYGWIN__) && (defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__))
#   define QHULL_OS_WIN
#elif defined(__MWERKS__) && defined(__INTEL__) /* Metrowerks discontinued before the release of Intel Macs */
#   define QHULL_OS_WIN
#endif

/*============================================================*/
/*============= qhull library constants ======================*/
/*============================================================*/

/*----------------------------------

  FILENAMElen -- max length for TI and TO filenames

*/

#define qh_FILENAMElen 500

/*----------------------------------

  msgcode -- Unique message codes for qh_fprintf

  If add new messages, assign these values and increment in user.h and user_r.h
  See QhullError.h for 10000 error codes.
  Cannot use '0031' since it would be octal

  def counters =  [31/32/33/38, 1067, 2113, 3079, 4097, 5006,
     6429, 7027/7028/7035/7068/7070/7102, 8163, 9428, 10000, 11034]

  See: qh_ERR* [libqhull_r.h]
*/

#define MSG_TRACE0     0   /* always include if logging ('Tn') */
#define MSG_TRACE1  1000
#define MSG_TRACE2  2000
#define MSG_TRACE3  3000
#define MSG_TRACE4  4000
#define MSG_TRACE5  5000
#define MSG_ERROR   6000   /* errors written to qh.ferr */
#define MSG_WARNING 7000
#define MSG_STDERR  8000   /* log messages Written to qh.ferr */
#define MSG_OUTPUT  9000
#define MSG_QHULL_ERROR 10000 /* errors thrown by QhullError.cpp (QHULLlastError is in QhullError.h) */
#define MSG_FIX    11000   /* Document as 'QH11... FIX: ...' */
#define MSG_MAXLEN  3000   /* qh_printhelp_degenerate() in user_r.c */


/*----------------------------------

  qh_OPTIONline -- max length of an option line 'FO'
*/
#define qh_OPTIONline 80

/*============================================================*/
/*============= data types and configuration macros ==========*/
/*============================================================*/

/*----------------------------------

  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
   helpful 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

/*----------------------------------

  countT
    The type for counts and identifiers (e.g., the number of points, vertex identifiers)
    Currently used by C++ code-only.  Decided against using it for setT because most sets are small.

    Defined as 'int' for C-code compatibility and QH11026

    QH11026 FIX: countT may be defined as a 'unsigned int', but several code issues need to be solved first.  See countT in Changes.txt
*/

#ifndef DEFcountT
#define DEFcountT 1
typedef int countT;
#endif
#define COUNTmax INT_MAX

/*----------------------------------

  qh_POINTSmax
    Maximum number of points for qh.num_points and point allocation in qh_readpoints
*/
#define qh_POINTSmax (INT_MAX-16)

/*----------------------------------

  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.  By default,
     defines clock_t as 'long'

   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_r.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, may be converted to approximate double */
#define qh_SECticks CLOCKS_PER_SECOND

#elif defined(CLOCKS_PER_SEC)
#define qh_CPUclock    ((unsigned long)clock())  /* return CPU clock, may be converted to approximate double */
#define qh_SECticks CLOCKS_PER_SEC

#elif defined(CLK_TCK)
#define qh_CPUclock    ((unsigned long)clock())  /* return CPU clock, may be converted to approximate double */
#define qh_SECticks CLK_TCK

#else
#define qh_CPUclock    ((unsigned long)clock())  /* return CPU clock, may be converted to approximate double */
#define qh_SECticks 1E6
#endif

#elif (qh_CLOCKtype == 2)
#define qh_CPUclock    qh_clock()  /* return CPU clock, may be converted to approximate double */
#define qh_SECticks 100

#else /* qh_CLOCKtype == ? */
#error unknown clock option
#endif

/*----------------------------------

  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(qh) with 31 bits (included with Qhull, requires 'qh')

  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_(qh, 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_(qh, seed) srand((unsigned int)seed);

#elif (qh_RANDOMtype == 3)
#define qh_RANDOMmax ((realT)0x7fffffffUL)  /* 31 bits, Sun */
#define qh_RANDOMint  rand()
#define qh_RANDOMseed_(qh, seed) srand((unsigned int)seed);

#elif (qh_RANDOMtype == 4)
#define qh_RANDOMmax ((realT)0x7fffffffUL)  /* 31 bits, lrand38()/MAX */
#define qh_RANDOMint lrand48()
#define qh_RANDOMseed_(qh, seed) srand48(seed);

#elif (qh_RANDOMtype == 5)  /* 'qh' is an implicit parameter */
#define qh_RANDOMmax ((realT)2147483646UL)  /* 31 bits, qh_rand/MAX */
#define qh_RANDOMint qh_rand(qh)
#define qh_RANDOMseed_(qh, seed) qh_srand(qh, seed);
/* unlike rand(), never returns 0 */

#else
#error: unknown random option
#endif

/*----------------------------------

  qh_ORIENTclock
    0 for inward pointing normals by Geomview convention
*/
#define qh_ORIENTclock 0

/*----------------------------------

  qh_RANDOMdist
    define for random perturbation of qh_distplane and qh_setfacetplane (qh.RANDOMdist, 'QRn')

  For testing qh.DISTround.  Qhull should not depend on computations always producing the same roundoff error 

  #define qh_RANDOMdist 1e-13
*/

/*============================================================*/
/*============= joggle constants =============================*/
/*============================================================*/

/*----------------------------------

  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

/*----------------------------------

  qh_JOGGLEincrease
    factor to increase qh.JOGGLEmax on qh_JOGGLEretry or qh_JOGGLEagain
*/
#define qh_JOGGLEincrease 10.0

/*----------------------------------

  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

/*----------------------------------

  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

/*----------------------------------

  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

/*----------------------------------

  qh_JOGGLEmaxretry
    stop after qh_JOGGLEmaxretry attempts
*/
#define qh_JOGGLEmaxretry 50

/*============================================================*/
/*============= performance related constants ================*/
/*============================================================*/

/*----------------------------------

  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

/*----------------------------------

  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

/*----------------------------------

  qh_INITIALsearch
     if qh_INITIALmax, search points up to this dimension
*/
#define qh_INITIALsearch 6

/*----------------------------------

  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

/*============================================================*/
/*============= memory constants =============================*/
/*============================================================*/

/*----------------------------------

  qh_MEMalign
    memory alignment for qh_meminitbuffers() in global_r.c

  notes:
    to avoid bus errors, memory allocation must consider alignment requirements.
    malloc() automatically takes care of alignment.   Since mem_r.c manages
    its own memory, we need to explicitly specify alignment in
    qh_meminitbuffers().

    A safe choice is sizeof(double).  sizeof(float) may be used if doubles
    do not occur in data structures and pointers are the same size.  Be careful
    of machines (e.g., DEC Alpha) with large pointers.

    If using gcc, best alignment is [fmax_() is defined in geom_r.h]
              #define qh_MEMalign fmax_(__alignof__(realT),__alignof__(void *))
*/
#define qh_MEMalign ((int)(fmax_(sizeof(realT), sizeof(void *))))

/*----------------------------------

  qh_MEMbufsize
    size of additional memory buffers

  notes:
    used for qh_meminitbuffers() in global_r.c
*/
#define qh_MEMbufsize 0x10000       /* allocate 64K memory buffers */

/*----------------------------------

  qh_MEMinitbuf
    size of initial memory buffer

  notes:
    use for qh_meminitbuffers() in global_r.c
*/
#define qh_MEMinitbuf 0x20000      /* initially allocate 128K buffer */

/*----------------------------------

  qh_INFINITE
    on output, indicates Voronoi center at infinity
*/
#define qh_INFINITE  -10.101

/*----------------------------------

  qh_DEFAULTbox
    default box size (Geomview expects 0.5)

  qh_DEFAULTbox
    default box size for integer coorindate (rbox only)
*/
#define qh_DEFAULTbox 0.5
#define qh_DEFAULTzbox 1e6

/*============================================================*/
/*============= conditional compilation ======================*/
/*============================================================*/

/*----------------------------------

  __cplusplus
    defined by C++ compilers

  __MSC_VER
    defined by Microsoft Visual C++

  __MWERKS__ && __INTEL__
    defined by Metrowerks when compiling for Windows (not Intel-based Macintosh)

  __MWERKS__ && __POWERPC__
    defined by Metrowerks when compiling for PowerPC-based Macintosh

  __STDC__
    defined for strict ANSI C
*/

/*----------------------------------

  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

/*----------------------------------

  qh_KEEPstatistics
    =0 removes most of statistic gathering and reporting

  notes:
    if 0, code size is reduced by about 4%.
*/
#define qh_KEEPstatistics 1

/*----------------------------------

  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

/*----------------------------------

  qh_NOmerge
    disables facet merging if defined
    For MSVC compiles, use qhull_r-exports-nomerge.def instead of qhull_r-exports.def

  notes:
    This saves about 25% space, 30% space in combination with qh_NOtrace, 
    and 36% with qh_NOtrace and qh_KEEPstatistics 0

    Unless option 'Q0' is used
      qh_NOmerge sets 'QJ' to avoid precision errors

  see:
    qh_NOmem in mem_r.h

    see user_r.c/user_eg.c for removing io_r.o

  #define qh_NOmerge
*/

/*----------------------------------

  qh_NOtrace
    no tracing if defined
    disables 'Tn', 'TMn', 'TPn' and 'TWn'
    override with 'Qw' for qh_addpoint tracing and various other items

  notes:
    This saves about 15% space.
    Removes all traceN((...)) code and substantial sections of qh.IStracing code

  #define qh_NOtrace
*/

#if 0  /* sample code */
    exitcode= qh_new_qhull(qhT *qh, dim, numpoints, points, ismalloc,
                      flags, outfile, errfile);
    qh_freeqhull(qhT *qh, !qh_ALL); /* frees long memory used by second call */
    qh_memfreeshort(qhT *qh, &curlong, &totlong);  /* frees short memory and memory allocator */
#endif

/*----------------------------------

  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 them.  They effect the performance of facet merging.
*/

/*----------------------------------

  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

/*----------------------------------

  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

/*----------------------------------

  qh_COPLANARratio
    for 3-d+ merging, qh.MINvisible is n*premerge_centrum

  notes:
    for non-merging, it's DISTround
*/
#define qh_COPLANARratio 3

/*----------------------------------

  qh_DIMmergeVertex
    max dimension for vertex merging (it is not effective in high-d)
*/
#define qh_DIMmergeVertex 6

/*----------------------------------

  qh_DIMreduceBuild
     max dimension for vertex reduction during build (slow in high-d)
*/
#define qh_DIMreduceBuild 5

/*----------------------------------

  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))

/*----------------------------------

  qh_MAXcheckpoint
    Report up to qh_MAXcheckpoint errors per facet in qh_check_point ('Tv')
*/
#define qh_MAXcheckpoint 10

/*----------------------------------

  qh_MAXcoplanarcentrum
    if pre-merging with qh.MERGEexact ('Qx') and f.nummerge > qh_MAXcoplanarcentrum
      use f.maxoutside instead of qh.centrum_radius for coplanarity testing

  notes:
    see qh_test_nonsimplicial_merges
    with qh.MERGEexact, a coplanar ridge is ignored until post-merging
    otherwise a large facet with many merges may take all the facets
*/
#define qh_MAXcoplanarcentrum 10

/*----------------------------------

  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

/*----------------------------------

  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

/*----------------------------------

  qh_RATIOconcavehorizon
    ratio of horizon vertex distance to max_outside for concave, twisted new facets in qh_test_nonsimplicial_merge
    if too small, end up with vertices far below merged facets
*/
#define qh_RATIOconcavehorizon 20.0

/*----------------------------------

  qh_RATIOconvexmerge
    ratio of vertex distance to qh.min_vertex for clearly convex new facets in qh_test_nonsimplicial_merge

  notes:
    must be convex for MRGtwisted
*/
#define qh_RATIOconvexmerge 10.0

/*----------------------------------

  qh_RATIOcoplanarapex
    ratio of best distance for coplanar apex vs. vertex merge in qh_getpinchedmerges

  notes:
    A coplanar apex always works, while a vertex merge may fail
*/
#define qh_RATIOcoplanarapex 3.0

/*----------------------------------

  qh_RATIOcoplanaroutside
    qh.MAXoutside ratio to repartition a coplanar point in qh_partitioncoplanar and qh_check_maxout

  notes:
    combines several tests, see qh_partitioncoplanar

*/
#define qh_RATIOcoplanaroutside 30.0

/*----------------------------------

  qh_RATIOmaxsimplex
    ratio of max determinate to estimated determinate for searching all points in qh_maxsimplex

  notes:
    As each point is added to the simplex, the max determinate is should approximate the previous determinate * qh.MAXwidth
    If maxdet is significantly less, the simplex may not be full-dimensional.
    If so, all points are searched, stopping at 10 times qh_RATIOmaxsimplex
*/
#define qh_RATIOmaxsimplex 1.0e-3

/*----------------------------------

  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, nearly incident points
*/
#define qh_RATIOnearinside 5

/*----------------------------------

  qh_RATIOpinchedsubridge
    ratio to qh.ONEmerge to accept vertices in qh_findbest_pinchedvertex
    skips search of neighboring vertices
    facet width may increase by this ratio
*/
#define qh_RATIOpinchedsubridge 10.0

/*----------------------------------

  qh_RATIOtrypinched
    ratio to qh.ONEmerge to try qh_getpinchedmerges in qh_buildcone_mergepinched
    otherwise a duplicate ridge will increase facet width by this amount
*/
#define qh_RATIOtrypinched 4.0

/*----------------------------------

  qh_RATIOtwisted
    maximum ratio to qh.ONEmerge to merge twisted facets in qh_merge_twisted
*/
#define qh_RATIOtwisted 20.0

/*----------------------------------

  qh_SEARCHdist
    When is a facet coplanar with the best facet?
    qh_findbesthorizon: all coplanar facets of the best facet need to be searched.
        increases minsearch if ischeckmax and more than 100 neighbors (is_5x_minsearch)
  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)));

/*----------------------------------

  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)

/*----------------------------------

  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

/*----------------------------------

  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

/*----------------------------------

  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

/*----------------------------------

  qh_WIDEduplicate
    merge ratio for errexit from qh_forcedmerges due to duplicate ridge
    Override with option Q12-allow-wide

  Notes:
    Merging a duplicate ridge can lead to very wide facets.
*/
#define qh_WIDEduplicate 100

/*----------------------------------

  qh_WIDEdupridge
    Merge ratio for selecting a forced dupridge merge

  Notes:
    Merging a dupridge can lead to very wide facets.
*/
#define qh_WIDEdupridge 50

/*----------------------------------

  qh_WIDEmaxoutside
    Precision ratio for maximum increase for qh.max_outside in qh_check_maxout
    Precision errors while constructing the hull, may lead to very wide facets when checked in qh_check_maxout
    Nearly incident points in 4-d and higher is the most likely culprit
    Skip qh_check_maxout with 'Q5' (no-check-outer)
    Do not error with option 'Q12' (allow-wide)
    Do not warn with options 'Q12 Pp'
*/
#define qh_WIDEmaxoutside 100

/*----------------------------------

  qh_WIDEmaxoutside2
    Precision ratio for maximum qh.max_outside in qh_check_maxout
    Skip qh_check_maxout with 'Q5' no-check-outer
    Do not error with option 'Q12' allow-wide
*/
#define qh_WIDEmaxoutside2 (10*qh_WIDEmaxoutside)


/*----------------------------------

  qh_WIDEpinched
    Merge ratio for distance between pinched vertices compared to current facet width for qh_getpinchedmerges and qh_next_vertexmerge
    Reports warning and merges duplicate ridges instead
    Enable these attempts with option Q14 merge-pinched-vertices

  notes:
    Merging pinched vertices should prevent duplicate ridges (see qh_WIDEduplicate)
    Merging the duplicate ridges may be better than merging the pinched vertices
    Found up to 45x ratio for qh_pointdist -- for ((i=1; i<20; i++)); do rbox 175 C1,6e-13 t | qhull d T4 2>&1 | tee x.1 | grep  -E 'QH|non-simplicial|Statis|pinched'; done
    Actual distance to facets is a third to a tenth of the qh_pointdist (T1)
*/
#define qh_WIDEpinched 100

/*----------------------------------

  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

/*============================================================*/
/*============= Microsoft DevStudio ==========================*/
/*============================================================*/

/*
   Finding Memory Leaks Using the CRT Library
   https://msdn.microsoft.com/en-us/library/x98tx3cf(v=vs.100).aspx

   Reports enabled in qh_lib_check for Debug window and stderr

   From 2005=>msvcr80d, 2010=>msvcr100d, 2012=>msvcr110d

   Watch: {,,msvcr80d.dll}_crtBreakAlloc  Value from {n} in the leak report
   _CrtSetBreakAlloc(689); // qh_lib_check() [global_r.c]

   Examples
     http://free-cad.sourceforge.net/SrcDocu/d2/d7f/MemDebug_8cpp_source.html
     https://github.com/illlust/Game/blob/master/library/MemoryLeak.cpp
*/
#if 0   /* off (0) by default for QHULL_CRTDBG */
#define QHULL_CRTDBG
#endif

#if defined(_MSC_VER) && defined(_DEBUG) && defined(QHULL_CRTDBG)
#define _CRTDBG_MAP_ALLOC
#include 
#include 
#endif

#endif /* qh_DEFuser */
qhull-2020.2/src/qconvex/0000755060175106010010000000000013724321420013436 5ustar  bbarberqhull-2020.2/src/qconvex/qconvex.c0000644060175106010010000003055413706714004015300 0ustar  bbarber/*
  ---------------------------------

   qconvex.c
      compute convex hulls using qhull

   see unix.c for full interface

   Copyright (c) 1993-2020, The Geometry Center
*/

#include "libqhull/libqhull.h"

#include 
#include 
#include 
#include 
#include 

#if defined(_MSC_VER)
#include 
#define isatty _isatty
/* int _isatty(int); */

#else
int isatty(int);  /* returns 1 if stdin is a tty
                   if "Undefined symbol" this can be deleted along with call in main() */
#endif

/*---------------------------------

  qh_prompt
    long prompt for qconvex

  notes:
    restricted version of libqhull.c

  notes:
    same text as unix.c
    see concise prompt below
    limit maximum literal to 1800 characters
*/

/* 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 Q10 Q11 Q15 ";

char qh_prompta[]= "\n\
qconvex -- compute the convex hull\n\
    http://www.qhull.org  %s\n\
\n\
input (stdin):\n\
    first lines: dimension and number of points (or vice-versa).\n\
    other lines: point coordinates, best if one point per line\n\
    comments:    start with a non-numeric character\n\
\n\
options:\n\
    Qc   - keep coplanar points with nearest facet\n\
    Qi   - keep interior points with nearest facet\n\
    QJ   - joggled input instead of merged facets\n\
    Qt   - triangulated output\n\
\n\
Qhull control options:\n\
    Qa   - allow input with fewer or more points than coordinates\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\
    Qs   - search all points for the initial simplex\n\
\n\
%s%s%s%s";  /* split up qh_prompt for Visual C++ */
char qh_promptb[]= "\
Qhull extra options:\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\
    Qw   - allow option warnings\n\
    Q12  - allow wide facets and wide dupridge\n\
    Q14  - merge pinched vertices that create a dupridge\n\
\n\
T options:\n\
    TFn  - report summary when n or more facets created\n\
    TI file - input file, may be enclosed in single quotes\n\
    TO file - output file, may be enclosed in single quotes\n\
    Ts   - statistics\n\
    Tv   - verify result: structure, convexity, and in-circle test\n\
    Tz   - send all output to stdout\n\
\n\
";
char qh_promptc[]= "\
Trace options:\n\
    T4   - trace at level n, 4=all, 5=mem/gauss, -1= events\n\
    Ta   - annotate output with message codes\n\
    TAn  - stop qhull after adding n vertices\n\
     TCn - stop qhull after building cone for point n\n\
     TVn - stop qhull after adding point n, -n for before\n\
    Tc   - check frequently during execution\n\
    Tf   - flush each qh_fprintf for debugging segfaults\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\
\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)\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\
    FM   - Maple output (2-d and 3-d)\n\
    Fn   - count plus neighboring facets for each facet\n\
    FN   - count plus neighboring facets for each point\n\
    Fo   - outer plane (or max_outside) for each facet\n\
    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\
                      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\
    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\
    Gc   - centrums\n\
    GDn  - drop dimension n in 3-d and 4-d output\n\
    Gh   - hyperplane intersections\n\
    Gi   - inner planes only\n\
     Gn  -  no planes\n\
     Go  -  outer planes only\n\
    Gr   - 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\
    PFn  - keep facets whose area is at least n\n\
    Pg   - print good facets (needs 'QGn' or 'QVn')\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\
    -?   - help with examples\n\
    -V   - version\n\
";
/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */

/*---------------------------------

  qh_prompt2
    synopsis for qhull
*/
char qh_prompt2[]= "\n\
qconvex -- compute the convex hull.  Qhull %s\n\
    input (stdin): dimension, number of points, point coordinates\n\
    comments start with a non-numeric character\n\
\n\
options (qconvex.htm):\n\
    Qt   - triangulated output\n\
    QJ   - joggled input instead of merged facets\n\
    Tv   - verify result: structure, convexity, and point inclusion\n\
    .    - concise list of all options\n\
    -    - one-line description of each option\n\
    -?   - this message\n\
    -V   - version\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\
    FA   - report total area and volume\n\
    FS   - total area and volume\n\
    Fx   - extreme points (convex hull vertices)\n\
    G    - Geomview output (2-d, 3-d, and 4-d)\n\
    m    - Mathematica output (2-d and 3-d)\n\
    o    - OFF format (dim, n, points, facets)\n\
    QVn  - print facets that include point n, -n if not\n\
    TI file - input file, may be enclosed in single quotes\n\
    TO file - output 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 Qc s n\n\
    rbox y 1000 W0 | qconvex s QJ              rbox d G1 D12 | qconvex QR0 FA Pp\n\
    rbox c D7 | qconvex FA TF1000\n\
\n\
";
/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */

/*---------------------------------

  qh_prompt3
    concise prompt for qhull
*/
char qh_prompt3[]= "\n\
Qhull %s\n\
Except for 'F.' and 'PG', upper-case options take an argument.\n\
\n\
 facet-dump     Geomview       incidences     mathematica    normals\n\
 off-format     points         summary\n\
\n\
 Farea          FArea-total    Fcoplanars     FCentrums      Fd-cdd-in\n\
 FD-cdd-out     FFacets-xridge Finner         FIDs           Fmerges\n\
 FMaple         Fneighbors     FNeigh-vertex  Fouter         FOptions\n\
 FPoint-near    FQhull         Fsummary       FSize          Ftriangles\n\
 Fvertices      FVertex-ave    Fxtremes\n\
\n\
 Gall-points    Gcentrums      GDrop-dim      Ghyperplanes   Ginner\n\
 Gno-planes     Gouter         Gpoints        Gridges        Gvertices\n\
\n\
 PArea-keep     Pdrop-d0:0D0   PFacet-area-keep  Pgood       PGood-neighbors\n\
 PMerge-keep    Poutput-forced Pprecision-not\n\
\n\
 Qallow-short   QbBound-0:0.5  QbB-scale-box  Qcoplanar      QGood-point\n\
 Qinterior      QJoggle        QRotate        Qsearch-all    Qtriangulate\n\
 QVertex-good   Qwarn-allow    Q12-allow-wide Q14-merge-pinched\n\
\n\
 TFacet-log     TInput-file    TOutput-file   Tstatistics    Tverify\n\
 Tz-stdout\n\
\n\
 T4-trace       Tannotate      TAdd-stop      Tcheck-often   TCone-stop\n\
 Tflush         TMerge-trace   TPoint-trace   TVertex-stop   TWide-trace\n\
\n\
 Angle-max      Centrum-size   Random-dist    Ucoplanar-max  Wide-outside\n\
";

/*---------------------------------

  main( argc, argv )
    processes the command line, calls qhull() to do the work, and exits

  design:
    initializes data structures
    reads points
    finishes initialization
    computes convex hull and other structures
    checks the result
    writes the output
    frees memory
*/
int main(int argc, char *argv[]) {
  int curlong, totlong; /* used !qh_NOmem */
  int exitcode, numpoints, dim;
  coordT *points;
  boolT ismalloc;

  QHULL_LIB_CHECK /* Check for compatible library */

  if ((argc == 1) && isatty( 0 /*stdin*/)) {
    fprintf(stdout, qh_prompt2, qh_version);
    exit(qh_ERRnone);
  }
  if (argc > 1 && *argv[1] == '-' && (*(argv[1] + 1) == '?' || *(argv[1] + 1) == '-')) { /* -? or --help */
    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);
  }
  if (argc > 1 && *argv[1] == '-' && *(argv[1]+1)=='V') {
      fprintf(stdout, "%s\n", qh_version2);
      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 NOerrexit= False;
    qh_checkflags(qh qhull_command, hidden_options);
    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(qh_ALL);
#else
  qh_freeqhull(!qh_ALL);
  qh_memfreeshort(&curlong, &totlong);
  if (curlong || totlong)
    qh_fprintf_stderr(7079, "qhull internal warning (main): did not free %d bytes of long memory(%d pieces)\n",
       totlong, curlong);
#endif
  return exitcode;
} /* main */

qhull-2020.2/src/qconvex/qconvex.pro0000644060175106010010000000033611545632020015645 0ustar  bbarber# -------------------------------------------------
# qconvex.pro -- Qt project file for qconvex.exe
# -------------------------------------------------

include(../qhull-app-c.pri)

TARGET = qconvex

SOURCES += qconvex.c
qhull-2020.2/src/qconvex/qconvex_r.c0000644060175106010010000003102713666056424015627 0ustar  bbarber/*
  ---------------------------------

   qconvex_r.c
      compute convex hulls using qhull

   see unix_r.c for full interface

   Copyright (c) 1993-2020, The Geometry Center
*/

#include "libqhull_r/libqhull_r.h"

#include 
#include 
#include 
#include 
#include 

#ifdef __cplusplus
extern "C" {
  int isatty(int);
}

#elif defined(_MSC_VER)
#include 
#define isatty _isatty
/* int _isatty(int); */

#else
int isatty(int);  /* returns 1 if stdin is a tty
                   if "Undefined symbol" this can be deleted along with call in main() */
#endif

/*---------------------------------

  qh_prompt
    long prompt for qconvex

  notes:
    restricted version of libqhull_r.c

  notes:
    same text as unix_r.c
    see concise prompt below
    limit maximum literal to 1800 characters
*/

/* 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 Q10 Q11 Q15 ";

char qh_prompta[]= "\n\
qconvex -- compute the convex hull\n\
    http://www.qhull.org  %s\n\
\n\
input (stdin):\n\
    first lines: dimension and number of points (or vice-versa).\n\
    other lines: point coordinates, best if one point per line\n\
    comments:    start with a non-numeric character\n\
\n\
options:\n\
    Qc   - keep coplanar points with nearest facet\n\
    Qi   - keep interior points with nearest facet\n\
    QJ   - joggled input instead of merged facets\n\
    Qt   - triangulated output\n\
\n\
Qhull control options:\n\
    Qa   - allow input with fewer or more points than coordinates\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\
    Qs   - search all points for the initial simplex\n\
\n\
%s%s%s%s";  /* split up qh_prompt for Visual C++ */
char qh_promptb[]= "\
Qhull extra options:\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\
    Qw   - allow option warnings\n\
    Q12  - allow wide facets and wide dupridge\n\
    Q14  - merge pinched vertices that create a dupridge\n\
\n\
T options:\n\
    TFn  - report summary when n or more facets created\n\
    TI file - input file, may be enclosed in single quotes\n\
    TO file - output file, may be enclosed in single quotes\n\
    Ts   - statistics\n\
    Tv   - verify result: structure, convexity, and in-circle test\n\
    Tz   - send all output to stdout\n\
\n\
";
char qh_promptc[]= "\
Trace options:\n\
    T4   - trace at level n, 4=all, 5=mem/gauss, -1= events\n\
    Ta   - annotate output with message codes\n\
    TAn  - stop qhull after adding n vertices\n\
     TCn - stop qhull after building cone for point n\n\
     TVn - stop qhull after adding point n, -n for before\n\
    Tc   - check frequently during execution\n\
    Tf   - flush each qh_fprintf for debugging segfaults\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\
\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)\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\
    FM   - Maple output (2-d and 3-d)\n\
    Fn   - count plus neighboring facets for each facet\n\
    FN   - count plus neighboring facets for each point\n\
    Fo   - outer plane (or max_outside) for each facet\n\
    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\
                      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\
    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\
    Gc   - centrums\n\
    GDn  - drop dimension n in 3-d and 4-d output\n\
    Gh   - hyperplane intersections\n\
    Gi   - inner planes only\n\
     Gn  -  no planes\n\
     Go  -  outer planes only\n\
    Gr   - 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\
    PFn  - keep facets whose area is at least n\n\
    Pg   - print good facets (needs 'QGn' or 'QVn')\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\
    -?   - help with examples\n\
    -V   - version\n\
";
/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */

/*---------------------------------

  qh_prompt2
    synopsis for qhull
*/
char qh_prompt2[]= "\n\
qconvex -- compute the convex hull.  Qhull %s\n\
    input (stdin): dimension, number of points, point coordinates\n\
    comments start with a non-numeric character\n\
\n\
options (qconvex.htm):\n\
    Qt   - triangulated output\n\
    QJ   - joggled input instead of merged facets\n\
    Tv   - verify result: structure, convexity, and point inclusion\n\
    .    - concise list of all options\n\
    -    - one-line description of each option\n\
    -?   - this message\n\
    -V   - version\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\
    FA   - report total area and volume\n\
    FS   - total area and volume\n\
    Fx   - extreme points (convex hull vertices)\n\
    G    - Geomview output (2-d, 3-d, and 4-d)\n\
    m    - Mathematica output (2-d and 3-d)\n\
    o    - OFF format (dim, n, points, facets)\n\
    QVn  - print facets that include point n, -n if not\n\
    TI file - input file, may be enclosed in single quotes\n\
    TO file - output 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 Qc s n\n\
    rbox y 1000 W0 | qconvex s QJ              rbox d G1 D12 | qconvex QR0 FA Pp\n\
    rbox c D7 | qconvex FA TF1000\n\
\n\
";
/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */

/*---------------------------------

  qh_prompt3
    concise prompt for qhull
*/
char qh_prompt3[]= "\n\
Qhull %s\n\
Except for 'F.' and 'PG', upper-case options take an argument.\n\
\n\
 facet-dump     Geomview       incidences     mathematica    normals\n\
 off-format     points         summary\n\
\n\
 Farea          FArea-total    Fcoplanars     FCentrums      Fd-cdd-in\n\
 FD-cdd-out     FFacets-xridge Finner         FIDs           Fmerges\n\
 FMaple         Fneighbors     FNeigh-vertex  Fouter         FOptions\n\
 FPoint-near    FQhull         Fsummary       FSize          Ftriangles\n\
 Fvertices      FVertex-ave    Fxtremes\n\
\n\
 Gall-points    Gcentrums      GDrop-dim      Ghyperplanes   Ginner\n\
 Gno-planes     Gouter         Gpoints        Gridges        Gvertices\n\
\n\
 PArea-keep     Pdrop-d0:0D0   PFacet-area-keep  Pgood       PGood-neighbors\n\
 PMerge-keep    Poutput-forced Pprecision-not\n\
\n\
 Qallow-short   QbBound-0:0.5  QbB-scale-box  Qcoplanar      QGood-point\n\
 Qinterior      QJoggle        QRotate        Qsearch-all    Qtriangulate\n\
 QVertex-good   Qwarn-allow    Q12-allow-wide Q14-merge-pinched\n\
\n\
 TFacet-log     TInput-file    TOutput-file   Tstatistics    Tverify\n\
 Tz-stdout\n\
\n\
 T4-trace       Tannotate      TAdd-stop      Tcheck-often   TCone-stop\n\
 Tflush         TMerge-trace   TPoint-trace   TVertex-stop   TWide-trace\n\
\n\
 Angle-max      Centrum-size   Random-dist    Ucoplanar-max  Wide-outside\n\
";

/*---------------------------------

  main( argc, argv )
    processes the command line, calls qhull() to do the work, and exits

  design:
    initializes data structures
    reads points
    finishes initialization
    computes convex hull and other structures
    checks the result
    writes the output
    frees memory
*/
int main(int argc, char *argv[]) {
  int curlong, totlong; /* used !qh_NOmem */
  int exitcode, numpoints, dim;
  coordT *points;
  boolT ismalloc;
  qhT qh_qh;
  qhT *qh= &qh_qh;

  QHULL_LIB_CHECK /* Check for compatible library */

  if ((argc == 1) && isatty( 0 /*stdin*/)) {
    fprintf(stdout, qh_prompt2, qh_version);
    exit(qh_ERRnone);
  }
  if (argc > 1 && *argv[1] == '-' && (*(argv[1] + 1) == '?' || *(argv[1] + 1) == '-')) { /* -? or --help */
    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);
  }
  if (argc > 1 && *argv[1] == '-' && *(argv[1]+1)=='V') {
      fprintf(stdout, "%s\n", qh_version2);
      exit(qh_ERRnone);
  }
  qh_init_A(qh, stdin, stdout, stderr, argc, argv);  /* sets qh->qhull_command */
  exitcode= setjmp(qh->errexit); /* simple statement for CRAY J916 */
  if (!exitcode) {
    qh->NOerrexit = False;
    qh_checkflags(qh, qh->qhull_command, hidden_options);
    qh_initflags(qh, qh->qhull_command);
    points= qh_readpoints(qh, &numpoints, &dim, &ismalloc);
    qh_init_B(qh, points, numpoints, dim, ismalloc);
    qh_qhull(qh);
    qh_check_output(qh);
    qh_produce_output(qh);
    if (qh->VERIFYoutput && !qh->FORCEoutput && !qh->STOPpoint && !qh->STOPcone)
      qh_check_points(qh);
    exitcode= qh_ERRnone;
  }
  qh->NOerrexit= True;  /* no more setjmp */
#ifdef qh_NOmem
  qh_freeqhull(qh, qh_ALL);
#else
  qh_freeqhull(qh, !qh_ALL);
  qh_memfreeshort(qh, &curlong, &totlong);
  if (curlong || totlong)
    qh_fprintf_stderr(7079, "qhull internal warning (main): did not free %d bytes of long memory(%d pieces)\n",
       totlong, curlong);
#endif
  return exitcode;
} /* main */

qhull-2020.2/src/qdelaunay/0000755060175106010010000000000013724321421013737 5ustar  bbarberqhull-2020.2/src/qdelaunay/qdelaun.c0000644060175106010010000003026013706714004015540 0ustar  bbarber/*
  ---------------------------------

   qdelaun.c
     compute Delaunay triangulations and furthest-point Delaunay
     triangulations using qhull

   see unix.c for full interface

   Copyright (c) 1993-2020, The Geometry Center
*/

#include "libqhull/libqhull.h"

#include 
#include 
#include 
#include 
#include 

#if defined(_MSC_VER)
#include 
#define isatty _isatty
/* int _isatty(int); */

#else
int isatty(int);  /* returns 1 if stdin is a tty
                   if "Undefined symbol" this can be deleted along with call in main() */
#endif

/*---------------------------------

  qh_prompt
    long prompt for qhull

  notes:
    restricted version of libqhull.c

  notes:
    same text as unix.c
    see concise prompt below
    limit maximum literal to 1800 characters
*/

/* duplicated in qdelau_f.htm and qdelaun.htm */
char hidden_options[]=" d n v H U Qb QB Qc Qf Qg Qi Qm Qr Qv Qx TR E V FC Fi Fo Ft Fp FV Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 Q10 Q11 Q15 ";

char qh_prompta[]= "\n\
qdelaunay -- compute the Delaunay triangulation\n\
    http://www.qhull.org  %s\n\
\n\
input (stdin):\n\
    first lines: dimension and number of points (or vice-versa).\n\
    other lines: point coordinates, best if one point per line\n\
    comments:    start with a non-numeric character\n\
\n\
options:\n\
    QJ   - joggled input instead of merged facets\n\
    Qt   - triangulated output\n\
    Qu   - compute furthest-site Delaunay triangulation\n\
\n\
Qhull control options:\n\
    Qa   - allow input with fewer or more points than coordinates\n\
    QJn  - randomly joggle input in range [-n,n]\n\
    QRn  - random rotation (n=seed, n=0 time, n=-1 time/no rotate)\n\
    Qs   - search all points for the initial simplex\n\
    Qz   - add point-at-infinity to Delaunay triangulation\n\
\n\
%s%s%s%s";  /* split up qh_prompt for Visual C++ */
char qh_promptb[]= "\
Qhull extra options:\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\
    Qw   - allow option warnings\n\
    Q12  - allow wide facets and wide dupridge\n\
    Q14  - merge pinched vertices that create a dupridge\n\
\n\
T options:\n\
    TFn  - report summary when n or more facets created\n\
    TI file - input file, may be enclosed in single quotes\n\
    TO file - output file, may be enclosed in single quotes\n\
    Ts   - statistics\n\
    Tv   - verify result: structure, convexity, and in-circle test\n\
    Tz   - send all output to stdout\n\
\n\
";
char qh_promptc[]= "\
Trace options:\n\
    T4   - trace at level n, 4=all, 5=mem/gauss, -1= events\n\
    Ta   - annotate output with message codes\n\
    TAn  - stop qhull after adding n vertices\n\
     TCn - stop qhull after building cone for point n\n\
     TVn - stop qhull after adding point n, -n for before\n\
    Tc   - check frequently during execution\n\
    Tf   - flush each qh_fprintf for debugging segfaults\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\
\n\
Precision options:\n\
    Cn   - radius of centrum (roundoff added).  Merge facets if non-convex\n\
     An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex\n\
           C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge\n\
    Rn   - randomly perturb computations by a factor of [1-n,1+n]\n\
    Wn   - min facet width for outside point (before roundoff)\n\
\n\
Output formats (may be combined; if none, produces a summary to stdout):\n\
    f    - facet dump\n\
    G    - Geomview output (see below)\n\
    i    - vertices incident to each Delaunay region\n\
    m    - Mathematica output (2-d only, lifted to a paraboloid)\n\
    o    - OFF format (dim, points, and facets as a paraboloid)\n\
    p    - point coordinates (lifted to a paraboloid)\n\
    s    - summary (stderr)\n\
\n\
";
char qh_promptd[]= "\
More formats:\n\
    Fa   - area for each Delaunay region\n\
    FA   - compute total area for option 's'\n\
    Fc   - count plus coincident points for each Delaunay region\n\
    Fd   - use cdd format for input (homogeneous with offset first)\n\
    FD   - use cdd format for numeric output (offset first)\n\
    FF   - facet dump without ridges\n\
    FI   - ID of each Delaunay region\n\
    Fm   - merge count for each Delaunay region (511 max)\n\
    FM   - Maple output (2-d only, lifted to a paraboloid)\n\
    Fn   - count plus neighboring region for each Delaunay region\n\
    FN   - count plus neighboring region for each point\n\
    FO   - options and precision constants\n\
    FP   - nearest point and distance for each coincident point\n\
    FQ   - command used for qdelaunay\n\
    Fs   - summary: #int (8), dimension, #points, tot vertices, tot facets,\n\
                    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 output (2-d and 3-d points lifted to a paraboloid)\n\
    Ga   - all points as dots\n\
     Gp  -  coplanar points and vertices as radii\n\
     Gv  -  vertices as spheres\n\
    Gc   - centrums\n\
    GDn  - drop dimension n in 3-d and 4-d output\n\
    Gh   - hyperplane intersections\n\
    Gi   - inner planes only\n\
     Gn  -  no planes\n\
     Go  -  outer planes only\n\
    Gr   - ridges\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\
    PFn  - keep Delaunay regions whose area is at least n\n\
    Pg   - print good Delaunay regions (needs 'QGn' or 'QVn')\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\
    -?   - help with examples\n\
    -V   - version\n\
";
/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */

/*---------------------------------

  qh_prompt2
    synopsis for qhull
*/
char qh_prompt2[]= "\n\
qdelaunay -- compute the Delaunay triangulation.  Qhull %s\n\
    input (stdin): dimension, number of points, point coordinates\n\
    comments start with a non-numeric character\n\
\n\
options (qdelaun.htm):\n\
    Qu   - furthest-site Delaunay triangulation\n\
    Qt   - triangulated output\n\
    QJ   - joggled input instead of merged facets\n\
    Tv   - verify result: structure, convexity, and in-circle test\n\
    .    - concise list of all options\n\
    -    - one-line description of each option\n\
    -?   - this message\n\
    -V   - version\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\
    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\
    o    - OFF format (shows the points lifted to a paraboloid)\n\
    QVn  - print Delaunay regions that include point n, -n if not\n\
    TI file - input file, may be enclosed in single quotes\n\
    TO file - output file, may be enclosed in single quotes\n\
\n\
examples:\n\
    rbox c P0 D2 | qdelaunay s o          rbox c P0 D2 | qdelaunay i\n\
    rbox c P0 D2 | qdelaunay Fv           rbox c P0 D2 | qdelaunay s Qu Fv\n\
    rbox c G1 d D2 | qdelaunay s i        rbox c G1 d D2 | qdelaunay Qt\n\
    rbox M3,4 z 100 D2 | qdelaunay s      rbox M3,4 z 100 D2 | qdelaunay s Qt\n\
\n\
";
/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */

/*---------------------------------

  qh_prompt3
    concise prompt for qhull
*/
char qh_prompt3[]= "\n\
Qhull %s\n\
Except for 'F.' and 'PG', upper-case options take an argument.\n\
\n\
 facet-dump     Geomview       incidences     mathematica    off-format\n\
 points-lifted  summary\n\
\n\
 Farea          FArea-total    Fcoincident    Fd-cdd-in      FD-cdd-out\n\
 FF-dump-xridge FIDs           Fmerges        FMaple         Fneighbors\n\
 FNeigh-vertex  FOptions       FPoint-near    FQdelaun       Fsummary\n\
 FSize          Fvertices      Fxtremes\n\
\n\
 Gall-points    Gcentrums      GDrop-dim      Ghyperplanes   Ginner\n\
 Gno-planes     Gouter         Gpoints        Gridges        Gtransparent\n\
 Gvertices\n\
\n\
 PArea-keep     Pdrop-d0:0D0   PFacet-area-keep  Pgood       PGood-neighbors\n\
 PMerge-keep    Poutput-forced Pprecision-not\n\
\n\
 Qallow-short   QGood-point    QJoggle        Qrotate        Qsearch-all\n\
 Qtriangulate   QupperDelaunay QVertex-good   Qwarn-allow    Qzinfinite\n\
 Q12-allow-wide Q14-merge-pinched\n\
\n\
 TFacet-log     TInput-file    TOutput-file   Tstatistics    Tverify\n\
 Tz-stdout\n\
\n\
 T4-trace       Tannotate      TAdd-stop      Tcheck-often   TCone-stop\n\
 Tflush         TMerge-trace   TPoint-trace   TVertex-stop   TWide-trace\n\
\n\
 Angle-max      Centrum-size   Random-dist    Wide-outside\n\
";

/*---------------------------------

  main( argc, argv )
    processes the command line, calls qhull() to do the work, and exits

  design:
    initializes data structures
    reads points
    finishes initialization
    computes convex hull and other structures
    checks the result
    writes the output
    frees memory
*/
int main(int argc, char *argv[]) {
  int curlong, totlong; /* used !qh_NOmem */
  int exitcode, numpoints, dim;
  coordT *points;
  boolT ismalloc;

  QHULL_LIB_CHECK /* Check for compatible library */

  if ((argc == 1) && isatty( 0 /*stdin*/)) {
    fprintf(stdout, qh_prompt2, qh_version);
    exit(qh_ERRnone);
  }
  if (argc > 1 && *argv[1] == '-' && (*(argv[1] + 1) == '?' || *(argv[1] + 1) == '-')) { /* -? or --help */
    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);
  }
  if (argc > 1 && *argv[1] == '-' && *(argv[1]+1)=='V') {
      fprintf(stdout, "%s\n", qh_version2);
      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 NOerrexit= False;
    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);
    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(qh_ALL);
#else
  qh_freeqhull(!qh_ALL);
  qh_memfreeshort(&curlong, &totlong);
  if (curlong || totlong)
    qh_fprintf_stderr(7079, "qhull internal warning (main): did not free %d bytes of long memory(%d pieces)\n",
       totlong, curlong);
#endif
  return exitcode;
} /* main */

qhull-2020.2/src/qdelaunay/qdelaunay.pro0000644060175106010010000000034311545632020016443 0ustar  bbarber# -------------------------------------------------
# qdelaunay.pro -- Qt project file for qvoronoi.exe
# -------------------------------------------------

include(../qhull-app-c.pri)

TARGET = qdelaunay

SOURCES += qdelaun.c
qhull-2020.2/src/qdelaunay/qdelaun_r.c0000644060175106010010000003054213661633606016074 0ustar  bbarber/*
  ---------------------------------

   qdelaun_r.c
     compute Delaunay triangulations and furthest-point Delaunay
     triangulations using qhull

   see unix_r.c for full interface

   Copyright (c) 1993-2020, The Geometry Center
*/

#include "libqhull_r/libqhull_r.h"

#include 
#include 
#include 
#include 
#include 

#ifdef __cplusplus
extern "C" {
  int isatty(int);
}

#elif defined(_MSC_VER)
#include 
#define isatty _isatty
/* int _isatty(int); */

#else
int isatty(int);  /* returns 1 if stdin is a tty
                   if "Undefined symbol" this can be deleted along with call in main() */
#endif

/*---------------------------------

  qh_prompt
    long prompt for qhull

  notes:
    restricted version of libqhull_r.c

  notes:
    same text as unix_r.c
    see concise prompt below
    limit maximum literal to 1800 characters
*/

/* duplicated in qdelau_f.htm and qdelaun.htm */
char hidden_options[]=" d n v H U Qb QB Qc Qf Qg Qi Qm Qr Qv Qx TR E V FC Fi Fo Ft Fp FV Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 Q10 Q11 Q15 ";

char qh_prompta[]= "\n\
qdelaunay -- compute the Delaunay triangulation\n\
    http://www.qhull.org  %s\n\
\n\
input (stdin):\n\
    first lines: dimension and number of points (or vice-versa).\n\
    other lines: point coordinates, best if one point per line\n\
    comments:    start with a non-numeric character\n\
\n\
options:\n\
    QJ   - joggled input instead of merged facets\n\
    Qt   - triangulated output\n\
    Qu   - compute furthest-site Delaunay triangulation\n\
\n\
Qhull control options:\n\
    Qa   - allow input with fewer or more points than coordinates\n\
    QJn  - randomly joggle input in range [-n,n]\n\
    QRn  - random rotation (n=seed, n=0 time, n=-1 time/no rotate)\n\
    Qs   - search all points for the initial simplex\n\
    Qz   - add point-at-infinity to Delaunay triangulation\n\
\n\
%s%s%s%s";  /* split up qh_prompt for Visual C++ */
char qh_promptb[]= "\
Qhull extra options:\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\
    Qw   - allow option warnings\n\
    Q12  - allow wide facets and wide dupridge\n\
    Q14  - merge pinched vertices that create a dupridge\n\
\n\
T options:\n\
    TFn  - report summary when n or more facets created\n\
    TI file - input file, may be enclosed in single quotes\n\
    TO file - output file, may be enclosed in single quotes\n\
    Ts   - statistics\n\
    Tv   - verify result: structure, convexity, and in-circle test\n\
    Tz   - send all output to stdout\n\
\n\
";
char qh_promptc[]= "\
Trace options:\n\
    T4   - trace at level n, 4=all, 5=mem/gauss, -1= events\n\
    Ta   - annotate output with message codes\n\
    TAn  - stop qhull after adding n vertices\n\
     TCn - stop qhull after building cone for point n\n\
     TVn - stop qhull after adding point n, -n for before\n\
    Tc   - check frequently during execution\n\
    Tf   - flush each qh_fprintf for debugging segfaults\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\
\n\
Precision options:\n\
    Cn   - radius of centrum (roundoff added).  Merge facets if non-convex\n\
     An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex\n\
           C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge\n\
    Rn   - randomly perturb computations by a factor of [1-n,1+n]\n\
    Wn   - min facet width for outside point (before roundoff)\n\
\n\
Output formats (may be combined; if none, produces a summary to stdout):\n\
    f    - facet dump\n\
    G    - Geomview output (see below)\n\
    i    - vertices incident to each Delaunay region\n\
    m    - Mathematica output (2-d only, lifted to a paraboloid)\n\
    o    - OFF format (dim, points, and facets as a paraboloid)\n\
    p    - point coordinates (lifted to a paraboloid)\n\
    s    - summary (stderr)\n\
\n\
";
char qh_promptd[]= "\
More formats:\n\
    Fa   - area for each Delaunay region\n\
    FA   - compute total area for option 's'\n\
    Fc   - count plus coincident points for each Delaunay region\n\
    Fd   - use cdd format for input (homogeneous with offset first)\n\
    FD   - use cdd format for numeric output (offset first)\n\
    FF   - facet dump without ridges\n\
    FI   - ID of each Delaunay region\n\
    Fm   - merge count for each Delaunay region (511 max)\n\
    FM   - Maple output (2-d only, lifted to a paraboloid)\n\
    Fn   - count plus neighboring region for each Delaunay region\n\
    FN   - count plus neighboring region for each point\n\
    FO   - options and precision constants\n\
    FP   - nearest point and distance for each coincident point\n\
    FQ   - command used for qdelaunay\n\
    Fs   - summary: #int (8), dimension, #points, tot vertices, tot facets,\n\
                    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 output (2-d and 3-d points lifted to a paraboloid)\n\
    Ga   - all points as dots\n\
     Gp  -  coplanar points and vertices as radii\n\
     Gv  -  vertices as spheres\n\
    Gc   - centrums\n\
    GDn  - drop dimension n in 3-d and 4-d output\n\
    Gh   - hyperplane intersections\n\
    Gi   - inner planes only\n\
     Gn  -  no planes\n\
     Go  -  outer planes only\n\
    Gr   - ridges\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\
    PFn  - keep Delaunay regions whose area is at least n\n\
    Pg   - print good Delaunay regions (needs 'QGn' or 'QVn')\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\
    -?   - help with examples\n\
    -V   - version\n\
";
/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */

/*---------------------------------

  qh_prompt2
    synopsis for qhull
*/
char qh_prompt2[]= "\n\
qdelaunay -- compute the Delaunay triangulation.  Qhull %s\n\
    input (stdin): dimension, number of points, point coordinates\n\
    comments start with a non-numeric character\n\
\n\
options (qdelaun.htm):\n\
    Qu   - furthest-site Delaunay triangulation\n\
    Qt   - triangulated output\n\
    QJ   - joggled input instead of merged facets\n\
    Tv   - verify result: structure, convexity, and in-circle test\n\
    .    - concise list of all options\n\
    -    - one-line description of each option\n\
    -?   - this message\n\
    -V   - version\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\
    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\
    o    - OFF format (shows the points lifted to a paraboloid)\n\
    QVn  - print Delaunay regions that include point n, -n if not\n\
    TI file - input file, may be enclosed in single quotes\n\
    TO file - output file, may be enclosed in single quotes\n\
\n\
examples:\n\
    rbox c P0 D2 | qdelaunay s o          rbox c P0 D2 | qdelaunay i\n\
    rbox c P0 D2 | qdelaunay Fv           rbox c P0 D2 | qdelaunay s Qu Fv\n\
    rbox c G1 d D2 | qdelaunay s i        rbox c G1 d D2 | qdelaunay Qt\n\
    rbox M3,4 z 100 D2 | qdelaunay s      rbox M3,4 z 100 D2 | qdelaunay s Qt\n\
\n\
";
/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */

/*---------------------------------

  qh_prompt3
    concise prompt for qhull
*/
char qh_prompt3[]= "\n\
Qhull %s\n\
Except for 'F.' and 'PG', upper-case options take an argument.\n\
\n\
 facet-dump     Geomview       incidences     mathematica    off-format\n\
 points-lifted  summary\n\
\n\
 Farea          FArea-total    Fcoincident    Fd-cdd-in      FD-cdd-out\n\
 FF-dump-xridge FIDs           Fmerges        FMaple         Fneighbors\n\
 FNeigh-vertex  FOptions       FPoint-near    FQdelaun       Fsummary\n\
 FSize          Fvertices      Fxtremes\n\
\n\
 Gall-points    Gcentrums      GDrop-dim      Ghyperplanes   Ginner\n\
 Gno-planes     Gouter         Gpoints        Gridges        Gtransparent\n\
 Gvertices\n\
\n\
 PArea-keep     Pdrop-d0:0D0   PFacet-area-keep  Pgood       PGood-neighbors\n\
 PMerge-keep    Poutput-forced Pprecision-not\n\
\n\
 Qallow-short   QGood-point    QJoggle        Qrotate        Qsearch-all\n\
 Qtriangulate   QupperDelaunay QVertex-good   Qwarn-allow    Qzinfinite\n\
 Q12-allow-wide Q14-merge-pinched\n\
\n\
 TFacet-log     TInput-file    TOutput-file   Tstatistics    Tverify\n\
 Tz-stdout\n\
\n\
 T4-trace       Tannotate      TAdd-stop      Tcheck-often   TCone-stop\n\
 Tflush         TMerge-trace   TPoint-trace   TVertex-stop   TWide-trace\n\
\n\
 Angle-max      Centrum-size   Random-dist    Wide-outside\n\
";

/*---------------------------------

  main( argc, argv )
    processes the command line, calls qhull() to do the work, and exits

  design:
    initializes data structures
    reads points
    finishes initialization
    computes convex hull and other structures
    checks the result
    writes the output
    frees memory
*/
int main(int argc, char *argv[]) {
  int curlong, totlong; /* used !qh_NOmem */
  int exitcode, numpoints, dim;
  coordT *points;
  boolT ismalloc;
  qhT qh_qh;
  qhT *qh= &qh_qh;

  QHULL_LIB_CHECK /* Check for compatible library */

  if ((argc == 1) && isatty( 0 /*stdin*/)) {
    fprintf(stdout, qh_prompt2, qh_version);
    exit(qh_ERRnone);
  }
  if (argc > 1 && *argv[1] == '-' && (*(argv[1] + 1) == '?' || *(argv[1] + 1) == '-')) { /* -? or --help */
    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);
  }
  if (argc > 1 && *argv[1] == '-' && *(argv[1]+1)=='V') {
      fprintf(stdout, "%s\n", qh_version2);
      exit(qh_ERRnone);
  }
  qh_init_A(qh, stdin, stdout, stderr, argc, argv);  /* sets qh->qhull_command */
  exitcode= setjmp(qh->errexit); /* simple statement for CRAY J916 */
  if (!exitcode) {
    qh->NOerrexit = False;
    qh_option(qh, "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, qh->qhull_command, hidden_options);
    qh_initflags(qh, qh->qhull_command);
    points= qh_readpoints(qh, &numpoints, &dim, &ismalloc);
    qh_init_B(qh, points, numpoints, dim, ismalloc);
    qh_qhull(qh);
    qh_check_output(qh);
    qh_produce_output(qh);
    if (qh->VERIFYoutput && !qh->FORCEoutput && !qh->STOPpoint && !qh->STOPcone)
      qh_check_points(qh);
    exitcode= qh_ERRnone;
  }
  qh->NOerrexit= True;  /* no more setjmp */
#ifdef qh_NOmem
  qh_freeqhull(qh, qh_ALL);
#else
  qh_freeqhull(qh, !qh_ALL);
  qh_memfreeshort(qh, &curlong, &totlong);
  if (curlong || totlong)
    qh_fprintf_stderr(7079, "qhull internal warning (main): did not free %d bytes of long memory(%d pieces)\n",
       totlong, curlong);
#endif
  return exitcode;
} /* main */

qhull-2020.2/src/qhalf/0000755060175106010010000000000013724321422013050 5ustar  bbarberqhull-2020.2/src/qhalf/qhalf.c0000644060175106010010000003023313664272550014322 0ustar  bbarber/*
  ---------------------------------

   qhalf.c
     compute the intersection of halfspaces about a point

   see unix.c for full interface

   Copyright (c) 1993-2020, The Geometry Center
*/

#include "libqhull/libqhull.h"

#include 
#include 
#include 
#include 
#include 

#if defined(_MSC_VER)
#include 
#define isatty _isatty
/* int _isatty(int); */

#else
int isatty(int);  /* returns 1 if stdin is a tty
                   if "Undefined symbol" this can be deleted along with call in main() */
#endif

/*---------------------------------

  qh_prompt
    long prompt for qhull

  notes:
    restricted version of libqhull.c
    same text as unix.c
    see concise prompt below
    limit maximum literal to 1800 characters
*/

/* duplicated in qhalf.htm */
char hidden_options[]=" d n v Qbb QbB Qf Qg Qm 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 Q10 Q11 Q15 ";

char qh_prompta[]= "\n\
qhalf -- compute the intersection of halfspaces about a point\n\
    http://www.qhull.org  %s\n\
\n\
input (stdin):\n\
    optional interior point: dimension, 1, coordinates\n\
    first lines: dimension+1 and number of halfspaces\n\
    other lines: halfspace coefficients followed by offset\n\
    comments:    start with a non-numeric character\n\
\n\
options:\n\
    Hn,n - specify coordinates of interior point\n\
    Qc   - keep coplanar halfspaces\n\
    Qi   - keep other redundant halfspaces\n\
    QJ   - joggled input instead of merged facets\n\
    Qt   - triangulated output\n\
\n\
Qhull control options:\n\
    Qa   - allow input with fewer or more points than coordinates\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\
    Qs   - search all halfspaces for the initial simplex\n\
\n\
%s%s%s%s";  /* split up qh_prompt for Visual C++ */
char qh_promptb[]= "\
Qhull extra options:\n\
    QGn  - print intersection if visible to halfspace n, -n for not\n\
    QVn  - print intersections for halfspace n, -n if not\n\
    Qw   - allow option warnings\n\
    Q12  - allow wide facets and wide dupridge\n\
    Q14  - merge pinched vertices that create a dupridge\n\
\n\
T options:\n\
    TFn  - report summary when n or more facets created\n\
    TI file - input file, may be enclosed in single quotes\n\
    TO file - output file, may be enclosed in single quotes\n\
    Ts   - statistics\n\
    Tv   - verify result: structure, convexity, and in-circle test\n\
    Tz   - send all output to stdout\n\
\n\
";
char qh_promptc[]= "\
Trace options:\n\
    T4   - trace at level n, 4=all, 5=mem/gauss, -1= events\n\
    Ta   - annotate output with message codes\n\
    TAn  - stop qhull after adding n vertices\n\
     TCn - stop qhull after building cone for point n\n\
     TVn - stop qhull after adding point n, -n for before\n\
    Tc   - check frequently during execution\n\
    Tf   - flush each qh_fprintf for debugging segfaults\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\
\n\
Precision options:\n\
    Cn   - radius of centrum (roundoff added).  Merge facets if non-convex\n\
     An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex\n\
           C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge\n\
    Rn   - randomly perturb computations by a factor of [1-n,1+n]\n\
    Un   - max distance below plane for a new, coplanar halfspace\n\
    Wn   - min facet width for outside halfspace (before roundoff)\n\
\n\
Output formats (may be combined; if none, produces a summary to stdout):\n\
    f    - facet dump\n\
    G    - Geomview output (dual convex hull)\n\
    i    - non-redundant halfspaces incident to each intersection\n\
    m    - Mathematica output (dual convex hull)\n\
    o    - OFF format (dual convex hull: dimension, points, and facets)\n\
    p    - vertex coordinates of dual convex hull (coplanars if 'Qc' or 'Qi')\n\
    s    - summary (stderr)\n\
\n\
";
char qh_promptd[]= "\
More formats:\n\
    Fc   - count plus redundant halfspaces for each intersection\n\
         -   Qc (default) for coplanar and Qi for other redundant\n\
    Fd   - use cdd format for input (homogeneous with offset first)\n\
    FF   - facet dump without ridges\n\
    FI   - ID of each intersection\n\
    Fm   - merge count for each intersection (511 max)\n\
    FM   - Maple output (dual 2-d or 3-d convex hull)\n\
    Fn   - count plus neighboring intersections for each intersection\n\
    FN   - count plus intersections for each 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\
                      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\
    Gc   - centrums\n\
    GDn  - drop dimension n in 3-d and 4-d output\n\
    Gh   - hyperplane intersections\n\
    Gi   - inner planes (i.e., halfspace intersections) only\n\
     Gn  -  no planes\n\
     Go  -  outer planes only\n\
    Gr   - ridges\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\
    PFn  - keep facets whose area is at least n\n\
    Pg   - print good facets (needs 'QGn' or 'QVn')\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\
    -?   - help with examples\n\
    -V   - version\n\
";
/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */

/*---------------------------------

  qh_prompt2
    synopsis for qhull
*/
char qh_prompt2[]= "\n\
qhalf -- halfspace intersection about a point.  Qhull %s\n\
    input (stdin): [dimension, 1, interior point]\n\
                       dimension+1, number of halfspaces, 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 each option\n\
    -?   - this message\n\
    -V   - version\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\
    G    - Geomview output (dual convex hull)\n\
    m    - Mathematica output (dual convex hull)\n\
    o    - OFF file format (dual convex hull)\n\
    QVn  - print intersections for halfspace n, -n if not\n\
    TI file - input file, may be enclosed in single quotes\n\
    TO file - output file, may be enclosed in single quotes\n\
\n\
examples:\n\
    rbox d | qconvex FQ n | qhalf s H0,0,0 Fp\n\
    rbox c | qconvex FQ FV n | qhalf s i\n\
    rbox c | qconvex FQ FV n | qhalf s o\n\
\n\
";
/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */

/*---------------------------------

  qh_prompt3
    concise prompt for qhull
*/
char qh_prompt3[]= "\n\
Qhull %s\n\
Except for 'F.' and 'PG', upper_case options take an argument.\n\
\n\
 facet-dump     Geomview       H0,0-interior incidences      mathematica\n\
 off-format     point-dual     summary\n\
\n\
 Fc-redundant   Fd-cdd-in      FF-dump-xridge FIDs           Fmerges\n\
 FMaple         Fneighbors     FN-intersect   FOptions       Fp-coordinates\n\
 FP-nearest     FQhalf         Fsummary       Fv-halfspace   Fx-non-redundant\n\
\n\
 Gall-points    Gcentrums      GDrop-dim      Ghyperplanes   Ginner\n\
 Gno-planes     Gouter         Gpoints        Gridges        Gvertices\n\
\n\
 PArea-keep     Pdrop-d0:0D0   PFacet-area-keep  Pgood       PGood-neighbors\n\
 PMerge-keep    Poutput-forced Pprecision-not\n\
\n\
 Qallow-short   Qbk:0Bk:0-drop Qcoplanar      QG-half-good   Qi-redundant\n\
 QJoggle        QRotate        Qsearch-all    Qtriangulate   QVertex-good\n\
 Qwarn-allow    Q12-allow-wide Q14-merge-pinched\n\
\n\
 TFacet-log     TInput-file    TOutput-file   Tstatistics    Tverify\n\
 Tz-stdout\n\
\n\
 T4-trace       Tannotate      TAdd-stop      Tcheck-often   TCone-stop\n\
 Tflush         TMerge-trace   TPoint-trace   TVertex-stop   TWide-trace\n\
\n\
 Angle-max      Centrum-size   Random-dist    Ucoplanar-max  Wide-outside\n\
";

/*---------------------------------

  main( argc, argv )
    processes the command line, calls qhull() to do the work, and exits

  design:
    initializes data structures
    reads points
    finishes initialization
    computes convex hull and other structures
    checks the result
    writes the output
    frees memory
*/
int main(int argc, char *argv[]) {
  int curlong, totlong; /* used !qh_NOmem */
  int exitcode, numpoints, dim;
  coordT *points;
  boolT ismalloc;

  QHULL_LIB_CHECK /* Check for compatible library */

  if ((argc == 1) && isatty( 0 /*stdin*/)) {
    fprintf(stdout, qh_prompt2, qh_version);
    exit(qh_ERRnone);
  }
  if (argc > 1 && *argv[1] == '-' && (*(argv[1] + 1) == '?' || *(argv[1] + 1) == '-')) { /* -? or --help */
    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);
  }
  if (argc > 1 && *argv[1] == '-' && *(argv[1]+1)=='V') {
      fprintf(stdout, "%s\n", qh_version2);
      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 NOerrexit= False;
    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);
    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(qh_ALL);
#else
  qh_freeqhull(!qh_ALL);
  qh_memfreeshort(&curlong, &totlong);
  if (curlong || totlong)
    qh_fprintf_stderr(7079, "qhull internal warning (main): did not free %d bytes of long memory(%d pieces)\n",
       totlong, curlong);
#endif
  return exitcode;
} /* main */

qhull-2020.2/src/qhalf/qhalf.pro0000644060175106010010000000033011545632020014657 0ustar  bbarber# -------------------------------------------------
# qhalf.pro -- Qt project file for qconvex.exe
# -------------------------------------------------

include(../qhull-app-c.pri)

TARGET = qhalf

SOURCES += qhalf.c
qhull-2020.2/src/qhalf/qhalf_r.c0000644060175106010010000003052113661631132014633 0ustar  bbarber/*
  ---------------------------------

   qhalf_r.c
     compute the intersection of halfspaces about a point

   see unix_r.c for full interface

   Copyright (c) 1993-2020, The Geometry Center
*/

#include "libqhull_r/libqhull_r.h"

#include 
#include 
#include 
#include 
#include 

#ifdef __cplusplus
extern "C" {
  int isatty(int);
}

#elif defined(_MSC_VER)
#include 
#define isatty _isatty
/* int _isatty(int); */

#else
int isatty(int);  /* returns 1 if stdin is a tty
                   if "Undefined symbol" this can be deleted along with call in main() */
#endif

/*---------------------------------

  qh_prompt
    long prompt for qhull

  notes:
    restricted version of libqhull_r.c
    same text as unix_r.c
    see concise prompt below
    limit maximum literal to 1800 characters
*/

/* duplicated in qhalf.htm */
char hidden_options[]=" d n v Qbb QbB Qf Qg Qm 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 Q10 Q11 Q15 ";

char qh_prompta[]= "\n\
qhalf -- compute the intersection of halfspaces about a point\n\
    http://www.qhull.org  %s\n\
\n\
input (stdin):\n\
    optional interior point: dimension, 1, coordinates\n\
    first lines: dimension+1 and number of halfspaces\n\
    other lines: halfspace coefficients followed by offset\n\
    comments:    start with a non-numeric character\n\
\n\
options:\n\
    Hn,n - specify coordinates of interior point\n\
    Qc   - keep coplanar halfspaces\n\
    Qi   - keep other redundant halfspaces\n\
    QJ   - joggled input instead of merged facets\n\
    Qt   - triangulated output\n\
\n\
Qhull control options:\n\
    Qa   - allow input with fewer or more points than coordinates\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\
    Qs   - search all halfspaces for the initial simplex\n\
\n\
%s%s%s%s";  /* split up qh_prompt for Visual C++ */
char qh_promptb[]= "\
Qhull extra options:\n\
    QGn  - print intersection if visible to halfspace n, -n for not\n\
    QVn  - print intersections for halfspace n, -n if not\n\
    Qw   - allow option warnings\n\
    Q12  - allow wide facets and wide dupridge\n\
    Q14  - merge pinched vertices that create a dupridge\n\
\n\
T options:\n\
    TFn  - report summary when n or more facets created\n\
    TI file - input file, may be enclosed in single quotes\n\
    TO file - output file, may be enclosed in single quotes\n\
    Ts   - statistics\n\
    Tv   - verify result: structure, convexity, and in-circle test\n\
    Tz   - send all output to stdout\n\
\n\
";
char qh_promptc[]= "\
Trace options:\n\
    T4   - trace at level n, 4=all, 5=mem/gauss, -1= events\n\
    Ta   - annotate output with message codes\n\
    TAn  - stop qhull after adding n vertices\n\
     TCn - stop qhull after building cone for point n\n\
     TVn - stop qhull after adding point n, -n for before\n\
    Tc   - check frequently during execution\n\
    Tf   - flush each qh_fprintf for debugging segfaults\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\
\n\
Precision options:\n\
    Cn   - radius of centrum (roundoff added).  Merge facets if non-convex\n\
     An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex\n\
           C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge\n\
    Rn   - randomly perturb computations by a factor of [1-n,1+n]\n\
    Un   - max distance below plane for a new, coplanar halfspace\n\
    Wn   - min facet width for outside halfspace (before roundoff)\n\
\n\
Output formats (may be combined; if none, produces a summary to stdout):\n\
    f    - facet dump\n\
    G    - Geomview output (dual convex hull)\n\
    i    - non-redundant halfspaces incident to each intersection\n\
    m    - Mathematica output (dual convex hull)\n\
    o    - OFF format (dual convex hull: dimension, points, and facets)\n\
    p    - vertex coordinates of dual convex hull (coplanars if 'Qc' or 'Qi')\n\
    s    - summary (stderr)\n\
\n\
";
char qh_promptd[]= "\
More formats:\n\
    Fc   - count plus redundant halfspaces for each intersection\n\
         -   Qc (default) for coplanar and Qi for other redundant\n\
    Fd   - use cdd format for input (homogeneous with offset first)\n\
    FF   - facet dump without ridges\n\
    FI   - ID of each intersection\n\
    Fm   - merge count for each intersection (511 max)\n\
    FM   - Maple output (dual 2-d or 3-d convex hull)\n\
    Fn   - count plus neighboring intersections for each intersection\n\
    FN   - count plus intersections for each 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\
                      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\
    Gc   - centrums\n\
    GDn  - drop dimension n in 3-d and 4-d output\n\
    Gh   - hyperplane intersections\n\
    Gi   - inner planes (i.e., halfspace intersections) only\n\
     Gn  -  no planes\n\
     Go  -  outer planes only\n\
    Gr   - ridges\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\
    PFn  - keep facets whose area is at least n\n\
    Pg   - print good facets (needs 'QGn' or 'QVn')\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\
    -?   - help with examples\n\
    -V   - version\n\
";
/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */

/*---------------------------------

  qh_prompt2
    synopsis for qhull
*/
char qh_prompt2[]= "\n\
qhalf -- halfspace intersection about a point.  Qhull %s\n\
    input (stdin): [dimension, 1, interior point]\n\
                       dimension+1, number of halfspaces, 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 each option\n\
    -?   - this message\n\
    -V   - version\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\
    G    - Geomview output (dual convex hull)\n\
    m    - Mathematica output (dual convex hull)\n\
    o    - OFF file format (dual convex hull)\n\
    QVn  - print intersections for halfspace n, -n if not\n\
    TI file - input file, may be enclosed in single quotes\n\
    TO file - output file, may be enclosed in single quotes\n\
\n\
examples:\n\
    rbox d | qconvex FQ n | qhalf s H0,0,0 Fp\n\
    rbox c | qconvex FQ FV n | qhalf s i\n\
    rbox c | qconvex FQ FV n | qhalf s o\n\
\n\
";
/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */

/*---------------------------------

  qh_prompt3
    concise prompt for qhull
*/
char qh_prompt3[]= "\n\
Qhull %s\n\
Except for 'F.' and 'PG', upper_case options take an argument.\n\
\n\
 facet-dump     Geomview       H0,0-interior incidences      mathematica\n\
 off-format     point-dual     summary\n\
\n\
 Fc-redundant   Fd-cdd-in      FF-dump-xridge FIDs           Fmerges\n\
 FMaple         Fneighbors     FN-intersect   FOptions       Fp-coordinates\n\
 FP-nearest     FQhalf         Fsummary       Fv-halfspace   Fx-non-redundant\n\
\n\
 Gall-points    Gcentrums      GDrop-dim      Ghyperplanes   Ginner\n\
 Gno-planes     Gouter         Gpoints        Gridges        Gvertices\n\
\n\
 PArea-keep     Pdrop-d0:0D0   PFacet-area-keep  Pgood       PGood-neighbors\n\
 PMerge-keep    Poutput-forced Pprecision-not\n\
\n\
 Qallow-short   Qbk:0Bk:0-drop Qcoplanar      QG-half-good   Qi-redundant\n\
 QJoggle        QRotate        Qsearch-all    Qtriangulate   QVertex-good\n\
 Qwarn-allow    Q12-allow-wide Q14-merge-pinched\n\
\n\
 TFacet-log     TInput-file    TOutput-file   Tstatistics    Tverify\n\
 Tz-stdout\n\
\n\
 T4-trace       Tannotate      TAdd-stop      Tcheck-often   TCone-stop\n\
 Tflush         TMerge-trace   TPoint-trace   TVertex-stop   TWide-trace\n\
\n\
 Angle-max      Centrum-size   Random-dist    Ucoplanar-max  Wide-outside\n\
";

/*---------------------------------

  main( argc, argv )
    processes the command line, calls qhull() to do the work, and exits

  design:
    initializes data structures
    reads points
    finishes initialization
    computes convex hull and other structures
    checks the result
    writes the output
    frees memory
*/
int main(int argc, char *argv[]) {
  int curlong, totlong; /* used !qh_NOmem */
  int exitcode, numpoints, dim;
  coordT *points;
  boolT ismalloc;
  qhT qh_qh;
  qhT *qh= &qh_qh;

  QHULL_LIB_CHECK /* Check for compatible library */

  if ((argc == 1) && isatty( 0 /*stdin*/)) {
    fprintf(stdout, qh_prompt2, qh_version);
    exit(qh_ERRnone);
  }
  if (argc > 1 && *argv[1] == '-' && (*(argv[1] + 1) == '?' || *(argv[1] + 1) == '-')) { /* -? or --help */
    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);
  }
  if (argc > 1 && *argv[1] == '-' && *(argv[1]+1)=='V') {
      fprintf(stdout, "%s\n", qh_version2);
      exit(qh_ERRnone);
  }
  qh_init_A(qh, stdin, stdout, stderr, argc, argv);  /* sets qh->qhull_command */
  exitcode= setjmp(qh->errexit); /* simple statement for CRAY J916 */
  if (!exitcode) {
    qh->NOerrexit = False;
    qh_option(qh, "Halfspace", NULL, NULL);
    qh->HALFspace= True;    /* 'H'   */
    qh_checkflags(qh, qh->qhull_command, hidden_options);
    qh_initflags(qh, 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, qh_ERRinput, NULL, NULL);
    }
    points= qh_readpoints(qh, &numpoints, &dim, &ismalloc);
    qh_init_B(qh, points, numpoints, dim, ismalloc);
    qh_qhull(qh);
    qh_check_output(qh);
    qh_produce_output(qh);
    if (qh->VERIFYoutput && !qh->FORCEoutput && !qh->STOPpoint && !qh->STOPcone)
      qh_check_points(qh);
    exitcode= qh_ERRnone;
  }
  qh->NOerrexit= True;  /* no more setjmp */
#ifdef qh_NOmem
  qh_freeqhull(qh, qh_ALL);
#else
  qh_freeqhull(qh, !qh_ALL);
  qh_memfreeshort(qh, &curlong, &totlong);
  if (curlong || totlong)
    qh_fprintf_stderr(7079, "qhull internal warning (main): did not free %d bytes of long memory(%d pieces)\n",
       totlong, curlong);
#endif
  return exitcode;
} /* main */

qhull-2020.2/src/qhull/0000755060175106010010000000000013724321423013103 5ustar  bbarberqhull-2020.2/src/qhull/qhull.pro0000644060175106010010000000035712550611114014752 0ustar  bbarber# -------------------------------------------------
# qhull.pro -- Qt project file for qhull.exe with libqhullstatic_r
# -------------------------------------------------

include(../qhull-app-c_r.pri)

TARGET = qhull

SOURCES += unix_r.c
qhull-2020.2/src/qhull/unix.c0000644060175106010010000004066413661633675014263 0ustar  bbarber/*
  ---------------------------------

   unix.c
     command line interface to qhull
         includes SIOUX interface for Macintoshes

   see qh-qhull.htm

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/qhull/unix.c#4 $$Change: 2954 $
   $DateTime: 2020/05/21 22:30:09 $$Author: bbarber $
*/

#include "libqhull/libqhull.h"

#include 
#include 
#include 
#include 
#include 

#if defined(_MSC_VER)
#include 
#define isatty _isatty
/* int _isatty(int); */

#else
int isatty(int);  /* returns 1 if stdin is a tty
                   if "Undefined symbol" this can be deleted along with call in main() */
#endif

/*---------------------------------

  qh_prompt
    long prompt for qhull

  notes:
    see concise prompt below
    same text as qconvex.c, qdelanay.c, qhalf.c, qvoronoi.c
    limit maximum literal to 1800 characters
*/
char qh_prompta[]= "\n\
qhull -- compute convex hulls and related structures.\n\
    http://www.qhull.org  %s\n\
\n\
input (stdin):\n\
    first lines: dimension and number of points (or vice-versa).\n\
    other lines: point coordinates, best if one point per line\n\
    comments:    start with a non-numeric character\n\
    halfspaces:  use dim plus one and put offset after coefficients.\n\
                 May be preceded 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\
    Hn,n,... - halfspace intersection about point [n,n,0,...]\n\
    Qc   - keep coplanar points with nearest facet\n\
    Qi   - keep interior points with nearest facet\n\
    QJ   - joggled input instead of merged facets\n\
    Qt   - triangulated output\n\
    v    - Voronoi diagram (dual of the Delaunay triangulation)\n\
    v Qu - furthest-site Voronoi diagram\n\
\n\
Qhull control options:\n\
    Qa   - allow input with fewer or more points than coordinates\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\
    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\
    QVn  - good facet if it includes point n, -n if not\n\
    Qx   - exact pre-merges (skips coplanar and angle-coplanar facets)\n\
    Qz   - add point-at-infinity to Delaunay triangulation\n\
\n\
%s%s%s%s";  /* split up qh_prompt for Visual C++ */
char qh_promptb[]= "\
Qhull extra options:\n\
    Qf   - partition point to furthest outside facet\n\
    Qg   - only build good facets (needs 'QGn', 'QVn', or 'PdD')\n\
    QGn  - good facet if visible from point n, -n for not visible\n\
    Qm   - only process points that would increase max_outside\n\
    Qr   - process random outside points instead of furthest ones\n\
    Qv   - test vertex neighbors for convexity\n\
    Qw   - allow option warnings\n\
    Q0   - turn off default premerge with 'C-0'/'Qx'\n\
    Q1   - merge by mergetype/angle instead of mergetype/distance\n\
    Q2   - merge all coplanar facets instead of merging 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\
    Q12  - allow wide facets and wide dupridge\n\
    Q14  - merge pinched vertices that create a dupridge\n\
    Q15  - check for duplicate ridges with the same vertices\n\
\n\
T options:\n\
    TFn  - report summary when n or more facets created\n\
    TI file - input file, may be enclosed in single quotes\n\
    TO file - output file, may be enclosed in single quotes\n\
    Ts   - statistics\n\
    Tv   - verify result: structure, convexity, and point inclusion\n\
    Tz   - send all output to stdout\n\
\n\
";
char qh_promptc[]= "\
Trace options:\n\
    T4   - trace at level n, 4=all, 5=mem/gauss, -1= events\n\
    Ta   - annotate output with message codes\n\
    TAn  - stop qhull after adding n vertices\n\
     TCn - stop qhull after building cone for point n\n\
     TVn - stop qhull after adding point n, -n for before\n\
    Tc   - check frequently during execution\n\
    Tf   - flush each qh_fprintf for debugging segfaults\n\
    TPn  - turn on tracing when point n added to hull\n\
     TP-1  turn on tracing after qh_buildhull and qh_postmerge\n\
     TMn - turn on tracing at merge n\n\
     TWn - trace merge facets when width > n\n\
    TRn  - rerun qhull n times for statistics to adjust 'QJn'\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\
    n    - normals with offsets\n\
    o    - OFF format (dim, points and facets; Voronoi regions)\n\
    p    - vertex coordinates or Voronoi vertices (coplanar points if 'Qc')\n\
    s    - summary (stderr)\n\
\n\
";
char qh_promptd[]= "\
More formats:\n\
    Fa   - area for each facet\n\
    FA   - compute total area and volume for option 's'\n\
    Fc   - count plus coplanar points for each facet\n\
           use 'Qc' (default) for coplanar and 'Qi' for interior\n\
    FC   - centrum or Voronoi center for each facet\n\
    Fd   - use cdd format for input (homogeneous with offset first)\n\
    FD   - use cdd format for numeric output (offset first)\n\
    FF   - facet dump without ridges\n\
    Fi   - inner plane for each facet\n\
           for 'v', separating hyperplanes for bounded Voronoi regions\n\
    FI   - ID of each facet\n\
    Fm   - merge count for each facet (511 max)\n\
    FM   - Maple output (2-d and 3-d)\n\
    Fn   - count plus neighboring facets for each facet\n\
    FN   - count plus neighboring facets for each point\n\
    Fo   - outer plane (or max_outside) for each facet\n\
           for 'v', separating hyperplanes for unbounded Voronoi regions\n\
    FO   - options and precision constants\n\
    Fp   - dim, count, and intersection coordinates (halfspace only)\n\
    FP   - nearest vertex and distance for each coplanar point\n\
    FQ   - command used for qhull\n\
    Fs   - summary: #int (8), dimension, #points, tot vertices, tot facets,\n\
                      output: #vertices, #facets, #coplanars, #nonsimplicial\n\
                    #real (2), max outer plane, min vertex\n\
    FS   - sizes:   #int (0)\n\
                    #real (2) tot area, tot volume\n\
    Ft   - triangulation with centrums for non-simplicial facets (OFF format)\n\
    Fv   - count plus vertices for each facet\n\
           for 'v', Voronoi diagram as Voronoi vertices for pairs of sites\n\
    FV   - average of vertices (a feasible point for 'H')\n\
    Fx   - extreme points (in order for 2-d)\n\
\n\
";
char qh_prompte[]= "\
Geomview output (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\
    Gc   - centrums\n\
    GDn  - drop dimension n in 3-d and 4-d output\n\
    Gh   - hyperplane intersections\n\
    Gi   - inner planes only\n\
     Gn  -  no planes\n\
     Go  -  outer planes only\n\
    Gr   - ridges\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\
    PFn  - keep facets whose area is at least n\n\
    Pg   - print good facets (needs 'QGn' or 'QVn')\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\
    -?   - help with examples\n\
    -V   - version\n\
";
/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */

/*---------------------------------

  qh_prompt2
    synopsis for qhull

  notes:
    limit maximum literal to 1800 characters
*/
char qh_prompt2a[]= "\n\
qhull -- compute convex hulls and related structures.  Qhull %s\n\
    input (stdin): dimension, number of points, point coordinates\n\
    comments start with a non-numeric character\n\
    halfspace: use dim+1 and put offsets after coefficients\n\
\n\
options (qh-quick.htm):\n\
    d    - Delaunay triangulation by lifting points to a paraboloid\n\
    d Qu - furthest-site Delaunay triangulation (upper convex hull)\n\
    v    - Voronoi diagram as the dual of the Delaunay triangulation\n\
    v Qu - furthest-site Voronoi diagram\n\
    H1,1 - Halfspace intersection about [1,1,0,...] via polar duality\n\
    Qt   - triangulated output\n\
    QJ   - joggled input instead of merged facets\n\
    Tv   - verify result: structure, convexity, and point inclusion\n\
    .    - concise list of all options\n\
    -    - one-line description of each option\n\
    -?   - this message\n\
    -V   - version\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\
    FA   - report total area and volume\n\
    Fp   - halfspace intersections\n\
    FS   - total area and volume\n\
    Fx   - extreme points (convex hull vertices)\n\
    G    - Geomview output (2-d, 3-d and 4-d)\n\
    m    - Mathematica output (2-d and 3-d)\n\
    o    - OFF format (if 'v', outputs Voronoi regions)\n\
    QVn  - print facets that include point n, -n if not\n\
    TI file - input file, may be enclosed in single quotes\n\
    TO file - output file, may be enclosed in single quotes\n\
\n\
%s";  /* split literal */
char qh_prompt2b[]= "\
examples:\n\
    rbox D4 | qhull Tv                        rbox 1000 s | qhull Tv s FA\n\
    rbox 10 D2 | qhull d QJ s i TO result     rbox 10 D2 | qhull v Qbb Qt p\n\
    rbox 10 D2 | qhull d Qu QJ m              rbox 10 D2 | qhull v Qu QJ o\n\
    rbox c d D2 | qhull Qc s f Fx | more      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 Qc                 rbox c | qhull n\n\
\n\
";
/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */

/*---------------------------------

  qh_prompt3
    concise prompt for qhull

  notes:
    limit maximum literal to 1800 characters
*/
char qh_prompt3a[]= "\n\
Qhull %s\n\
Except for 'F.' and 'PG', upper-case options take an argument.\n\
\n\
 delaunay       facet-dump     Geomview       H0,0-interior  Halfspace\n\
 incidences     mathematica    normals        off-format     points\n\
 summary        voronoi\n\
\n\
 Farea          FArea-total    Fcoplanars     FCentrums      Fd-cdd-in\n\
 FD-cdd-out     FFacets-xridge Finner         FIDs           Fmerges\n\
 FMaple         Fneighbors     FNeigh-vertex  Fouter         FOptions\n\
 Fpoint-intersect  FPoint-near FQhull         Fsummary       FSize\n\
 Ftriangles     Fvertices      Fvoronoi       FVertex-ave    Fxtremes\n\
\n\
 Gall-points    Gcentrums      GDrop-dim      Ghyperplanes   Ginner\n\
 Gno-planes     Gouter         Gpoints        Gridges        Gtransparent\n\
 Gvertices\n\
\n\
 PArea-keep     Pdrop-d0:0D0   PFacet-area-keep  Pgood       PGood-neighbors\n\
 PMerge-keep    Poutput-forced Pprecision-not\n\
\n\
 Qallow-short   QbBound-0:0.5  QbB-scale-box  Qbb-scale-last Qbk:0Bk:0-drop\n\
 Qcoplanar      Qinterior      QJoggle        QRotate        Qsearch-all\n\
 Qtriangulate   QupperDelaunay Qwarn-allow    Qxact-merge    Qzinfinite\n\
\n\
 Qfurthest      Qgood-only     QGood-point    Qmax-outside   Qrandom\n\
 Qvneighbors    QVertex-good\n\
\n\
%s"; /* split literal */
char qh_prompt3b[]= "\
 Q0-no-premerge Q1-angle-merge     Q2-no-independ  Q3-no-redundant\n\
 Q4-no-old      Q5-no-check-out    Q6-no-concave   Q7-depth-first\n\
 Q8-no-near-in  Q9-pick-furthest   Q10-no-narrow   Q11-trinormals\n\
 Q12-allow-wide Q14-merge-pinched  Q15-duplicates\n\
\n\
 TFacet-log     TInput-file    TOutput-file   Tstatistics    Tverify\n\
 Tz-stdout\n\
\n\
 T4-trace       Tannotate      TAdd-stop      Tcheck-often   TCone-stop\n\
 Tflush         TMerge-trace   TPoint-trace   TRerun         TVertex-stop\n\
 TWide-trace\n\
\n\
 Angle-max      Centrum-size   Error-round    Random-dist    Ucoplanar-max\n\
 Visible-min    Wide-outside\n\
";

/*---------------------------------

  main( argc, argv )
    processes the command line, calls qhull() to do the work, and exits

  design:
    initializes data structures
    reads points
    finishes initialization
    computes convex hull and other structures
    checks the result
    writes the output
    frees memory
*/
int main(int argc, char *argv[]) {
  int curlong, totlong; /* used !qh_NOmem */
  int exitcode, numpoints, dim;
  coordT *points;
  boolT ismalloc;

  QHULL_LIB_CHECK /* Check for compatible library */

  if ((argc == 1) && isatty( 0 /*stdin*/)) {
    fprintf(stdout, qh_prompt2a, qh_version, qh_prompt2b);
    exit(qh_ERRnone);
  }
  if (argc > 1 && *argv[1] == '-' && (*(argv[1] + 1) == '?' || *(argv[1] + 1) == '-')) { /* -? or --help */
    fprintf(stdout, qh_prompt2a, qh_version, qh_prompt2b);
    exit(qh_ERRnone);
  }
  if (argc > 1 && *argv[1] == '-' && (*(argv[1] + 1) == '?' || *(argv[1] + 1) == '-')) { /* -? or --help */
    fprintf(stdout, qh_prompt2a, qh_version, qh_prompt2b);
    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_prompt3a, qh_version, qh_prompt3b);
    exit(qh_ERRnone);
  }
  if (argc > 1 && *argv[1] == '-' && *(argv[1]+1)=='V') {
      fprintf(stdout, "%s\n", qh_version2);
      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 NOerrexit = False;
    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 STOPadd && !qh STOPcone && !qh STOPpoint)
      qh_check_points();
    exitcode= qh_ERRnone;
  }
  qh NOerrexit= True;  /* no more setjmp */
#ifdef qh_NOmem
  qh_freeqhull(qh_ALL);
#else
  qh_freeqhull(!qh_ALL);
  qh_memfreeshort(&curlong, &totlong);
  if (curlong || totlong)
    qh_fprintf_stderr(7079, "qhull internal warning (main): did not free %d bytes of long memory(%d pieces)\n",
       totlong, curlong);
#endif
  return exitcode;
} /* main */

qhull-2020.2/src/qhull/unix_r.c0000644060175106010010000004113513706714004014560 0ustar  bbarber/*
  ---------------------------------

   unix_r.c
     command line interface to qhull
         includes SIOUX interface for Macintoshes

   see qh-qhull.htm

   Copyright (c) 1993-2020 The Geometry Center.
   $Id: //main/2019/qhull/src/qhull/unix_r.c#6 $$Change: 3006 $
   $DateTime: 2020/07/29 18:28:16 $$Author: bbarber $
*/

#include "libqhull_r/libqhull_r.h"

#include 
#include 
#include 
#include 
#include 

#ifdef __cplusplus
extern "C" {
  int isatty(int);
}

#elif defined(_MSC_VER)
#include 
#define isatty _isatty
/* int _isatty(int); */

#else
int isatty(int);  /* returns 1 if stdin is a tty
                   if "Undefined symbol" this can be deleted along with call in main() */
#endif

/*---------------------------------

  qh_prompt
    long prompt for qhull

  notes:
    see concise prompt below
    same text as qconvex_r.c, qdelanay_r.c, qhalf_r.c, qvoronoi_r.c
    limit maximum literal to 1800 characters
*/
char qh_prompta[]= "\n\
qhull -- compute convex hulls and related structures.\n\
    http://www.qhull.org  %s\n\
\n\
input (stdin):\n\
    first lines: dimension and number of points (or vice-versa).\n\
    other lines: point coordinates, best if one point per line\n\
    comments:    start with a non-numeric character\n\
    halfspaces:  use dim plus one and put offset after coefficients.\n\
                 May be preceded 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\
    Hn,n,... - halfspace intersection about point [n,n,0,...]\n\
    Qc   - keep coplanar points with nearest facet\n\
    Qi   - keep interior points with nearest facet\n\
    QJ   - joggled input instead of merged facets\n\
    Qt   - triangulated output\n\
    v    - Voronoi diagram (dual of the Delaunay triangulation)\n\
    v Qu - furthest-site Voronoi diagram\n\
\n\
Qhull control options:\n\
    Qa   - allow input with fewer or more points than coordinates\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\
    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\
    QVn  - good facet if it includes point n, -n if not\n\
    Qx   - exact pre-merges (skips coplanar and angle-coplanar facets)\n\
    Qz   - add point-at-infinity to Delaunay triangulation\n\
\n\
%s%s%s%s";  /* split up qh_prompt for Visual C++ */
char qh_promptb[]= "\
Qhull extra options:\n\
    Qf   - partition point to furthest outside facet\n\
    Qg   - only build good facets (needs 'QGn', 'QVn', or 'PdD')\n\
    QGn  - good facet if visible from point n, -n for not visible\n\
    Qm   - only process points that would increase max_outside\n\
    Qr   - process random outside points instead of furthest ones\n\
    Qv   - test vertex neighbors for convexity\n\
    Qw   - allow option warnings\n\
    Q0   - turn off default premerge with 'C-0'/'Qx'\n\
    Q1   - merge by mergetype/angle instead of mergetype/distance\n\
    Q2   - merge all coplanar facets instead of merging 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\
    Q12  - allow wide facets and wide dupridge\n\
    Q14  - merge pinched vertices that create a dupridge\n\
    Q15  - check for duplicate ridges with the same vertices\n\
\n\
T options:\n\
    TFn  - report summary when n or more facets created\n\
    TI file - input file, may be enclosed in single quotes\n\
    TO file - output file, may be enclosed in single quotes\n\
    Ts   - statistics\n\
    Tv   - verify result: structure, convexity, and point inclusion\n\
    Tz   - send all output to stdout\n\
\n\
";
char qh_promptc[]= "\
Trace options:\n\
    T4   - trace at level n, 4=all, 5=mem/gauss, -1= events\n\
    Ta   - annotate output with message codes\n\
    TAn  - stop qhull after adding n vertices\n\
     TCn - stop qhull after building cone for point n\n\
     TVn - stop qhull after adding point n, -n for before\n\
    Tc   - check frequently during execution\n\
    Tf   - flush each qh_fprintf for debugging segfaults\n\
    TPn  - turn on tracing when point n added to hull\n\
     TP-1  turn on tracing after qh_buildhull and qh_postmerge\n\
     TMn - turn on tracing at merge n\n\
     TWn - trace merge facets when width > n\n\
    TRn  - rerun qhull n times for statistics to adjust 'QJn'\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\
    n    - normals with offsets\n\
    o    - OFF format (dim, points and facets; Voronoi regions)\n\
    p    - vertex coordinates or Voronoi vertices (coplanar points if 'Qc')\n\
    s    - summary (stderr)\n\
\n\
";
char qh_promptd[]= "\
More formats:\n\
    Fa   - area for each facet\n\
    FA   - compute total area and volume for option 's'\n\
    Fc   - count plus coplanar points for each facet\n\
           use 'Qc' (default) for coplanar and 'Qi' for interior\n\
    FC   - centrum or Voronoi center for each facet\n\
    Fd   - use cdd format for input (homogeneous with offset first)\n\
    FD   - use cdd format for numeric output (offset first)\n\
    FF   - facet dump without ridges\n\
    Fi   - inner plane for each facet\n\
           for 'v', separating hyperplanes for bounded Voronoi regions\n\
    FI   - ID of each facet\n\
    Fm   - merge count for each facet (511 max)\n\
    FM   - Maple output (2-d and 3-d)\n\
    Fn   - count plus neighboring facets for each facet\n\
    FN   - count plus neighboring facets for each point\n\
    Fo   - outer plane (or max_outside) for each facet\n\
           for 'v', separating hyperplanes for unbounded Voronoi regions\n\
    FO   - options and precision constants\n\
    Fp   - dim, count, and intersection coordinates (halfspace only)\n\
    FP   - nearest vertex and distance for each coplanar point\n\
    FQ   - command used for qhull\n\
    Fs   - summary: #int (8), dimension, #points, tot vertices, tot facets,\n\
                      output: #vertices, #facets, #coplanars, #nonsimplicial\n\
                    #real (2), max outer plane, min vertex\n\
    FS   - sizes:   #int (0)\n\
                    #real (2) tot area, tot volume\n\
    Ft   - triangulation with centrums for non-simplicial facets (OFF format)\n\
    Fv   - count plus vertices for each facet\n\
           for 'v', Voronoi diagram as Voronoi vertices for pairs of sites\n\
    FV   - average of vertices (a feasible point for 'H')\n\
    Fx   - extreme points (in order for 2-d)\n\
\n\
";
char qh_prompte[]= "\
Geomview output (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\
    Gc   - centrums\n\
    GDn  - drop dimension n in 3-d and 4-d output\n\
    Gh   - hyperplane intersections\n\
    Gi   - inner planes only\n\
     Gn  -  no planes\n\
     Go  -  outer planes only\n\
    Gr   - ridges\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\
    PFn  - keep facets whose area is at least n\n\
    Pg   - print good facets (needs 'QGn' or 'QVn')\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\
    -?   - help with examples\n\
    -V   - version\n\
";
/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */

/*---------------------------------

  qh_prompt2
    synopsis for qhull

  notes:
    limit maximum literal to 1800 characters
*/
char qh_prompt2a[]= "\n\
qhull -- compute convex hulls and related structures.  Qhull %s\n\
    input (stdin): dimension, number of points, point coordinates\n\
    comments start with a non-numeric character\n\
    halfspace: use dim+1 and put offsets after coefficients\n\
\n\
options (qh-quick.htm):\n\
    d    - Delaunay triangulation by lifting points to a paraboloid\n\
    d Qu - furthest-site Delaunay triangulation (upper convex hull)\n\
    v    - Voronoi diagram as the dual of the Delaunay triangulation\n\
    v Qu - furthest-site Voronoi diagram\n\
    H1,1 - Halfspace intersection about [1,1,0,...] via polar duality\n\
    Qt   - triangulated output\n\
    QJ   - joggled input instead of merged facets\n\
    Tv   - verify result: structure, convexity, and point inclusion\n\
    .    - concise list of all options\n\
    -    - one-line description of each option\n\
    -?   - this message\n\
    -V   - version\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\
    FA   - report total area and volume\n\
    Fp   - halfspace intersections\n\
    FS   - total area and volume\n\
    Fx   - extreme points (convex hull vertices)\n\
    G    - Geomview output (2-d, 3-d and 4-d)\n\
    m    - Mathematica output (2-d and 3-d)\n\
    o    - OFF format (if 'v', outputs Voronoi regions)\n\
    QVn  - print facets that include point n, -n if not\n\
    TI file - input file, may be enclosed in single quotes\n\
    TO file - output file, may be enclosed in single quotes\n\
\n\
%s";  /* split literal */
char qh_prompt2b[]= "\
examples:\n\
    rbox D4 | qhull Tv                        rbox 1000 s | qhull Tv s FA\n\
    rbox 10 D2 | qhull d QJ s i TO result     rbox 10 D2 | qhull v Qbb Qt p\n\
    rbox 10 D2 | qhull d Qu QJ m              rbox 10 D2 | qhull v Qu QJ o\n\
    rbox c d D2 | qhull Qc s f Fx | more      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 Qc                 rbox c | qhull n\n\
\n\
";
/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */

/*---------------------------------

  qh_prompt3
    concise prompt for qhull

  notes:
    limit maximum literal to 1800 characters
*/
char qh_prompt3a[]= "\n\
Qhull %s\n\
Except for 'F.' and 'PG', upper-case options take an argument.\n\
\n\
 delaunay       facet-dump     Geomview       H0,0-interior  Halfspace\n\
 incidences     mathematica    normals        off-format     points\n\
 summary        voronoi\n\
\n\
 Farea          FArea-total    Fcoplanars     FCentrums      Fd-cdd-in\n\
 FD-cdd-out     FFacets-xridge Finner         FIDs           Fmerges\n\
 FMaple         Fneighbors     FNeigh-vertex  Fouter         FOptions\n\
 Fpoint-intersect  FPoint-near FQhull         Fsummary       FSize\n\
 Ftriangles     Fvertices      Fvoronoi       FVertex-ave    Fxtremes\n\
\n\
 Gall-points    Gcentrums      GDrop-dim      Ghyperplanes   Ginner\n\
 Gno-planes     Gouter         Gpoints        Gridges        Gtransparent\n\
 Gvertices\n\
\n\
 PArea-keep     Pdrop-d0:0D0   PFacet-area-keep  Pgood       PGood-neighbors\n\
 PMerge-keep    Poutput-forced Pprecision-not\n\
\n\
 Qallow-short   QbBound-0:0.5  QbB-scale-box  Qbb-scale-last Qbk:0Bk:0-drop\n\
 Qcoplanar      Qinterior      QJoggle        QRotate        Qsearch-all\n\
 Qtriangulate   QupperDelaunay Qwarn-allow    Qxact-merge    Qzinfinite\n\
\n\
 Qfurthest      Qgood-only     QGood-point    Qmax-outside   Qrandom\n\
 Qvneighbors    QVertex-good\n\
\n\
%s"; /* split literal */
char qh_prompt3b[]= "\
 Q0-no-premerge Q1-angle-merge     Q2-no-independ  Q3-no-redundant\n\
 Q4-no-old      Q5-no-check-out    Q6-no-concave   Q7-depth-first\n\
 Q8-no-near-in  Q9-pick-furthest   Q10-no-narrow   Q11-trinormals\n\
 Q12-allow-wide Q14-merge-pinched  Q15-duplicates\n\
\n\
 TFacet-log     TInput-file    TOutput-file   Tstatistics    Tverify\n\
 Tz-stdout\n\
\n\
 T4-trace       Tannotate      TAdd-stop      Tcheck-often   TCone-stop\n\
 Tflush         TMerge-trace   TPoint-trace   TRerun         TVertex-stop\n\
 TWide-trace\n\
\n\
 Angle-max      Centrum-size   Error-round    Random-dist    Ucoplanar-max\n\
 Visible-min    Wide-outside\n\
";

/*---------------------------------

  main( argc, argv )
    processes the command line, calls qhull() to do the work, and exits

  design:
    initializes data structures
    reads points
    finishes initialization
    computes convex hull and other structures
    checks the result
    writes the output
    frees memory
*/
int main(int argc, char *argv[]) {
  int curlong, totlong; /* used !qh_NOmem */
  int exitcode, numpoints, dim;
  coordT *points;
  boolT ismalloc;
  qhT qh_qh;
  qhT *qh= &qh_qh;

  QHULL_LIB_CHECK /* Check for compatible library */

  if ((argc == 1) && isatty( 0 /*stdin*/)) {
    fprintf(stdout, qh_prompt2a, qh_version, qh_prompt2b);
    exit(qh_ERRnone);
  }
  if (argc > 1 && *argv[1] == '-' && (*(argv[1] + 1) == '?' || *(argv[1] + 1) == '-')) { /* -? or --help */
    fprintf(stdout, qh_prompt2a, qh_version, qh_prompt2b);
    exit(qh_ERRnone);
  }
  if (argc > 1 && *argv[1] == '-' && (*(argv[1] + 1) == '?' || *(argv[1] + 1) == '-')) { /* -? or --help */
    fprintf(stdout, qh_prompt2a, qh_version, qh_prompt2b);
    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_prompt3a, qh_version, qh_prompt3b);
    exit(qh_ERRnone);
  }
  if (argc > 1 && *argv[1] == '-' && *(argv[1]+1)=='V') {
      fprintf(stdout, "%s\n", qh_version2);
      exit(qh_ERRnone);
  }
  qh_init_A(qh, stdin, stdout, stderr, argc, argv);  /* sets qh->qhull_command */
  exitcode= setjmp(qh->errexit); /* simple statement for CRAY J916 */
  if (!exitcode) {
    qh->NOerrexit= False;
    qh_initflags(qh, qh->qhull_command);
    points= qh_readpoints(qh, &numpoints, &dim, &ismalloc);
    qh_init_B(qh, points, numpoints, dim, ismalloc);
    qh_qhull(qh);
    qh_check_output(qh);
    qh_produce_output(qh);
    if (qh->VERIFYoutput && !qh->FORCEoutput && !qh->STOPadd && !qh->STOPcone && !qh->STOPpoint)
      qh_check_points(qh);
    exitcode= qh_ERRnone;
  }
  qh->NOerrexit= True;  /* no more setjmp */
#ifdef qh_NOmem
  qh_freeqhull(qh, qh_ALL);
#else
  qh_freeqhull(qh, !qh_ALL);
  qh_memfreeshort(qh, &curlong, &totlong);
  if (curlong || totlong)
    qh_fprintf_stderr(7079, "qhull internal warning (main): did not free %d bytes of long memory(%d pieces)\n",
       totlong, curlong);
#endif
  return exitcode;
} /* main */

qhull-2020.2/src/qhull-all.pro0000644060175106010010000000740113430324072014372 0ustar  bbarber# -------------------------------------------------
# qhull-all.pro -- Qt project to build executables and static libraries
#
# To build with Qt on mingw
#   Download Qt SDK, install Perl
#   /c/qt/2010.05/qt> ./configure -static -platform win32-g++ -fast -no-qt3support
#
# To build DevStudio sln and proj files (Qhull ships with cmake derived files)
# qmake is in Qt's bin directory
# mkdir -p build && cd build && qmake -tp vc -r ../src/qhull-all.pro
# Additional Library Directories -- C:\qt\Qt5.2.0\5.2.0\msvc2012_64\lib
# libqhullcpp and libqhullstatic refered to $(QTDIR) but apparently didn't retrieve (should be %QTDIR%?)
# libqhull_r also needs ..\..\lib
# Need to change build/x64/Debug/*.lib to lib/ (or copy libs by hand, each time)
# Additional Build Dependencies
# See README.txt -- Need to add Build Dependencies, disable rtti, rename targets to qhull.dll, qhull6_p.dll and qhull6_pd.dll
# -------------------------------------------------

TEMPLATE = subdirs
CONFIG += ordered

SUBDIRS += libqhull_r      #shared library with reentrant code
SUBDIRS += libqhullstatic  #static library
SUBDIRS += libqhullstatic_r #static library with reentrant code
SUBDIRS += libqhullcpp     #static library for C++ interface with libqhullstatic_r

SUBDIRS += qhull           #qhull program linked to libqhullstatic_r
SUBDIRS += rbox         
SUBDIRS += qconvex         #qhull programs linked to libqhullstatic
SUBDIRS += qdelaunay
SUBDIRS += qhalf
SUBDIRS += qvoronoi

SUBDIRS += user_eg         #user programs linked to libqhull_r
SUBDIRS += user_eg2  
SUBDIRS += user_eg3        #user program with libqhullcpp and libqhullstatic_r

SUBDIRS += qhulltest       #C++ test program with Qt, libqhullcpp, and libqhullstatic_r
SUBDIRS += testqset        #test program for qset.c with mem.c
SUBDIRS += testqset_r      #test program for qset_r.c with mem_r.c
                           #See eg/q_test for qhull tests

OTHER_FILES += Changes.txt
OTHER_FILES += CMakeLists.txt
OTHER_FILES += Make-config.sh
OTHER_FILES += ../Announce.txt
OTHER_FILES += ../CMakeLists.txt
OTHER_FILES += ../COPYING.txt
OTHER_FILES += ../File_id.diz
OTHER_FILES += ../index.htm
OTHER_FILES += ../Makefile
OTHER_FILES += ../README.txt
OTHER_FILES += ../REGISTER.txt
OTHER_FILES += ../eg/make-vcproj.sh
OTHER_FILES += ../eg/q_benchmark
OTHER_FILES += ../eg/q_eg
OTHER_FILES += ../eg/q_egtest
OTHER_FILES += ../eg/q_test
OTHER_FILES += ../eg/qhull-zip.sh
OTHER_FILES += ../eg/qtest.sh
OTHER_FILES += ../html/index.htm
OTHER_FILES += ../html/qconvex.htm
OTHER_FILES += ../html/qdelau_f.htm
OTHER_FILES += ../html/qdelaun.htm
OTHER_FILES += ../html/qhalf.htm
OTHER_FILES += ../html/qh-code.htm
OTHER_FILES += ../html/qh-eg.htm
OTHER_FILES += ../html/qh-faq.htm
OTHER_FILES += ../html/qh-get.htm
OTHER_FILES += ../html/qh-impre.htm
OTHER_FILES += ../html/qh-optc.htm
OTHER_FILES += ../html/qh-optf.htm
OTHER_FILES += ../html/qh-optg.htm
OTHER_FILES += ../html/qh-opto.htm
OTHER_FILES += ../html/qh-optp.htm
OTHER_FILES += ../html/qh-optq.htm
OTHER_FILES += ../html/qh-optt.htm
OTHER_FILES += ../html/qh-quick.htm
OTHER_FILES += ../html/qhull.htm
OTHER_FILES += ../html/qhull.man
OTHER_FILES += ../html/qhull.txt
OTHER_FILES += ../html/qhull-cpp.xml
OTHER_FILES += ../html/qvoron_f.htm
OTHER_FILES += ../html/qvoronoi.htm
OTHER_FILES += ../html/rbox.htm
OTHER_FILES += ../html/rbox.man
OTHER_FILES += ../html/rbox.txt
OTHER_FILES += ../src/libqhull/Makefile
OTHER_FILES += ../src/libqhull_r/Makefile
OTHER_FILES += ../src/libqhull_r/qhull_r-exports.def
OTHER_FILES += ../src/qconvex/qconvex_r.c
OTHER_FILES += ../src/qdelaunay/qdelaun_r.c
OTHER_FILES += ../src/qhalf/qhalf_r.c
OTHER_FILES += ../src/qhull/rbox_r.c
OTHER_FILES += ../src/qvoronoi/qvoronoi_r.c
OTHER_FILES += ../src/qhull/unix.c
OTHER_FILES += ../src/user_eg/user_eg.c
OTHER_FILES += ../src/user_eg2/user_eg2.c
qhull-2020.2/src/qhull-app-c.pri0000644060175106010010000000112712477710165014627 0ustar  bbarber# -------------------------------------------------
# qhull-app-c.pri -- Qt include project for C qhull applications linked to libqhull
# -------------------------------------------------

include(qhull-warn.pri)

DESTDIR = ../../bin
TEMPLATE = app
CONFIG += console warn_on
CONFIG -= qt

LIBS += -L../../lib
build_pass:CONFIG(debug, debug|release){
   LIBS += -lqhullstatic_d
   OBJECTS_DIR = Debug
}else:build_pass:CONFIG(release, debug|release){
   LIBS += -lqhullstatic
   OBJECTS_DIR = Release
}
win32-msvc* : QMAKE_LFLAGS += /INCREMENTAL:NO

INCLUDEPATH += ..
CONFIG += qhull_warn_conversion

qhull-2020.2/src/qhull-app-cpp.pri0000644060175106010010000000145112541657633015171 0ustar  bbarber# -------------------------------------------------
# qhull-app-cpp.pri -- Qt include project for qhull as C++ classes
# -------------------------------------------------

include(qhull-warn.pri)

DESTDIR = ../../bin
TEMPLATE = app
CONFIG += console warn_on
CONFIG -= rtti
LIBS += -L../../lib
build_pass:CONFIG(debug, debug|release){
   LIBS += -lqhullcpp_d
   LIBS += -lqhullstatic_rd  # Must be last, otherwise qh_fprintf,etc. are loaded from here instead of qhullcpp-d.lib
   OBJECTS_DIR = Debug
}else:build_pass:CONFIG(release, debug|release){
   LIBS += -lqhullcpp
   LIBS += -lqhullstatic_r  # Must be last, otherwise qh_fprintf,etc. are loaded from here instead of qhullcpp.lib
   OBJECTS_DIR = Release
}
win32-msvc* : QMAKE_LFLAGS += /INCREMENTAL:NO

INCLUDEPATH += ../../src # "libqhull_r/qhull_a.h"
qhull-2020.2/src/qhull-app-c_r.pri0000644060175106010010000000117512541576316015153 0ustar  bbarber# -------------------------------------------------
# qhull-app-c_r.pri -- Qt include project for C qhull applications linked to qhullstatic_r
#
# It uses reentrant Qhull
# -------------------------------------------------

include(qhull-warn.pri)

DESTDIR = ../../bin
TEMPLATE = app
CONFIG += console warn_on
CONFIG -= qt

LIBS += -L../../lib
build_pass:CONFIG(debug, debug|release){
   LIBS += -lqhullstatic_rd
   OBJECTS_DIR = Debug
}else:build_pass:CONFIG(release, debug|release){
   LIBS += -lqhullstatic_r
   OBJECTS_DIR = Release
}
win32-msvc* : QMAKE_LFLAGS += /INCREMENTAL:NO

INCLUDEPATH += ..
CONFIG += qhull_warn_conversion

qhull-2020.2/src/qhull-app-shared.pri0000644060175106010010000000126112266257314015650 0ustar  bbarber# -------------------------------------------------
# qhull-app-shared.pri -- Deprecated Qt include project for C qhull applications linked with libqhull (shared library)
# -------------------------------------------------

include(qhull-warn.pri)

DESTDIR = ../../bin
TEMPLATE = app
CONFIG += console warn_on
CONFIG -= qt

LIBS += -L../../lib
build_pass:CONFIG(debug, debug|release){
   LIBS += -lqhull_d
   OBJECTS_DIR = Debug
}else:build_pass:CONFIG(release, debug|release){
   LIBS += -lqhull
   OBJECTS_DIR = Release
}
win32-msvc* : QMAKE_LFLAGS += /INCREMENTAL:NO

win32-msvc* : DEFINES += qh_dllimport # libqhull/user.h

INCLUDEPATH += ../libqhull
CONFIG += qhull_warn_conversion


qhull-2020.2/src/qhull-app-shared_r.pri0000644060175106010010000000130212541657657016177 0ustar  bbarber# -------------------------------------------------
# qhull-app-shared_r.pri -- Qt include project for C qhull applications linked with libqhull_r (shared library)
#
# It uses reentrant Qhull
# -------------------------------------------------

include(qhull-warn.pri)

DESTDIR = ../../bin
TEMPLATE = app
CONFIG += console warn_on
CONFIG -= qt

LIBS += -L../../lib
build_pass:CONFIG(debug, debug|release){
   LIBS += -lqhull_rd
   OBJECTS_DIR = Debug
}else:build_pass:CONFIG(release, debug|release){
   LIBS += -lqhull_r
   OBJECTS_DIR = Release
}
win32-msvc* : QMAKE_LFLAGS += /INCREMENTAL:NO

win32-msvc* : DEFINES += qh_dllimport # libqhull_r/user.h

INCLUDEPATH += ..
CONFIG += qhull_warn_conversion


qhull-2020.2/src/qhull-libqhull-src.pri0000644060175106010010000000262512465510163016225 0ustar  bbarber# -------------------------------------------------
# qhull-libqhull-src.pri -- Qt include project for libqhull sources and headers
#   libqhull.pro, libqhullp.pro, and libqhulldll.pro are the same for SOURCES and HEADERS
# -------------------------------------------------

# Order object files by frequency of execution.  Small files at end.
# Current directory is caller

# libqhull/libqhull.pro and ../qhull-libqhull-src.pri have the same SOURCES and HEADERS
SOURCES += ../libqhull/global.c
SOURCES += ../libqhull/stat.c
SOURCES += ../libqhull/geom2.c
SOURCES += ../libqhull/poly2.c
SOURCES += ../libqhull/merge.c
SOURCES += ../libqhull/libqhull.c
SOURCES += ../libqhull/geom.c
SOURCES += ../libqhull/poly.c
SOURCES += ../libqhull/qset.c
SOURCES += ../libqhull/mem.c
SOURCES += ../libqhull/random.c
SOURCES += ../libqhull/usermem.c
SOURCES += ../libqhull/userprintf.c
SOURCES += ../libqhull/io.c
SOURCES += ../libqhull/user.c
SOURCES += ../libqhull/rboxlib.c
SOURCES += ../libqhull/userprintf_rbox.c

# [2014] qmake locates the headers in the shadow build directory not the src directory
HEADERS += ../libqhull/geom.h
HEADERS += ../libqhull/io.h
HEADERS += ../libqhull/libqhull.h
HEADERS += ../libqhull/mem.h
HEADERS += ../libqhull/merge.h
HEADERS += ../libqhull/poly.h
HEADERS += ../libqhull/random.h
HEADERS += ../libqhull/qhull_a.h
HEADERS += ../libqhull/qset.h
HEADERS += ../libqhull/stat.h
HEADERS += ../libqhull/user.h
qhull-2020.2/src/qhull-libqhull-src_r.pri0000644060175106010010000000257112541576157016560 0ustar  bbarber# -------------------------------------------------
# qhull-libqhull-src_r.pri -- Qt include project for libqhull_r sources and headers
#
# It uses reentrant Qhull
# -------------------------------------------------

# Order object files by frequency of execution.  Small files at end.
# Current directory is caller

# libqhull_r/libqhull_r.pro and ../qhull-libqhull-src_r.pri have the same SOURCES and HEADERS
SOURCES += ../libqhull_r/global_r.c
SOURCES += ../libqhull_r/stat_r.c
SOURCES += ../libqhull_r/geom2_r.c
SOURCES += ../libqhull_r/poly2_r.c
SOURCES += ../libqhull_r/merge_r.c
SOURCES += ../libqhull_r/libqhull_r.c
SOURCES += ../libqhull_r/geom_r.c
SOURCES += ../libqhull_r/poly_r.c
SOURCES += ../libqhull_r/qset_r.c
SOURCES += ../libqhull_r/mem_r.c
SOURCES += ../libqhull_r/random_r.c
SOURCES += ../libqhull_r/usermem_r.c
SOURCES += ../libqhull_r/userprintf_r.c
SOURCES += ../libqhull_r/io_r.c
SOURCES += ../libqhull_r/user_r.c
SOURCES += ../libqhull_r/rboxlib_r.c
SOURCES += ../libqhull_r/userprintf_rbox_r.c

HEADERS += ../libqhull_r/geom_r.h
HEADERS += ../libqhull_r/io_r.h
HEADERS += ../libqhull_r/libqhull_r.h
HEADERS += ../libqhull_r/mem_r.h
HEADERS += ../libqhull_r/merge_r.h
HEADERS += ../libqhull_r/poly_r.h
HEADERS += ../libqhull_r/random_r.h
HEADERS += ../libqhull_r/qhull_ra.h
HEADERS += ../libqhull_r/qset_r.h
HEADERS += ../libqhull_r/stat_r.h
HEADERS += ../libqhull_r/user_r.h
qhull-2020.2/src/qhull-warn.pri0000644060175106010010000000624313723763036014602 0ustar  bbarber# -------------------------------------------------
# qhull-warn.pri -- Qt project warnings for warn_on
#   CONFIG += qhull_warn_all        # Qhull compiles with all warnings except for qhull_warn_shadow and qhull_warn_conversion
#   CONFIG += qhull_warn_conversion # Warn in Qt and Qhull about conversion errors
#   CONFIG += qhull_warn_error      # Turn warnings into errors
#   CONFIG += qhull_warn_shadow     # Warn in Qt about shadowing of functions and fields
# -------------------------------------------------

# Define qhull_VERSION in CMakeLists.txt, Makefile, and qhull-warn.pri
# [apr'11] VERSION works erratically for msvc builds
# VERSION= 8.0.2
qhull_SOVERSION= 8.0

# Uncomment to report warnings as errors
#CONFIG += qhull_warn_error

*g++{
    qhull_warn_error{
        QMAKE_CFLAGS_WARN_ON += -Werror
        QMAKE_CXXFLAGS_WARN_ON += -Werror
    }

    QMAKE_CFLAGS_WARN_ON += -Wcast-qual -Wextra -Wshadow -Wwrite-strings

    QMAKE_CXXFLAGS_WARN_ON += -Wcast-qual -Wextra -Wwrite-strings
    QMAKE_CXXFLAGS_WARN_ON += -Wno-sign-conversion

    qhull_warn_shadow{
        QMAKE_CXXFLAGS_WARN_ON += -Wshadow     # Shadowing occurs in Qt, e.g., nested foreach
    }

    qhull_warn_conversion{
        QMAKE_CFLAGS_WARN_ON += -Wno-sign-conversion   # libqhullstatic has many size_t vs. int warnings
        QMAKE_CFLAGS_WARN_ON += -Wconversion           # libqhullstatic has no workaround for bit-field conversions
        QMAKE_CXXFLAGS_WARN_ON += -Wconversion         # Qt has conversion errors for qbitarray and qpalette
    }

    qhull_warn_all{
        QMAKE_CFLAGS_WARN_ON += -Waddress -Warray-bounds -Wchar-subscripts -Wclobbered -Wcomment -Wempty-body
        QMAKE_CFLAGS_WARN_ON += -Wformat -Wignored-qualifiers -Wimplicit-function-declaration -Wimplicit-int
        QMAKE_CFLAGS_WARN_ON += -Wmain -Wmissing-braces -Wmissing-field-initializers -Wmissing-parameter-type
        QMAKE_CFLAGS_WARN_ON += -Wnonnull -Wold-style-declaration -Woverride-init -Wparentheses
        QMAKE_CFLAGS_WARN_ON += -Wpointer-sign -Wreturn-type -Wsequence-point -Wsign-compare
        QMAKE_CFLAGS_WARN_ON += -Wsign-compare -Wstrict-aliasing -Wstrict-overflow=1 -Wswitch
        QMAKE_CFLAGS_WARN_ON += -Wtrigraphs -Wtype-limits -Wuninitialized -Wuninitialized
        QMAKE_CFLAGS_WARN_ON += -Wunknown-pragmas -Wunused-function -Wunused-label -Wunused-parameter
        QMAKE_CFLAGS_WARN_ON += -Wunused-value -Wunused-variable -Wvolatile-register-var

        QMAKE_CXXFLAGS_WARN_ON += -Waddress -Warray-bounds -Wc++0x-compat -Wchar-subscripts
        QMAKE_CXXFLAGS_WARN_ON += -Wclobbered -Wcomment -Wempty-body -Wenum-compare
        QMAKE_CXXFLAGS_WARN_ON += -Wformat -Wignored-qualifiers -Wmain -Wmissing-braces
        QMAKE_CXXFLAGS_WARN_ON += -Wmissing-field-initializers -Wparentheses -Wreorder -Wreturn-type
        QMAKE_CXXFLAGS_WARN_ON += -Wsequence-point -Wsign-compare -Wsign-compare -Wstrict-aliasing
        QMAKE_CXXFLAGS_WARN_ON += -Wstrict-overflow=1 -Wswitch -Wtrigraphs -Wtype-limits
        QMAKE_CXXFLAGS_WARN_ON += -Wuninitialized -Wunknown-pragmas -Wunused-function -Wunused-label
        QMAKE_CXXFLAGS_WARN_ON += -Wunused-parameter -Wunused-value -Wunused-variable -Wvolatile-register-var
    }
}
qhull-2020.2/src/qhulltest/0000755060175106010010000000000013724321431014002 5ustar  bbarberqhull-2020.2/src/qhulltest/Coordinates_test.cpp0000644060175106010010000002361413706662047020040 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2009-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/qhulltest/Coordinates_test.cpp#4 $$Change: 3001 $
** $DateTime: 2020/07/24 20:43:28 $$Author: bbarber $
**
****************************************************************************/

//pre-compiled headers
#include 
#include "qhulltest/RoadTest.h" // QT_VERSION

#include "libqhullcpp/Coordinates.h"
#include "libqhullcpp/QhullError.h"
#include "libqhullcpp/RboxPoints.h"
#include "libqhullcpp/Qhull.h"

using std::cout;
using std::endl;
using std::ostringstream;
using std::ostream;
using std::string;

namespace orgQhull {

class Coordinates_test : public RoadTest
{
    Q_OBJECT

#//!\name Test slots
private slots:
    void t_construct();
    void t_convert();
    void t_element();
    void t_readonly();
    void t_operator();
    void t_const_iterator();
    void t_iterator();
    void t_foreach();
    void t_search();
    void t_readwrite();
    void t_io();
};//Coordinates_test

void
add_Coordinates_test()
{
    new Coordinates_test();  // RoadTest::s_testcases
}

void Coordinates_test::
t_construct()
{
    Coordinates c;
    QCOMPARE(c.size(), 0U);
    QVERIFY(c.isEmpty());
    c << 1.0;
    QCOMPARE(c.count(), 1);
    Coordinates c2(c);
    c2 << 2.0;
    QCOMPARE(c2.count(), 2);
    Coordinates c3;
    c3= c2;
    QCOMPARE(c3.count(), 2);
    QCOMPARE(c3[0]+c3[1], 3.0);
    QVERIFY(c2==c3);
    std::vector vc;
    vc.push_back(3.0);
    vc.push_back(4.0);
    Coordinates c4(vc);
    QCOMPARE(c4[0]+c4[1], 7.0);
    Coordinates c5(c3);
    QVERIFY(c5==c3);
    c5= vc;
    QVERIFY(c5!=c3);
    QVERIFY(c5==c4);
}//t_construct

void Coordinates_test::
t_convert()
{
    Coordinates c;
    c << 1.0 << 3.0;
    QCOMPARE(c.data()[1], 3.0);
    coordT *c2= c.data();
    const coordT *c3= c.data();
    QCOMPARE(c2, c3);
    std::vector vc= c.toStdVector();
    QCOMPARE((size_t)vc.size(), c.size());
    for(int k= (int)vc.size(); k--; ){
        QCOMPARE(vc[k], c[k]);
    }
    QList qc= c.toQList();
    QCOMPARE(qc.count(), c.count());
    for(int k= qc.count(); k--; ){
        QCOMPARE(qc[k], c[k]);
    }
    Coordinates c4;
    c4= std::vector(2, 0.0);
    QCOMPARE(c4.back(), 0.0);
    Coordinates c5(std::vector(2, 0.0));
    QCOMPARE(c4.size(), c5.size());
    QVERIFY(c4==c5);
}//t_convert

void Coordinates_test::
t_element()
{
    Coordinates c;
    c << 1.0 << -2.0;
    c.at(1)= -3;
    QCOMPARE(c.at(1), -3.0);
    QCOMPARE(c.back(), -3.0);
    QCOMPARE(c.front(), 1.0);
    c[1]= -2.0;
    QCOMPARE(c[1],-2.0);
    QCOMPARE(c.first(), 1.0);
    c.first()= 2.0;
    QCOMPARE(c.first(), 2.0);
    QCOMPARE(c.last(), -2.0);
    c.last()= 0.0;
    QCOMPARE(c.first()+c.last(), 2.0);
    coordT *c4= &c.first();
    const coordT *c5= &c.first();
    QCOMPARE(c4, c5);
    coordT *c6= &c.last();
    const coordT *c7= &c.last();
    QCOMPARE(c6, c7);
    Coordinates c2= c.mid(1);
    QCOMPARE(c2.count(), 1);
    c << 3.0;
    Coordinates c3= c.mid(1,1);
    QCOMPARE(c2, c3);
    QCOMPARE(c3.value(-1, -1.0), -1.0);
    QCOMPARE(c3.value(3, 4.0), 4.0);
    QCOMPARE(c.value(2, 4.0), 3.0);
}//t_element

void Coordinates_test::
t_readonly()
{
    Coordinates c;
    QCOMPARE(c.size(), 0u);
    QCOMPARE(c.count(), 0);
    QVERIFY(c.isEmpty());
    c << 1.0 << -2.0;
    QCOMPARE(c.size(), 2u);
    QCOMPARE(c.count(), 2);
    QVERIFY(!c.isEmpty());
}//t_readonly

void Coordinates_test::
t_operator()
{
    Coordinates c;
    Coordinates c2(c);
    QVERIFY(c==c2);
    QVERIFY(!(c!=c2));
    c << 1.0;
    QVERIFY(!(c==c2));
    QVERIFY(c!=c2);
    c2 << 1.0;
    QVERIFY(c==c2);
    QVERIFY(!(c!=c2));
    c[0]= 0.0;
    QVERIFY(c!=c2);
    Coordinates c3= c+c2;
    QCOMPARE(c3.count(), 2);
    QCOMPARE(c3[0], 0.0);
    QCOMPARE(c3[1], 1.0);
    c3 += c3;
    QCOMPARE(c3.count(), 4);
    QCOMPARE(c3[2], 0.0);
    QCOMPARE(c3[3], 1.0);
    c3 += c2;
    QCOMPARE(c3[4], 1.0);
    c3 += 5.0;
    QCOMPARE(c3.count(), 6);
    QCOMPARE(c3[5], 5.0);
    // << checked above
}//t_operator

void Coordinates_test::
t_const_iterator()
{
    Coordinates c;
    QCOMPARE(c.begin(), c.end());
    // begin and end checked elsewhere
    c << 1.0 << 3.0;
    Coordinates::const_iterator i= c.begin();
    QCOMPARE(*i, 1.0);
    QCOMPARE(i[1], 3.0);
    // i[1]= -3.0; // compiler error
    // operator-> is not applicable to double
    QCOMPARE(*i++, 1.0);
    QCOMPARE(*i, 3.0);
    QCOMPARE(*i--, 3.0);
    QCOMPARE(*i, 1.0);
    QCOMPARE(*(i+1), 3.0);
    QCOMPARE(*++i, 3.0);
    QCOMPARE(*(i-1), 1.0);
    QCOMPARE(*--i, 1.0);
    QVERIFY(i==c.begin());
    QVERIFY(i==c.constBegin());
    QVERIFY(i!=c.end());
    QVERIFY(i!=c.constEnd());
    QVERIFY(i=c.begin());
    QVERIFY(i+1<=c.end());
    QVERIFY(i+1>c.begin());
    Coordinates::iterator i2= c.begin();
    Coordinates::const_iterator i3(i2);
    QCOMPARE(*i3, 1.0);
    QCOMPARE(i3[1], 3.0);
}//t_const_iterator

void Coordinates_test::
t_iterator()
{
    Coordinates c;
    QCOMPARE(c.begin(), c.end());
    // begin and end checked elsewhere
    c << 1.0 << 3.0;
    Coordinates::iterator i= c.begin();
    QCOMPARE(*i, 1.0);
    QCOMPARE(i[1], 3.0);
    *i= -1.0;
    QCOMPARE(*i, -1.0);
    i[1]= -3.0;
    QCOMPARE(i[1], -3.0);
    *i= 1.0;
    // operator-> is not applicable to double
    QCOMPARE(*i++, 1.0);
    QCOMPARE(*i, -3.0);
    *i= 3.0;
    QCOMPARE(*i--, 3.0);
    QCOMPARE(*i, 1.0);
    QCOMPARE(*(i+1), 3.0);
    QCOMPARE(*++i, 3.0);
    QCOMPARE(*(i-1), 1.0);
    QCOMPARE(*--i, 1.0);
    QVERIFY(i==c.begin());
    QVERIFY(i==c.constBegin());
    QVERIFY(i!=c.end());
    QVERIFY(i!=c.constEnd());
    QVERIFY(i=c.begin());
    QVERIFY(i+1<=c.end());
    QVERIFY(i+1>c.begin());
}//t_iterator

void Coordinates_test::
t_foreach()
{
    RboxPoints rcube("c");
    Qhull q;
    Coordinates cs;
    cs << 0.1 << 0.2 << 0.3;
    q.setFeasiblePoint(cs);
    q.runQhull(rcube, "QR0"); // a rotated cube, feasiblePoint is set but not used
    coordT c2= cs.at(1);

    // Qt's 'foreach' should not be used.  It makes a copy of the std::vector

    bool isC2= false;
    int count= 0;
    for(coordT c : q.feasiblePoint()){
        ++count;
        if(c==c2){
            isC2= true;
        }
    }
    QVERIFY(isC2);
    QCOMPARE(count, cs.count());
}//t_foreach

void Coordinates_test::
t_search()
{
    Coordinates c;
    c << 1.0 << 3.0 << 1.0;
    QVERIFY(c.contains(1.0));
    QVERIFY(c.contains(3.0));
    QVERIFY(!c.contains(0.0));
    QCOMPARE(c.count(1.0), 2);
    QCOMPARE(c.count(3.0), 1);
    QCOMPARE(c.count(0.0), 0);
    QCOMPARE(c.indexOf(1.0), 0);
    QCOMPARE(c.indexOf(3.0), 1);
    QCOMPARE(c.indexOf(1.0, -1), 2);
    QCOMPARE(c.indexOf(3.0, -1), -1);
    QCOMPARE(c.indexOf(3.0, -2), 1);
    QCOMPARE(c.indexOf(1.0, -3), 0);
    QCOMPARE(c.indexOf(1.0, -4), 0);
    QCOMPARE(c.indexOf(1.0, 1), 2);
    QCOMPARE(c.indexOf(3.0, 2), -1);
    QCOMPARE(c.indexOf(1.0, 2), 2);
    QCOMPARE(c.indexOf(1.0, 3), -1);
    QCOMPARE(c.indexOf(1.0, 4), -1);
    QCOMPARE(c.lastIndexOf(1.0), 2);
    QCOMPARE(c.lastIndexOf(3.0), 1);
    QCOMPARE(c.lastIndexOf(1.0, -1), 2);
    QCOMPARE(c.lastIndexOf(3.0, -1), 1);
    QCOMPARE(c.lastIndexOf(3.0, -2), 1);
    QCOMPARE(c.lastIndexOf(1.0, -3), 0);
    QCOMPARE(c.lastIndexOf(1.0, -4), -1);
    QCOMPARE(c.lastIndexOf(1.0, 1), 0);
    QCOMPARE(c.lastIndexOf(3.0, 2), 1);
    QCOMPARE(c.lastIndexOf(1.0, 2), 2);
    QCOMPARE(c.lastIndexOf(1.0, 3), 2);
    QCOMPARE(c.lastIndexOf(1.0, 4), 2);
    c.removeAll(3.0);
    QCOMPARE(c.count(), 2);
    c.removeAll(4.0);
    QCOMPARE(c.count(), 2);
    c.removeAll(1.0);
    QCOMPARE(c.count(), 0);
    c.removeAll(4.0);
    QCOMPARE(c.count(), 0);
}//t_search

void Coordinates_test::
t_readwrite()
{
    Coordinates c;
    c.clear();
    QCOMPARE(c.count(), 0);
    c << 1.0 << 3.0;
    c.clear();
    QCOMPARE(c.count(), 0);
    coordT c2[4]= { 0.0, 1.0, 2.0, 3.0};
    c.append(4, c2);
    QCOMPARE(c.count(), 4);
    QCOMPARE(c[0], 0.0);
    QCOMPARE(c[1], 1.0);
    QCOMPARE(c[3], 3.0);
    c.clear();
    c << 1.0 << 3.0;
    c.erase(c.begin(), c.end());
    QCOMPARE(c.count(), 0);
    c << 1.0 << 0.0;
    Coordinates::iterator i= c.erase(c.begin());
    QCOMPARE(*i, 0.0);
    i= c.insert(c.end(), 1.0);
    QCOMPARE(*i, 1.0);
    QCOMPARE(c.count(), 2);
    c.pop_back();
    QCOMPARE(c.count(), 1);   // 0
    QCOMPARE(c[0], 0.0);
    c.push_back(2.0);
    QCOMPARE(c.count(), 2);
    c.append(3.0);
    QCOMPARE(c.count(), 3);   // 0, 2, 3
    QCOMPARE(c[2], 3.0);
    c.insert(0, 4.0);
    QCOMPARE(c[0], 4.0);
    QCOMPARE(c[3], 3.0);
    c.insert(c.count(), 5.0);
    QCOMPARE(c.count(), 5);   // 4, 0, 2, 3, 5
    QCOMPARE(c[4], 5.0);
    c.move(4, 0);
    QCOMPARE(c.count(), 5);   // 5, 4, 0, 2, 3
    QCOMPARE(c[0], 5.0);
    c.pop_front();
    QCOMPARE(c.count(), 4);
    QCOMPARE(c[0], 4.0);
    c.prepend(6.0);
    QCOMPARE(c.count(), 5);   // 6, 4, 0, 2, 3
    QCOMPARE(c[0], 6.0);
    c.push_front(7.0);
    QCOMPARE(c.count(), 6);
    QCOMPARE(c[0], 7.0);
    c.removeAt(1);
    QCOMPARE(c.count(), 5);   // 7, 4, 0, 2, 3
    QCOMPARE(c[1], 4.0);
    c.removeFirst();
    QCOMPARE(c.count(), 4);   // 4, 0, 2, 3
    QCOMPARE(c[0], 4.0);
    c.removeLast();
    QCOMPARE(c.count(), 3);
    QCOMPARE(c.last(), 2.0);
    c.replace(2, 8.0);
    QCOMPARE(c.count(), 3);   // 4, 0, 8
    QCOMPARE(c[2], 8.0);
    c.swap(0, 2);
    QCOMPARE(c[2], 4.0);
    double d= c.takeAt(2);
    QCOMPARE(c.count(), 2);   // 8, 0
    QCOMPARE(d, 4.0);
    double d2= c.takeFirst();
    QCOMPARE(c.count(), 1);   // 0
    QCOMPARE(d2, 8.0);
    double d3= c.takeLast();
    QVERIFY(c.isEmpty()); \
    QCOMPARE(d3, 0.0);
}//t_readwrite

void Coordinates_test::
t_io()
{
    Coordinates c;
    c << 1.0 << 2.0 << 3.0;
    ostringstream os;
    os << "Coordinates 1-2-3\n" << c;
    cout << os.str();
    QString s= QString::fromStdString(os.str());
    QCOMPARE(s.count("2"), 2);
}//t_io

}//orgQhull

#include "moc/Coordinates_test.moc"
qhull-2020.2/src/qhulltest/PointCoordinates_test.cpp0000644060175106010010000003005513706714004021036 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2009-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/qhulltest/PointCoordinates_test.cpp#5 $$Change: 3006 $
** $DateTime: 2020/07/29 18:28:16 $$Author: bbarber $
**
****************************************************************************/

//pre-compiled headers
#include 
#include "qhulltest/RoadTest.h" // QT_VERSION

#include "libqhullcpp/PointCoordinates.h"
#include "libqhullcpp/QhullError.h"
#include "libqhullcpp/RboxPoints.h"
#include "libqhullcpp/Qhull.h"

using std::cout;
using std::endl;
using std::ostringstream;
using std::ostream;
using std::string;
using std::stringstream;

namespace orgQhull {

class PointCoordinates_test : public RoadTest
{
    Q_OBJECT

#//!\name Test slots
private slots:
    void t_construct_q();
    void t_construct_qh();
    void t_convert();
    void t_getset();
    void t_element();
    void t_foreach();
    void t_search();
    void t_modify();
    void t_append_points();
    void t_io();
};//PointCoordinates_test

void
add_PointCoordinates_test()
{
    new PointCoordinates_test();  // RoadTest::s_testcases
}

void PointCoordinates_test::
t_construct_q()
{
    Qhull q;
    PointCoordinates pc(q);
    QCOMPARE(pc.size(), 0U);
    QCOMPARE(pc.coordinateCount(), 0);
    QCOMPARE(pc.dimension(), 0);
    QCOMPARE(pc.coordinates(), (coordT *)0);
    QVERIFY(pc.isEmpty());
    pc.checkValid();
    PointCoordinates pc7(q, 2, "test explicit dimension");
    QCOMPARE(pc7.dimension(), 2);
    QCOMPARE(pc7.count(), 0);
    QVERIFY(pc7.isEmpty());
    QCOMPARE(pc7.comment(), std::string("test explicit dimension"));
    pc7.checkValid();
    PointCoordinates pc2(q, "Test pc2");
    QCOMPARE(pc2.count(), 0);
    QVERIFY(pc2.isEmpty());
    QCOMPARE(pc2.comment(), std::string("Test pc2"));
    pc2.checkValid();
    PointCoordinates pc3(q, 3, "Test 3-d pc3");
    QCOMPARE(pc3.dimension(), 3);
    QVERIFY(pc3.isEmpty());
    pc3.checkValid();
    coordT c[]= { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0 };
    PointCoordinates pc4(q, 2, "Test 2-d pc4", 6, c);
    QCOMPARE(pc4.dimension(), 2);
    QCOMPARE(pc4.count(), 3);
    QCOMPARE(pc4.size(), 3u);
    QVERIFY(!pc4.isEmpty());
    pc4.checkValid();
    QhullPoint p= pc4[2];
    QCOMPARE(p[1], 5.0);
    // QhullPoint refers to PointCoordinates
    p[1] += 1.0;
    QCOMPARE(pc4[2][1], 6.0);
    PointCoordinates pc5(q, 4, "Test 4-d pc5 with insufficient coordinates", 6, c);
    QCOMPARE(pc5.dimension(), 4);
    QCOMPARE(pc5.count(), 1);
    QCOMPARE(pc5.extraCoordinatesCount(), 2);
    QCOMPARE(pc5.extraCoordinates()[1], 5.0);
    QVERIFY(!pc5.isEmpty());;
    std::vector vc;
    vc.push_back(3.0);
    vc.push_back(4.0);
    vc.push_back(5.0);
    vc.push_back(6.0);
    vc.push_back(7.0);
    vc.push_back(9.0);
    pc5.append(2, &vc[3]); // Copy of vc[]
    pc5.checkValid();
    QhullPoint p5(q, 4, &vc[1]);
    QCOMPARE(pc5[1], p5);
    PointCoordinates pc6(pc5); // Makes copy of point_coordinates
    QCOMPARE(pc6[1], p5);
    QVERIFY(pc6==pc5);
    QhullPoint p6= pc5[1];  // Refers to pc5.coordinates
    pc5[1][0] += 1.0;
    QCOMPARE(pc5[1], p6);
    QVERIFY(pc5[1]!=p5);
    QVERIFY(pc6!=pc5);
    pc6= pc5;
    QVERIFY(pc6==pc5);
    PointCoordinates pc8(q);
    pc6= pc8;
    QVERIFY(pc6!=pc5);
    QVERIFY(pc6.isEmpty());
}//t_construct_q

void PointCoordinates_test::
t_construct_qh()
{
    QhullQh qh;
    PointCoordinates pc(&qh);
    QCOMPARE(pc.size(), 0U);
    QCOMPARE(pc.coordinateCount(), 0);
    QCOMPARE(pc.dimension(), 0);
    QCOMPARE(pc.coordinates(), (coordT *)0);
    QVERIFY(pc.isEmpty());
    pc.checkValid();
    PointCoordinates pc7(&qh, 2, "test explicit dimension");
    QCOMPARE(pc7.dimension(), 2);
    QCOMPARE(pc7.count(), 0);
    QVERIFY(pc7.isEmpty());
    QCOMPARE(pc7.comment(), std::string("test explicit dimension"));
    pc7.checkValid();
    PointCoordinates pc2(&qh, "Test pc2");
    QCOMPARE(pc2.count(), 0);
    QVERIFY(pc2.isEmpty());
    QCOMPARE(pc2.comment(), std::string("Test pc2"));
    pc2.checkValid();
    PointCoordinates pc3(&qh, 3, "Test 3-d pc3");
    QCOMPARE(pc3.dimension(), 3);
    QVERIFY(pc3.isEmpty());
    pc3.checkValid();
    coordT c[]= { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0 };
    PointCoordinates pc4(&qh, 2, "Test 2-d pc4", 6, c);
    QCOMPARE(pc4.dimension(), 2);
    QCOMPARE(pc4.count(), 3);
    QCOMPARE(pc4.size(), 3u);
    QVERIFY(!pc4.isEmpty());
    pc4.checkValid();
    QhullPoint p= pc4[2];
    QCOMPARE(p[1], 5.0);
    // QhullPoint refers to PointCoordinates
    p[1] += 1.0;
    QCOMPARE(pc4[2][1], 6.0);
    PointCoordinates pc5(&qh, 4, "Test 4-d pc5 with insufficient coordinates", 6, c);
    QCOMPARE(pc5.dimension(), 4);
    QCOMPARE(pc5.count(), 1);
    QCOMPARE(pc5.extraCoordinatesCount(), 2);
    QCOMPARE(pc5.extraCoordinates()[1], 5.0);
    QVERIFY(!pc5.isEmpty());;
    std::vector vc;
    vc.push_back(3.0);
    vc.push_back(4.0);
    vc.push_back(5.0);
    vc.push_back(6.0);
    vc.push_back(7.0);
    vc.push_back(9.0);
    pc5.append(2, &vc[3]); // Copy of vc[]
    pc5.checkValid();
    QhullPoint p5(&qh, 4, &vc[1]);
    QCOMPARE(pc5[1], p5);
    PointCoordinates pc6(pc5); // Makes copy of point_coordinates
    QCOMPARE(pc6[1], p5);
    QVERIFY(pc6==pc5);
    QhullPoint p6= pc5[1];  // Refers to pc5.coordinates
    pc5[1][0] += 1.0;
    QCOMPARE(pc5[1], p6);
    QVERIFY(pc5[1]!=p5);
    QVERIFY(pc6!=pc5);
    pc6= pc5;
    QVERIFY(pc6==pc5);
    PointCoordinates pc8(&qh);
    pc6= pc8;
    QVERIFY(pc6!=pc5);
    QVERIFY(pc6.isEmpty());
}//t_construct_qh

void PointCoordinates_test::
t_convert()
{
    Qhull q;
    //defineAs tested above
    coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
    PointCoordinates ps(q, 3, "two 3-d points", 6, c);
    QCOMPARE(ps.dimension(), 3);
    QCOMPARE(ps.size(), 2u);
    const coordT *c2= ps.constData();
    QVERIFY(c!=c2);
    QCOMPARE(c[0], c2[0]);
    const coordT *c3= ps.data();
    QCOMPARE(c3, c2);
    coordT *c4= ps.data();
    QCOMPARE(c4, c2);
    std::vector vs= ps.toStdVector();
    QCOMPARE(vs.size(), 6u);
    QCOMPARE(vs[5], 5.0);
    QList qs= ps.toQList();
    QCOMPARE(qs.size(), 6);
    QCOMPARE(qs[5], 5.0);
}//t_convert

void PointCoordinates_test::
t_getset()
{
    // See t_construct() for test of coordinates, coordinateCount, dimension, empty, isEmpty, ==, !=
    // See t_construct() for test of checkValid, comment, setDimension
    Qhull q;
    PointCoordinates pc(q, "Coordinates c");
    pc.setComment("New comment");
    QCOMPARE(pc.comment(), std::string("New comment"));
    pc.checkValid();
    pc.makeValid();  // A no-op
    pc.checkValid();
    Coordinates cs= pc.getCoordinates();
    QVERIFY(cs.isEmpty());
    PointCoordinates pc2(pc);
    pc.setDimension(3);
    QVERIFY(pc2!=pc);
    coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
    pc.append(6, c);
    pc.checkValid();
    pc.makeValid();  // A no-op
    QhullPoint p= pc[0];
    QCOMPARE(p[2], 2.0);
    try{
        pc.setDimension(2);
        QFAIL("setDimension(2) did not fail for 3-d.");
    }catch (const std::exception &e) {
        const char *s= e.what();
        cout << "INFO   : Caught " << s;
    }
}//t_getset

void PointCoordinates_test::
t_element()
{
    Qhull q;
    coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
    PointCoordinates pc(q, 2, "2-d points", 6, c);
    QhullPoint p= pc.at(0);
    QCOMPARE(p, pc[0]);
    QCOMPARE(p, pc.first());
    QCOMPARE(p, pc.value(0));
    p= pc.back();
    QCOMPARE(p, pc[2]);
    QCOMPARE(p, pc.last());
    QCOMPARE(p, pc.value(2));
    QhullPoints ps= pc.mid(1, 2);
    QCOMPARE(ps[1], p);
}//t_element

void PointCoordinates_test::
t_foreach()
{
    Qhull q;
    coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
    PointCoordinates pc(q, 2, "2-d points", 6, c);
    QhullPoints::Iterator i= pc.begin();
    QhullPoint p= pc[0];
    QCOMPARE(*i, p);
    QCOMPARE((*i)[0], 0.0);
    QhullPoint p3= pc[2];
    i= pc.end();
    QCOMPARE(i[-1], p3);
    const PointCoordinates pc2(q, 2, "2-d points", 6, c);
    QhullPoints::ConstIterator i2= pc.begin();
    const QhullPoint p0= pc2[0];
    QCOMPARE(*i2, p0);
    QCOMPARE((*i2)[0], 0.0);
    QhullPoints::ConstIterator i3= i2;
    QCOMPARE(i3, i2);
    QCOMPARE((*i3)[0], 0.0);
    i3= pc.constEnd();
    --i3;
    QhullPoint p2= pc2[2];
    QCOMPARE(*i3, p2);
    i= pc.end();
    QVERIFY(i-1==i3);
    i2= pc2.end();
    QVERIFY(i2-1!=i3);
    QCOMPARE(*(i2-1), *i3);
    Coordinates::ConstIterator i4= pc.beginCoordinates();
    QCOMPARE(*i4, 0.0);
    Coordinates::Iterator i5= pc.beginCoordinates();
    QCOMPARE(*i5, 0.0);
    i4= pc.beginCoordinates(1);
    QCOMPARE(*i4, 2.0);
    i5= pc.beginCoordinates(1);
    QCOMPARE(*i5, 2.0);
    i4= pc.endCoordinates();
    QCOMPARE(*--i4, 5.0);
    i5= pc.endCoordinates();
    QCOMPARE(*--i5, 5.0);

    // Qt's 'foreach' makes a copy of std::point_coordinates.  It should not be used.
    bool isP3= false;
    int count= false;
    isP3= false;
    count= false;
    for(QhullPoint pt : pc){
        ++count;
        QVERIFY(pt[0] >= 0.0);
        QVERIFY(pt[0] <= 5.0);
        if(pt==p3){
            isP3= true;
            QCOMPARE(count, 3);
        }
    }
    QVERIFY(isP3);
    QCOMPARE(count, pc.count());
}//t_foreach

void PointCoordinates_test::
t_search()
{
    Qhull q;
    coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
    PointCoordinates pc(q, 2, "2-d points", 6, c);
    QhullPoint p0= pc[0];
    QhullPoint p2= pc[2];
    QVERIFY(pc.contains(p0));
    QVERIFY(pc.contains(p2));
    QCOMPARE(pc.count(p0), 1);
    QCOMPARE(pc.indexOf(p2), 2);
    QCOMPARE(pc.lastIndexOf(p0), 0);
}//t_search

void PointCoordinates_test::
t_modify()
{
    Qhull q;
    coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
    PointCoordinates pc(q, 2, "2-d points", 6, c);
    coordT c3[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
    PointCoordinates pc5(q, 2, "test explicit dimension");
    pc5.append(6, c3); // 0-5
    QVERIFY(pc5==pc);
    PointCoordinates pc2(q, 2, "2-d");
    coordT c2[]= {6.0, 7.0, 8.0, 9.0, 10.0, 11.0};
    pc2.append(6, c2);
    QCOMPARE(pc2.count(), 3);
    pc2.append(14.0);
    QCOMPARE(pc2.count(), 3);
    QCOMPARE(pc2.extraCoordinatesCount(), 1);
    pc2.append(15.0); // 6-11, 14,15
    QCOMPARE(pc2.count(), 4);
    QCOMPARE(pc2.extraCoordinatesCount(), 0);
    QhullPoint p(pc[0]);
    pc2.append(p); // 6-11, 14,15, 0,1
    QCOMPARE(pc2.count(), 5);
    QCOMPARE(pc2.extraCoordinatesCount(), 0);
    QCOMPARE(pc2.lastIndexOf(p), 4);
    pc.append(pc2); // Invalidates p
    QCOMPARE(pc.count(), 8); // 0-11, 14,15, 0,1
    QCOMPARE(pc.extraCoordinatesCount(), 0);
    QCOMPARE(pc.lastIndexOf(pc[0]), 7);
    pc.appendComment(" operators");
    QCOMPARE(pc.comment(), std::string("2-d points operators"));
    pc.checkValid();
    // see t_append_points for appendPoints
    PointCoordinates pc3= pc+pc2;
    pc3.checkValid();
    QCOMPARE(pc3.count(), 13);
    QCOMPARE(pc3[6][0], 14.0);
    QCOMPARE(pc3[8][0], 6.0);
    pc3 += pc;
    QCOMPARE(pc3.count(), 21);
    QCOMPARE(pc3[14][0], 2.0);
    pc3 += 12.0;
    pc3 += 14.0;
    QCOMPARE(pc3.count(), 22);
    QCOMPARE(pc3.last()[0], 12.0);
    // QhullPoint p3= pc3.first(); // += throws error because append may move the data
    QhullPoint p3= pc2.first();
    pc3 += p3;
    QCOMPARE(pc3.count(), 23);
    QCOMPARE(pc3.last()[0], 6.0);
    pc3 << pc;
    QCOMPARE(pc3.count(), 31);
    QCOMPARE(pc3.last()[0], 0.0);
    pc3 << 12.0 << 14.0;
    QCOMPARE(pc3.count(), 32);
    QCOMPARE(pc3.last()[0], 12.0);
    PointCoordinates pc4(pc3);
    pc4.reserveCoordinates(100);
    QVERIFY(pc3==pc4);
}//t_modify

void PointCoordinates_test::
t_append_points()
{
    Qhull q;
    PointCoordinates pc(q, 2, "stringstream");
    stringstream s("2 3 1 2 3 4 5 6");
    pc.appendPoints(s);
    QCOMPARE(pc.count(), 3);
}//t_append_points

void PointCoordinates_test::
t_io()
{
    Qhull q;
    PointCoordinates c(q);
    ostringstream os;
    os << "PointCoordinates 0-d\n" << c;
    c.setDimension(2);
    c << 1.0 << 2.0 << 3.0 << 1.0 << 2.0 << 3.0;
    os << "PointCoordinates 1,2 3,1 2,3\n" << c;
    cout << os.str();
    QString s= QString::fromStdString(os.str());
    QCOMPARE(s.count("0"), 3);
    QCOMPARE(s.count("2"), 5);
}//t_io

}//orgQhull

#include "moc/PointCoordinates_test.moc"
qhull-2020.2/src/qhulltest/QhullFacetList_test.cpp0000644060175106010010000001535213710652070020440 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/qhulltest/QhullFacetList_test.cpp#4 $$Change: 3009 $
** $DateTime: 2020/07/30 19:25:22 $$Author: bbarber $
**
****************************************************************************/

//pre-compiled headers
#include 
#include "qhulltest/RoadTest.h" // QT_VERSION

#include "libqhullcpp/QhullFacetList.h"
#include "libqhullcpp/QhullError.h"
#include "libqhullcpp/QhullFacet.h"
#include "libqhullcpp/QhullVertex.h"
#include "libqhullcpp/QhullVertexSet.h"
#include "libqhullcpp/Qhull.h"
#include "libqhullcpp/RboxPoints.h"

using std::cout;
using std::endl;
using std::ostringstream;
using std::ostream;
using std::string;

namespace orgQhull {

class QhullFacetList_test : public RoadTest
{
    Q_OBJECT

#//!\name Test slots
private slots:
    void cleanup();
    void t_construct_qh();
    void t_construct_q();
    void t_convert();
    void t_readonly();
    void t_foreach();
    void t_java_iterator();
    void t_io();
};//QhullFacetList_test

void
add_QhullFacetList_test()
{
    new QhullFacetList_test();  // RoadTest::s_testcases
}

//Executed after each testcase
void QhullFacetList_test::
cleanup()
{
    RoadTest::cleanup();
}

void QhullFacetList_test::
t_construct_qh()
{
    RboxPoints rcube("c");
    Qhull q(rcube,"QR0");  // rotated unit cube
    QhullFacetList fs2= q.facetList();
    QVERIFY(!fs2.isEmpty());
    QCOMPARE(fs2.count(),6);
    QhullFacetList fs3(q.endFacet(), q.endFacet());
    QVERIFY(fs3.isEmpty());
    QhullFacetList fs4(q.endFacet().previous(), q.endFacet());
    QCOMPARE(fs4.count(), 1);
    QhullFacetList fs5(q.beginFacet(), q.endFacet());
    QCOMPARE(fs2.count(), fs5.count());
    QVERIFY(fs2==fs5);
    QhullFacetList fs6= fs2; // copy constructor
    QVERIFY(fs6==fs2);
    std::vector fv= fs2.toStdVector();
    QCOMPARE(fv.size(), 6u);
}//t_construct_qh

void QhullFacetList_test::
t_construct_q()
{
    RboxPoints rcube("c");
    Qhull q(rcube,"QR0");  // rotated unit cube
    QhullFacetList fs2= q.facetList();
    QVERIFY(!fs2.isEmpty());
    QCOMPARE(fs2.count(),6);
    QhullFacetList fs3(q.endFacet(), q.endFacet());
    QVERIFY(fs3.isEmpty());
    QhullFacetList fs4(q.endFacet().previous(), q.endFacet());
    QCOMPARE(fs4.count(), 1);
    QhullFacetList fs5(q.beginFacet(), q.endFacet());
    QCOMPARE(fs2.count(), fs5.count());
    QVERIFY(fs2==fs5);
    QhullFacetList fs6= fs2; // copy constructor
    QVERIFY(fs6==fs2);
    std::vector fv= fs2.toStdVector();
    QCOMPARE(fv.size(), 6u);
}//t_construct_q

void QhullFacetList_test::
t_convert()
{
    RboxPoints rcube("c");
    Qhull q(rcube,"QR0 QV2");  // rotated unit cube
    QhullFacetList fs2= q.facetList();
    QVERIFY(!fs2.isSelectAll());
    QVERIFY(!fs2.isEmpty());
    QCOMPARE(fs2.count(),3);
    std::vector fv= fs2.toStdVector();
    QCOMPARE(fv.size(), 3u);
    QList fv2= fs2.toQList();
    QCOMPARE(fv2.size(), 3);
    std::vector fv5= fs2.vertices_toStdVector();
    QCOMPARE(fv5.size(), 7u);
    QList fv6= fs2.vertices_toQList();
    QCOMPARE(fv6.size(), 7);
    fs2.selectAll();
    QVERIFY(fs2.isSelectAll());
    std::vector fv3= fs2.toStdVector();
    QCOMPARE(fv3.size(), 6u);
    QList fv4= fs2.toQList();
    QCOMPARE(fv4.size(), 6);
    std::vector fv7= fs2.vertices_toStdVector();
    QCOMPARE(fv7.size(), 8u);
    QList fv8= fs2.vertices_toQList();
    QCOMPARE(fv8.size(), 8);
}//t_convert

//! Spot check properties and read-only.  See QhullLinkedList_test
void QhullFacetList_test::
t_readonly()
{
    RboxPoints rcube("c");
    Qhull q(rcube,"QV0");  // good facets are adjacent to point 0
    QhullFacetList fs= q.facetList();
    QVERIFY(!fs.isSelectAll());
    QCOMPARE(fs.count(), 3);
    QCOMPARE(fs.first(), q.firstFacet());
    fs.selectAll();
    QVERIFY(fs.isSelectAll());
    QCOMPARE(fs.count(), 6);
    fs.selectGood();
    QVERIFY(!fs.isSelectAll());
    QCOMPARE(fs.count(), 3);
    fs.selectAll();
    QVERIFY(fs.isSelectAll());
    QCOMPARE(fs.count(), 6);
    QhullFacet f= fs.first();
    QhullFacet f2= fs.last();
    fs.selectAll();
    QVERIFY(fs.contains(f));
    QVERIFY(fs.contains(f2));
    QVERIFY(f.isGood());
    QVERIFY(!f2.isGood());
    fs.selectGood();
    QVERIFY(fs.contains(f));
    QVERIFY(!fs.contains(f2));
}//t_readonly

void QhullFacetList_test::
t_foreach()
{
    RboxPoints rcube("c");
    // Spot check predicates and accessors.  See QhullLinkedList_test
    Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
    QhullFacetList fs= q.facetList();
    QVERIFY(fs.contains(q.firstFacet()));
    QhullFacet f2= q.firstFacet().next();
    QVERIFY(fs.contains(f2));
    QCOMPARE(fs.first(), *fs.begin());
    QCOMPARE(*(fs.end()-1), fs.last());
    QCOMPARE(fs.first(), q.firstFacet());
    QCOMPARE(*fs.begin(), q.beginFacet());
    QCOMPARE(*fs.end(), q.endFacet());

    bool isF2= false;
    int count= 0;
    foreach(QhullFacet f, q.facetList()){  // Qt only
        ++count;
        if(f==f2){
            isF2= true;
            QCOMPARE(count, 2);
        }
    }
    QVERIFY(isF2);
    QCOMPARE(count, q.facetCount());
    QCOMPARE(count, fs.count());

    isF2= false;
    count= 0;
    for(QhullFacet f : q.facetList()){
        ++count;
        if(f==f2){
            isF2= true;
            QCOMPARE(count, 2);
        }
    }
    QVERIFY(isF2);
    QCOMPARE(count, q.facetCount());
    QCOMPARE(count, fs.count());
}//t_foreach

//! \see QhullLinkedList_test::t_QhullLinkedList_iterator
void QhullFacetList_test::
t_java_iterator()
{
    RboxPoints rcube("c");
    Qhull q(rcube, "Qt QR0");  // triangulation of rotated unit cube
    QhullFacet f2= q.firstFacet().next();

    bool isF2= false;
    int count= 0;
    QhullFacetListIterator i(q.facetList());
    while(i.hasNext()){
        QhullFacet f= i.next();
        QCOMPARE(i.peekPrevious(), f);
        ++count;
        if(f==f2){
            isF2= true;
            QCOMPARE(count, 2);
        }
    }
    QVERIFY(isF2);
    QCOMPARE(count, q.facetCount());
}//t_java_iterator

void QhullFacetList_test::
t_io()
{
    RboxPoints rcube("c");
    {
        Qhull q(rcube,"QR0 QV0");   // good facets are adjacent to point 0
        QhullFacetList fs= q.facetList();
        ostringstream os;
        os << fs.print("Show all of FacetList\n");
        os << "\nFacets only\n" << fs;
        os << "\nVertices only\n" << fs.printVertices();
        cout << os.str();
        QString facets= QString::fromStdString(os.str());
        QCOMPARE(facets.count("(v"), 2*7+12*3*2);
        QCOMPARE(facets.count(QRegExp("f\\d")), 2*3*7 + 13*3*2);
    }
}//t_io

}//orgQhull

#include "moc/QhullFacetList_test.moc"
qhull-2020.2/src/qhulltest/QhullFacetSet_test.cpp0000644060175106010010000001225313710652225020257 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/qhulltest/QhullFacetSet_test.cpp#5 $$Change: 3009 $
** $DateTime: 2020/07/30 19:25:22 $$Author: bbarber $
**
****************************************************************************/

//pre-compiled headers
#include 
#include "qhulltest/RoadTest.h" // QT_VERSION

#include "libqhullcpp/QhullFacetSet.h"
#include "libqhullcpp/QhullError.h"
#include "libqhullcpp/QhullFacet.h"
#include "libqhullcpp/Qhull.h"
#include "libqhullcpp/RboxPoints.h"

using std::cout;
using std::endl;
using std::ostringstream;
using std::ostream;
using std::string;

namespace orgQhull {

class QhullFacetSet_test : public RoadTest
{
    Q_OBJECT

#//!\name Test slots
private slots:
    void cleanup();
    void t_construct();
    void t_convert();
    void t_readonly();
    void t_foreach();
    void t_java_iterator();
    void t_io();
};//QhullFacetSet_test

void
add_QhullFacetSet_test()
{
    new QhullFacetSet_test();  // RoadTest::s_testcases
}

//Executed after each testcase
void QhullFacetSet_test::
cleanup()
{
    RoadTest::cleanup();
}

void QhullFacetSet_test::
t_construct()
{
    RboxPoints rcube("c");
    Qhull q(rcube,"QR0");  // rotated unit cube
    QhullFacet f= q.firstFacet();
    QhullFacetSet fs2= f.neighborFacets();
    QVERIFY(!fs2.isEmpty());
    QCOMPARE(fs2.count(),4);
    QhullFacetSet fs4= fs2; // copy constructor
    QVERIFY(fs4==fs2);
    QhullFacetSet fs3(q, q.qh()->facet_mergeset);
    QVERIFY(fs3.isEmpty());
}//t_construct

void QhullFacetSet_test::
t_convert()
{
    RboxPoints rcube("c");
    Qhull q2(rcube,"QR0 QV2");  // rotated unit cube
    QhullFacet f2= q2.firstFacet();
    QhullFacetSet fs2= f2.neighborFacets();
    QVERIFY(!fs2.isSelectAll());
    QCOMPARE(fs2.count(),2);
    std::vector fv= fs2.toStdVector();
    QCOMPARE(fv.size(), 2u);
    QList fv2= fs2.toQList();
    QCOMPARE(fv2.size(), 2);
    fs2.selectAll();
    QVERIFY(fs2.isSelectAll());
    std::vector fv3= fs2.toStdVector();
    QCOMPARE(fv3.size(), 4u);
    QList fv4= fs2.toQList();
    QCOMPARE(fv4.size(), 4);
}//t_convert

//! Spot check properties and read-only.  See QhullSet_test
void QhullFacetSet_test::
t_readonly()
{
    RboxPoints rcube("c");
    Qhull q(rcube,"QV0");  // good facets are adjacent to point 0
    QhullFacetSet fs= q.firstFacet().neighborFacets();
    QVERIFY(!fs.isSelectAll());
    QCOMPARE(fs.count(), 2);
    fs.selectAll();
    QVERIFY(fs.isSelectAll());
    QCOMPARE(fs.count(), 4);
    fs.selectGood();
    QVERIFY(!fs.isSelectAll());
    QCOMPARE(fs.count(), 2);
    QhullFacet f= fs.first();
    QhullFacet f2= fs.last();
    fs.selectAll();
    QVERIFY(fs.contains(f));
    QVERIFY(fs.contains(f2));
    QVERIFY(f.isGood());
    QVERIFY(!f2.isGood());
    fs.selectGood();
    QVERIFY(fs.contains(f));
    QVERIFY(!fs.contains(f2));
}//t_readonly

void QhullFacetSet_test::
t_foreach()
{
    RboxPoints rcube("c");
    // Spot check predicates and accessors.  See QhullLinkedList_test
    Qhull q(rcube,"QR0");  // rotated unit cube
    QhullFacetSet fs= q.firstFacet().neighborFacets();
    QVERIFY(!fs.contains(q.firstFacet()));
    QVERIFY(fs.contains(fs.first()));
    QhullFacet f2= q.firstFacet().next();
    if(!fs.contains(f2)){  // check if 'f2' is the facet opposite firstFacet()
        f2= f2.next();
    }
    QVERIFY(fs.contains(f2));
    QCOMPARE(fs.first(), *fs.begin());
    QCOMPARE(*(fs.end()-1), fs.last());

    bool isF2= false;
    int count= 0;
    foreach(QhullFacet f, q.firstFacet().neighborFacets()){ // Qt only
        ++count;
        if(f==f2){
            isF2= true;
        }
    }
    QVERIFY(isF2);
    QCOMPARE(count, fs.count());

    isF2= false;
    count= 0;
    for(QhullFacet f : q.firstFacet().neighborFacets()){
        ++count;
        if(f==f2){
            isF2= true;
        }
    }
    QVERIFY(isF2);
    QCOMPARE(count, fs.count());
}//t_foreach

void QhullFacetSet_test::
t_java_iterator()
{
    RboxPoints rcube("c");
    // Spot check predicates and accessors.  See QhullLinkedList_test
    Qhull q(rcube, "QR0");  // rotated unit cube
    QhullFacetSet fs= q.firstFacet().neighborFacets();
    QhullFacet f2= fs.at(1);

    bool isF2= false;
    int count= 0;
    QhullFacetSetIterator i(q.firstFacet().neighborFacets());
    while(i.hasNext()){
        QhullFacet f= i.next();
        QCOMPARE(i.peekPrevious(), f);
        ++count;
        if(f==f2){
            isF2= true;
            QCOMPARE(count, 2);
        }
    }
    QVERIFY(isF2);
    QCOMPARE(count, fs.count());
}//t_java_iterator

void QhullFacetSet_test::
t_io()
{
    RboxPoints rcube("c");
    {
        Qhull q(rcube,"QR0 QV0");   // good facets are adjacent to point 0
        QhullFacetSet fs= q.firstFacet().neighborFacets();
        ostringstream os;
        os << fs.print("Neighbors of first facet with point 0");
        os << fs.printIdentifiers("\nFacet identifiers: ");
        cout << os.str();
        QString facets= QString::fromStdString(os.str());
        QCOMPARE(facets.count(QRegExp(" f[0-9]")), 2+13*2);
    }
}//t_io

}//orgQhull

#include "moc/QhullFacetSet_test.moc"
qhull-2020.2/src/qhulltest/QhullFacet_test.cpp0000644060175106010010000002632013706714004017602 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/qhulltest/QhullFacet_test.cpp#6 $$Change: 3006 $
** $DateTime: 2020/07/29 18:28:16 $$Author: bbarber $
**
****************************************************************************/

//pre-compiled headers
#include 
#include "qhulltest/RoadTest.h" // QT_VERSION

#include "libqhullcpp/QhullFacet.h"
#include "libqhullcpp/QhullError.h"
#include "libqhullcpp/Coordinates.h"
#include "libqhullcpp/RboxPoints.h"
#include "libqhullcpp/QhullFacetList.h"
#include "libqhullcpp/QhullFacetSet.h"
#include "libqhullcpp/QhullPointSet.h"
#include "libqhullcpp/QhullRidge.h"
#include "libqhullcpp/Qhull.h"

using std::cout;
using std::endl;
using std::ostringstream;
using std::ostream;
using std::string;

namespace orgQhull {

class QhullFacet_test : public RoadTest
{
    Q_OBJECT

#//!\name Test slots
private slots:
    void cleanup();
    void t_construct_qh();
    void t_constructConvert();
    void t_getSet();
    void t_getSet2d();
    void t_value();
    void t_foreach();
    void t_io();
};//QhullFacet_test

void
add_QhullFacet_test()
{
    new QhullFacet_test();  // RoadTest::s_testcases
}

//Executed after each testcase
void QhullFacet_test::
cleanup()
{
    RoadTest::cleanup();
}

void QhullFacet_test::
t_construct_qh()
{
    // Qhull.runQhull() constructs QhullFacets as facetT
    QhullQh qh;
    QhullFacet f(&qh);
    QVERIFY(!f.isValid());
    QCOMPARE(f.dimension(),0);
}//t_construct_qh

void QhullFacet_test::
t_constructConvert()
{
    // Qhull.runQhull() constructs QhullFacets as facetT
    Qhull q2;
    QhullFacet f(q2);
    QVERIFY(!f.isValid());
    QCOMPARE(f.dimension(),0);
    RboxPoints rcube("c");
    Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
    QhullFacet f2(q.beginFacet());
    QCOMPARE(f2.dimension(),3);
    f= f2; // copy assignment
    QVERIFY(f.isValid());
    QCOMPARE(f.dimension(),3);
    QhullFacet f5= f2;
    QVERIFY(f5==f2);
    QVERIFY(f5==f);
    QhullFacet f3(q, f2.getFacetT());
    QCOMPARE(f,f3);
    QhullFacet f4(q, f2.getBaseT());
    QCOMPARE(f,f4);
}//t_constructConvert

void QhullFacet_test::
t_getSet()
{
    RboxPoints rcube("c");
    {
        Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
        cout << " rbox c | qhull Qt QR0 QR" << q.rotateRandom() << "   distanceEpsilon " << q.distanceEpsilon() << endl;
        QCOMPARE(q.facetCount(), 12);
        QCOMPARE(q.vertexCount(), 8);
        QhullFacetListIterator i(q.facetList());
        while(i.hasNext()){
            const QhullFacet f= i.next();
            cout << f.id() << endl;
            QhullFacet f2;
            f2.setFacetT(f.qh(), f.getFacetT());
            QCOMPARE(f, f2);
            QCOMPARE(f.dimension(),3);
            QVERIFY(f.id()>0 && f.id()<=39);
            QVERIFY(f.isValid());
            if(i.hasNext()){
                QCOMPARE(f.next(), i.peekNext());
                QVERIFY(f.next()!=f);
                QCOMPARE(f.next().previous(), f);
                QVERIFY(f.hasNext());
                QVERIFY(f.next().hasPrevious());
            }else
              QVERIFY(!f.hasNext());
            QVERIFY(i.hasPrevious());
            QCOMPARE(f, i.peekPrevious());
        }
        while(i.hasPrevious()){
          const QhullFacet f= i.previous();
          cout << f.id() << endl;
          QVERIFY(f.isValid());
          if(i.hasPrevious()){
            QVERIFY(f.hasPrevious());
            QCOMPARE(f.previous(), i.peekPrevious());
            QVERIFY(f.previous()!=f);
            QVERIFY(f.previous().hasNext());
            QCOMPARE(f.previous().next(), f);
          }else
            QVERIFY(!f.hasPrevious());
          QVERIFY(i.hasNext());
          QCOMPARE(f, i.peekNext());
        }
        // test tricoplanarOwner
        QhullFacet facet= q.beginFacet();
        QhullFacet tricoplanarOwner= facet.tricoplanarOwner();
        int tricoplanarCount= 0;
        i.toFront();
        while(i.hasNext()){
            const QhullFacet f= i.next();
            if(f.tricoplanarOwner()==tricoplanarOwner){
                tricoplanarCount++;
            }
        }
        QCOMPARE(tricoplanarCount, 2);
        int tricoplanarCount2= 0;
        foreach (QhullFacet f, q.facetList()){  // Qt only
            QhullHyperplane hi= f.innerplane();
            QCOMPARE(hi.count(), 3);
            double innerOffset= hi.offset() + 0.5;
            cout << "InnerPlane: " << hi << "   innerOffset+0.5 " << innerOffset << endl;
            QhullHyperplane h= f.hyperplane();
            double offset= h.offset() + 0.5;
            cout << "Hyperplane: " << h << "   offset+0.5 " << offset << endl;
            QCOMPARE(h.count(), 3);
            QCOMPARE(h.offset(), -0.5);
            double n= h.norm();
            QCOMPARE(n, 1.0);
            QhullHyperplane ho= f.outerplane();
            QCOMPARE(ho.count(), 3);
            double outerOffset= ho.offset()+0.5;
            cout << "OuterPlane: " << ho << "   outerOffset+0.5 " << outerOffset << endl;
            QVERIFY(offset < innerOffset); // the outerOffset is more negative than the innerOffset.  The expected values are -0.5 for the unit cube centered at the origin
            QVERIFY(outerOffset < offset); // QR1595623290 was 8.4x,   innerOffset+0.5 9.71445e-15, 2.5e-16 max. distance of a new vertex to a facet
            QVERIFY2(fabs(innerOffset) < (10 * q.distanceEpsilon()), "Guessed epsilon from -0.5 due to rotation");   
            QVERIFY2(fabs(outerOffset) < (10 * q.distanceEpsilon()), "Guessed epsilon from -0.5 due to rotation");

            for(int k= 0; k<3; k++){
                QVERIFY(ho[k]==hi[k]);
                QVERIFY(ho[k]==h[k]);
            }
            QhullPoint center= f.getCenter();
            cout << "Center: " << center;
            double d= f.distance(center);
            QVERIFY(d < innerOffset-outerOffset);
            QhullPoint center2= f.getCenter(qh_PRINTcentrums);
            QCOMPARE(center, center2);
            if(f.tricoplanarOwner()==tricoplanarOwner){
                tricoplanarCount2++;
            }
            cout << endl;
        }
        QCOMPARE(tricoplanarCount2, 2);
        Qhull q2(rcube,"d Qz Qt QR0");  // 3-d triangulation of Delaunay triangulation (the cube)
        cout << " rbox c | qhull d Qz Qt QR0 QR" << q2.rotateRandom() << "   distanceEpsilon " << q2.distanceEpsilon() << endl;
        QhullFacet f2= q2.firstFacet();
        QhullPoint center3= f2.getCenter(qh_PRINTtriangles);
        QCOMPARE(center3.dimension(), 3);
        QhullPoint center4= f2.getCenter();
        QCOMPARE(center4.dimension(), 4);
        for(int k= 0; k<3; k++){
            QVERIFY(center4[k]==center3[k]);
        }
        Qhull q3(rcube,"v Qz QR0");  // Voronoi diagram of a cube (one vertex)
        cout << " rbox c | qhull v Qz QR0 QR" << q3.rotateRandom() << "   distanceEpsilon " << q3.distanceEpsilon() << endl;

        q3.setFactorEpsilon(400); // Voronoi vertices are not necessarily within distance episilon
        QhullPoint origin= q3.inputOrigin();
        int voronoiCount= 0;
        foreach(QhullFacet f, q3.facetList()){ //Qt only
            if(f.isGood()){
                ++voronoiCount;
                QhullPoint p= f.voronoiVertex();
                cout << p.print("Voronoi vertex: ")
                    << " Is it within " << q3.factorEpsilon() << " * distanceEpsilon (" << q3.distanceEpsilon() << ") of the origin?" << endl;
                QCOMPARE(p, origin);
            }
        }
        QCOMPARE(voronoiCount, 1);
    }
}//t_getSet

void QhullFacet_test::
t_getSet2d()
{
    RboxPoints rsquare("c D2");
    Qhull q(rsquare, "o");  // convex hull of square
    q.setOutputStream(&cout);
    cout << "Points and facets.  Facet vertices in counter-clockwise order (option 'o')\n";
    q.outputQhull();
    int n= q.facetCount();
    QhullFacet f= q.firstFacet();
    QhullVertex v;
    cout << "Facets and vertices in counter-clockwise order (f.nextFacet2d)\n";
    for(int i= 0; imaxoutside;
                QVERIFY(maxoutside<1e-7);
            #endif
        }
    }
}//t_value

void QhullFacet_test::
t_foreach()
{
    RboxPoints rcube("c W0 300");  // cube plus 300 points on its surface
    {
        Qhull q(rcube, "QR0 Qc"); // keep coplanars, thick facet, and rotate the cube
        int coplanarCount= 0;
        foreach(const QhullFacet f, q.facetList()){
            QhullPointSet coplanars= f.coplanarPoints();
            coplanarCount += coplanars.count();
            QhullFacetSet neighbors= f.neighborFacets();
            QCOMPARE(neighbors.count(), 4);
            QhullPointSet outsides= f.outsidePoints();
            QCOMPARE(outsides.count(), 0);
            QhullRidgeSet ridges= f.ridges();
            QCOMPARE(ridges.count(), 4);
            QhullVertexSet vertices= f.vertices();
            QCOMPARE(vertices.count(), 4);
            int ridgeCount= 0;
            QhullRidge r= ridges.first();
            for(int r0= r.id(); ridgeCount==0 || r.id()!=r0; r= r.nextRidge3d(f)){
                ++ridgeCount;
                if(!r.hasNextRidge3d(f)){
                    QFAIL("Unexpected simplicial facet.  They only have ridges to non-simplicial neighbors.");
                }
            }
            QCOMPARE(ridgeCount, 4);
        }
        QCOMPARE(coplanarCount, 300);
    }
}//t_foreach

void QhullFacet_test::
t_io()
{
    RboxPoints rcube("c");
    {
        Qhull q(rcube, "");
        QhullFacet f= q.beginFacet();
        cout << f;
        ostringstream os;
        os << f.print("\nWith a message\n");
        os << "\nPrint header for the same facet\n";
        os << f.printHeader();
        os << "\nPrint each component\n";
        os << f.printFlags("    - flags:");
        os << f.printCenter(qh_PRINTfacets, "    - center: ");
        os << f.printRidges();
        cout << os.str();
        ostringstream os2;
        os2 << f;
        QString facetString2= QString::fromStdString(os2.str());
        facetString2.replace(QRegExp("\\s\\s+"), " ");
        facetString2.replace(QRegExp("seen "), "");
        ostringstream os3;
        q.qh()->setOutputStream(&os3);
        q.outputQhull("f");
        QString facetsString= QString::fromStdString(os3.str());
        QString facetString3= facetsString.mid(facetsString.indexOf("- f1\n"));
        facetString3= facetString3.left(facetString3.indexOf("\n- f")+1);
        facetString3.replace(QRegExp("\\s\\s+"), " ");
        QCOMPARE(facetString2, facetString3);
    }
}//t_io

// toQhullFacet is static_cast only

}//orgQhull

#include "moc/QhullFacet_test.moc"
qhull-2020.2/src/qhulltest/QhullHyperplane_test.cpp0000644060175106010010000003202013706637722020674 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2009-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/qhulltest/QhullHyperplane_test.cpp#4 $$Change: 3001 $
** $DateTime: 2020/07/24 20:43:28 $$Author: bbarber $
**
****************************************************************************/

//pre-compiled headers
#include 
#include "qhulltest/RoadTest.h" // QT_VERSION

#include "libqhullcpp/QhullHyperplane.h"
#include "libqhullcpp/QhullError.h"
#include "libqhullcpp/RboxPoints.h"
#include "libqhullcpp/QhullFacet.h"
#include "libqhullcpp/QhullFacetList.h"
#include "libqhullcpp/QhullFacetSet.h"
#include "libqhullcpp/Qhull.h"

#include 
#include 

using std::cout;
using std::endl;
using std::ostringstream;
using std::ostream;
using std::string;

namespace orgQhull {

class QhullHyperplane_test : public RoadTest
{
    Q_OBJECT

#//!\name Test slots
private slots:
    void cleanup();
    void t_construct();
    void t_construct_qh();
    void t_convert();
    void t_readonly();
    void t_define();
    void t_value();
    void t_operator();
    void t_iterator();
    void t_const_iterator();
    void t_foreach();
    void t_qhullHyperplane_iterator();
    void t_java_iterator();
    void t_io();
};//QhullHyperplane_test

void
add_QhullHyperplane_test()
{
    new QhullHyperplane_test();  // RoadTest::s_testcases
}

//Executed after each testcase
void QhullHyperplane_test::
cleanup()
{
    RoadTest::cleanup();
}

void QhullHyperplane_test::
t_construct()
{
    QhullHyperplane h4;
    QVERIFY(!h4.isValid());
    QCOMPARE(h4.dimension(), 0);
    // Qhull.runQhull() constructs QhullFacets as facetT
    RboxPoints rcube("c");
    Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
    QhullHyperplane h(q);
    QVERIFY(!h.isValid());
    QCOMPARE(h.dimension(), 0);
    QCOMPARE(h.coordinates(),static_cast(0));
    QhullFacet f= q.firstFacet();
    QhullHyperplane h2(f.hyperplane());
    QVERIFY(h2.isValid());
    QCOMPARE(h2.dimension(), 3);
    h= h2;
    QCOMPARE(h, h2);
    QhullHyperplane h3(q, h2.dimension(), h2.coordinates(), h2.offset());
    QCOMPARE(h2, h3);
    QhullHyperplane h5= h2; // copy constructor
    QVERIFY(h5==h2);
}//t_construct

void QhullHyperplane_test::
t_construct_qh()
{
    // Qhull.runQhull() constructs QhullFacets as facetT
    RboxPoints rcube("c");
    Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
    QhullFacet f= q.firstFacet();
    QhullHyperplane h2(f.hyperplane());
    QVERIFY(h2.isValid());
    QCOMPARE(h2.dimension(), 3);
    // h= h2;  // copy assignment disabled, ambiguous
    QhullHyperplane h3(q.qh(), h2.dimension(), h2.coordinates(), h2.offset());
    QCOMPARE(h2, h3);
    QhullHyperplane h5= h2; // copy constructor
    QVERIFY(h5==h2);
}//t_construct_qh

void QhullHyperplane_test::
t_convert()
{
    RboxPoints rcube("c");
    Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
    QhullHyperplane h= q.firstFacet().hyperplane();
    std::vector fs= h.toStdVector();
    QCOMPARE(fs.size(), 4u);
    double offset= fs.back();
    fs.pop_back();
    QCOMPARE(offset, -0.5);

    double squareNorm= inner_product(fs.begin(), fs.end(), fs.begin(), 0.0);
    QCOMPARE(squareNorm, 1.0);
    QList qs= h.toQList();
    QCOMPARE(qs.size(), 4);
    double offset2= qs.takeLast();
    QCOMPARE(offset2, -0.5);
    double squareNorm2= std::inner_product(qs.begin(), qs.end(), qs.begin(), 0.0);
    QCOMPARE(squareNorm2, 1.0);
}//t_convert

void QhullHyperplane_test::
t_readonly()
{
    RboxPoints rcube("c");
    {
        Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
        QhullFacetList fs= q.facetList();
        QhullFacetListIterator i(fs);
        while(i.hasNext()){
            QhullFacet f= i.next();
            QhullHyperplane h= f.hyperplane();
            int id= f.id();
            cout << "h" << id << endl;
            QVERIFY(h.isValid());
            QCOMPARE(h.dimension(),3);
            const coordT *c= h.coordinates();
            coordT *c2= h.coordinates();
            QCOMPARE(c, c2);
            const coordT *c3= h.begin();
            QCOMPARE(c, c3);
            QCOMPARE(h.offset(), -0.5);
            int j= h.end()-h.begin();
            QCOMPARE(j, 3);
            double squareNorm= std::inner_product(h.begin(), h.end(), h.begin(), 0.0);
            QCOMPARE(squareNorm, 1.0);
        }
        QhullHyperplane h2= fs.first().hyperplane();
        QhullHyperplane h3= fs.last().hyperplane();
        QVERIFY(h2!=h3);
        QVERIFY(h3.coordinates()!=h2.coordinates());
    }
}//t_readonly

void QhullHyperplane_test::
t_define()
{
    RboxPoints rcube("c");
    {
        Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
        QhullFacetList fs= q.facetList();
        QhullHyperplane h= fs.first().hyperplane();
        QhullHyperplane h2= h;
        QVERIFY(h==h2);
        QhullHyperplane h3= fs.last().hyperplane();
        QVERIFY(h2!=h3);

        QhullHyperplane h4= h3;
        h4.defineAs(h2);
        QVERIFY(h2==h4);
        QhullHyperplane p5= h3;
        p5.defineAs(h2.dimension(), h2.coordinates(), h2.offset());
        QVERIFY(h2==p5);
        QhullHyperplane h6= h3;
        h6.setCoordinates(h2.coordinates());
        QCOMPARE(h2.coordinates(), h6.coordinates());
        h6.setOffset(h2.offset());
        QCOMPARE(h2.offset(), h6.offset());
        QVERIFY(h2==h6);
        h6.setDimension(2);
        QCOMPARE(h6.dimension(), 2);
        QVERIFY(h2!=h6);
    }
}//t_define

void QhullHyperplane_test::
t_value()
{
    RboxPoints rcube("c G1");
    Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
    QhullFacet f= q.firstFacet();
    QhullFacet f2= f.neighborFacets().at(0);
    const QhullHyperplane h= f.hyperplane();
    const QhullHyperplane h2= f2.hyperplane();   // At right angles
    double dist= h.distance(q.origin());
    QCOMPARE(dist, -1.0);
    double norm= h.norm();
    QCOMPARE(norm, 1.0);
    double angle= h.hyperplaneAngle(h2);
    cout << "angle " << angle << endl;
    QCOMPARE(angle+1.0, 1.0); // qFuzzyCompare does not work for 0.0
    QVERIFY(h==h);
    QVERIFY(h!=h2);
}//t_value

void QhullHyperplane_test::
t_operator()
{
    RboxPoints rcube("c");
    Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
    const QhullHyperplane h= q.firstFacet().hyperplane();
    //operator== and operator!= tested elsewhere
    const coordT *c= h.coordinates();
    for(int k=h.dimension(); k--; ){
        QCOMPARE(c[k], h[k]);
    }
    //h[0]= 10.0; // compiler error, const
    QhullHyperplane h2= q.firstFacet().hyperplane();
    h2[0]= 10.0;  // Overwrites Hyperplane coordinate!
    QCOMPARE(h2[0], 10.0);
}//t_operator

void QhullHyperplane_test::
t_iterator()
{
    RboxPoints rcube("c");
    {
        Qhull q(rcube,"QR0");  // rotated unit cube
        QhullHyperplane h= q.firstFacet().hyperplane();
        QCOMPARE(h.count(), 3);
        QCOMPARE(h.size(), 3u);
        QhullHyperplane::Iterator i= h.begin();
        QhullHyperplane::iterator i2= h.begin();
        QVERIFY(i==i2);
        QVERIFY(i>=i2);
        QVERIFY(i<=i2);
        i= h.begin();
        QVERIFY(i==i2);
        i2= h.end();
        QVERIFY(i!=i2);
        double d3= *i;
        i2--;
        double d2= *i2;
        QCOMPARE(d3, h[0]);
        QCOMPARE(d2, h[2]);
        QhullHyperplane::Iterator i3(i2);
        QCOMPARE(*i2, *i3);

        (i3= i)++;
        QCOMPARE((*i3), h[1]);
        QVERIFY(i==i);
        QVERIFY(i!=i2);
        QVERIFY(ii);
        QVERIFY(i2>=i);

        QhullHyperplane::ConstIterator i4= h.begin();
        QVERIFY(i==i4); // iterator COMP const_iterator
        QVERIFY(i<=i4);
        QVERIFY(i>=i4);
        QVERIFY(i4==i); // const_iterator COMP iterator
        QVERIFY(i4<=i);
        QVERIFY(i4>=i);
        QVERIFY(i>=i4);
        QVERIFY(i4<=i);
        QVERIFY(i2!=i4);
        QVERIFY(i2>i4);
        QVERIFY(i2>=i4);
        QVERIFY(i4!=i2);
        QVERIFY(i4i);
        QVERIFY(i4>=i);

        i= h.begin();
        i2= h.begin();
        QCOMPARE(i, i2++);
        QCOMPARE(*i2, h[1]);
        QCOMPARE(++i, i2);
        QCOMPARE(i, i2--);
        QCOMPARE(i2, h.begin());
        QCOMPARE(--i, i2);
        QCOMPARE(i2 += 3, h.end());
        QCOMPARE(i2 -= 3, h.begin());
        QCOMPARE(i2+0, h.begin());
        QCOMPARE(i2+3, h.end());
        i2 += 3;
        i= i2-0;
        QCOMPARE(i, i2);
        i= i2-3;
        QCOMPARE(i, h.begin());
        QCOMPARE(i2-i, 3);

        //h.begin end tested above

        // QhullHyperplane is const-only
    }
}//t_iterator

void QhullHyperplane_test::
t_const_iterator()
{
    RboxPoints rcube("c");
    {
        Qhull q(rcube,"QR0");  // rotated unit cube
        QhullHyperplane h= q.firstFacet().hyperplane();
        QhullHyperplane::ConstIterator i= h.begin();
        QhullHyperplane::const_iterator i2= h.begin();
        QVERIFY(i==i2);
        QVERIFY(i>=i2);
        QVERIFY(i<=i2);
        i= h.begin();
        QVERIFY(i==i2);
        i2= h.end();
        QVERIFY(i!=i2);
        double d3= *i;
        i2--;
        double d2= *i2;
        QCOMPARE(d3, h[0]);
        QCOMPARE(d2, h[2]);
        QhullHyperplane::ConstIterator i3(i2);
        QCOMPARE(*i2, *i3);

        (i3= i)++;
        QCOMPARE((*i3), h[1]);
        QVERIFY(i==i);
        QVERIFY(i!=i2);
        QVERIFY(ii);
        QVERIFY(i2>=i);

        // See t_iterator for const_iterator COMP iterator

        i= h.begin();
        i2= h.constBegin();
        QCOMPARE(i, i2++);
        QCOMPARE(*i2, h[1]);
        QCOMPARE(++i, i2);
        QCOMPARE(i, i2--);
        QCOMPARE(i2, h.constBegin());
        QCOMPARE(--i, i2);
        QCOMPARE(i2+=3, h.constEnd());
        QCOMPARE(i2-=3, h.constBegin());
        QCOMPARE(i2+0, h.constBegin());
        QCOMPARE(i2+3, h.constEnd());
        i2 += 3;
        i= i2-0;
        QCOMPARE(i, i2);
        i= i2-3;
        QCOMPARE(i, h.constBegin());
        QCOMPARE(i2-i, 3);

        // QhullHyperplane is const-only
    }
}//t_const_iterator

void QhullHyperplane_test::
t_foreach()
{
    RboxPoints rcube("c");
    Qhull q(rcube, "QR0");  // rotated unit cube
    QhullHyperplane h= q.firstFacet().hyperplane();
    coordT c2= (h.coordinates())[1];
    
    bool isC2= false;
    int count= 0;
    foreach(coordT c, q.firstFacet().hyperplane()){
        ++count;
        if(c==c2){
            isC2= true;
            QCOMPARE(count, 2);
        }
    }
    QVERIFY(isC2);
    QCOMPARE(count, q.dimension());
    
    isC2= false;
    count= 0;
    for(coordT c : q.firstFacet().hyperplane()){
        ++count;
        if(c==c2){
            isC2= true;
            QCOMPARE(count, 2);
        }
    }
    QVERIFY(isC2);
    QCOMPARE(count, q.dimension());
}//t_foreach

void QhullHyperplane_test::
t_qhullHyperplane_iterator()
{
    RboxPoints rcube("c");
    Qhull q(rcube,"QR0");  // rotated unit cube
    QhullHyperplane h= q.firstFacet().hyperplane();
    QhullHyperplaneIterator i2(h);
    QCOMPARE(h.dimension(), 3);
    QhullHyperplaneIterator i= h;
    QVERIFY(i2.hasNext());
    QVERIFY(!i2.hasPrevious());
    QVERIFY(i.hasNext());
    QVERIFY(!i.hasPrevious());
    i2.toBack();
    i.toFront();
    QVERIFY(!i2.hasNext());
    QVERIFY(i2.hasPrevious());
    QVERIFY(i.hasNext());
    QVERIFY(!i.hasPrevious());

    // i at front, i2 at end/back, 3 coordinates
    QCOMPARE(i.peekNext(), h[0]);
    QCOMPARE(i2.peekPrevious(), h[2]);
    QCOMPARE(i2.previous(), h[2]);
    QCOMPARE(i2.previous(), h[1]);
    QCOMPARE(i2.previous(), h[0]);
    QVERIFY(!i2.hasPrevious());
    QCOMPARE(i.peekNext(), h[0]);
    // i.peekNext()= 1.0; // compiler error, i is const
    QCOMPARE(i.next(), h[0]);
    QCOMPARE(i.peekNext(), h[1]);
    QCOMPARE(i.next(), h[1]);
    QCOMPARE(i.next(), h[2]);
    QVERIFY(!i.hasNext());
    i.toFront();
    QCOMPARE(i.next(), h[0]);
}//t_qhullHyperplane_iterator

void QhullHyperplane_test::
t_java_iterator()
{
    RboxPoints rcube("c");
    Qhull q(rcube, "QR0");  // rotated unit cube
    QhullHyperplane h= q.firstFacet().hyperplane();
    coordT c2= (h.coordinates())[1];
    
    bool isC2= false;
    int count= 0;
    QhullHyperplaneIterator i(q.firstFacet().hyperplane());
    while(i.hasNext()){
        coordT c= i.next();
        ++count;
        if(c==c2){
            isC2= true;
            QCOMPARE(count, 2);
        }
    }
    QVERIFY(isC2);
    QCOMPARE(count, q.dimension());
}//t_java_iterator

void QhullHyperplane_test::
t_io()
{
    RboxPoints rcube("c");
    {
        Qhull q(rcube, "");
        QhullHyperplane h= q.firstFacet().hyperplane();
        ostringstream os;
        os << "Hyperplane:\n";
        os << h;
        os << h.print("message");
        os << h.print(" and a message ", " offset ");
        cout << os.str();
        QString s= QString::fromStdString(os.str());
        QCOMPARE(s.count("1"), 3);
        // QCOMPARE(s.count(QRegExp("f\\d")), 3*7 + 13*3*2);
    }
}//t_io


}//orgQhull

#include "moc/QhullHyperplane_test.moc"
qhull-2020.2/src/qhulltest/QhullLinkedList_test.cpp0000644060175106010010000002455513710652225020633 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2009-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/qhulltest/QhullLinkedList_test.cpp#5 $$Change: 3009 $
** $DateTime: 2020/07/30 19:25:22 $$Author: bbarber $
**
****************************************************************************/

//pre-compiled headers
#include 
#include "qhulltest/RoadTest.h"

#include "libqhullcpp/QhullLinkedList.h"
#include "libqhullcpp/Qhull.h"
#include "libqhullcpp/QhullVertex.h"
#include "libqhullcpp/RboxPoints.h"

namespace orgQhull {

class QhullLinkedList_test : public RoadTest
{
    Q_OBJECT

#//!\name Test slots
private slots:
    void cleanup();
    void t_construct();
    void t_convert();
    void t_element();
    void t_search();
    void t_iterator();
    void t_const_iterator();
    void t_foreach();
    void t_QhullLinkedList_iterator();
    void t_java_iterator();
    void t_io();
};//QhullLinkedList_test

void
add_QhullLinkedList_test()
{
    new QhullLinkedList_test();  // RoadTest::s_testcases
}

//Executed after each testcase
void QhullLinkedList_test::
cleanup()
{
    RoadTest::cleanup();
}

void QhullLinkedList_test::
t_construct()
{
    // QhullLinkedList vs; //private (compiler error).  No memory allocation
    RboxPoints rcube("c");
    {
        Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
        QCOMPARE(q.facetCount(), 12);
        QhullVertexList vs= QhullVertexList(q.beginVertex(), q.endVertex());
        QCOMPARE(vs.count(), 8);
        QCOMPARE(vs.size(), 8u);
        QVERIFY(!vs.isEmpty());
        QhullVertexList vs2= q.vertexList();
        QCOMPARE(vs2.count(), 8);
        QCOMPARE(vs2.size(),8u);
        QVERIFY(!vs2.isEmpty());
        QVERIFY(vs==vs2);
        // vs= vs2; // disabled.  Would not copy the vertices
        QhullVertexList vs3= vs2; // copy constructor
        QVERIFY(vs3==vs2);
    }
}//t_construct

void QhullLinkedList_test::
t_convert()
{
    RboxPoints rcube("c");
    {
        Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
        QCOMPARE(q.facetCount(), 12);
        QhullVertexList vs= q.vertexList();
        QCOMPARE(vs.size(), 8u);
        QVERIFY(!vs.isEmpty());
        std::vector vs2= vs.toStdVector();
        QCOMPARE(vs2.size(), vs.size());
        QhullVertexList::Iterator i= vs.begin();
        for(int k= 0; k<(int)vs2.size(); k++){
            QCOMPARE(vs2[k], *i++);
        }
        QList vs3= vs.toQList();
        QCOMPARE(vs3.count(), vs.count());
        i= vs.begin();
        for(int k= 0; k
#include "RoadTest.h" // QT_VERSION

#include "libqhullcpp/QhullPointSet.h"
#include "libqhullcpp/RboxPoints.h"
#include "libqhullcpp/QhullPoint.h"
#include "libqhullcpp/QhullFacet.h"
#include "libqhullcpp/QhullFacetList.h"
#include "libqhullcpp/Qhull.h"

using std::cout;
using std::endl;
using std::ostringstream;

namespace orgQhull {

class QhullPointSet_test : public RoadTest
{
    Q_OBJECT

#//!\name Test slots
private slots:
    void cleanup();
    void t_construct();
    void t_convert();
    void t_element();
    void t_iterator();
    void t_const_iterator();
    void t_search();
    void t_foreach();
    void t_pointset_iterator();
    void t_java_iterator();
    void t_io();
};//QhullPointSet_test

void
add_QhullPointSet_test()
{
    new QhullPointSet_test();  // RoadTest::s_testcases
}

//Executed after each testcase
void QhullPointSet_test::
cleanup()
{
    RoadTest::cleanup();
}

void QhullPointSet_test::
t_construct()
{
    // Default constructor is disallowed (i.e., private)
    RboxPoints rcube("c W0 1000");
    Qhull q(rcube,"Qc");  // cube with 1000 coplanar points
    int coplanarCount= 0;
    foreach(QhullFacet f, q.facetList()){
        QhullPointSet ps(q, f.getFacetT()->outsideset);
        QVERIFY(ps.isEmpty());
        QCOMPARE(ps.count(), 0);
        QCOMPARE(ps.size(), 0u);
        QhullPointSet ps2(q.qh(), f.getFacetT()->coplanarset);
        QVERIFY(!ps2.isEmpty());
        coplanarCount += ps2.count();
        QCOMPARE(ps2.count(), (int)ps2.size());
        QhullPointSet ps3(ps2);
        QVERIFY(!ps3.isEmpty());
        QCOMPARE(ps3.count(), ps2.count());
        QVERIFY(ps3==ps2);
        QVERIFY(ps3!=ps);
        QhullPointSet ps4= ps3;
        QVERIFY(ps4==ps2);
    }
    QCOMPARE(coplanarCount, 1000);
}//t_construct

void QhullPointSet_test::
t_convert()
{
    RboxPoints rcube("c W0 1000");
    Qhull q(rcube,"Qc");  // cube with 1000 coplanar points
    QhullFacet f= q.firstFacet();
    QhullPointSet ps= f.coplanarPoints();
    QVERIFY(ps.count()>=1);   // Sometimes no coplanar points
    std::vector vs= ps.toStdVector();
    QCOMPARE(vs.size(), ps.size());
    QhullPoint p= ps[0];
    QhullPoint p2= vs[0];
    QCOMPARE(p, p2);
    QList qs= ps.toQList();
    QCOMPARE(qs.size(), static_cast(ps.size()));
    QhullPoint p3= qs[0];
    QCOMPARE(p3, p);
}//t_convert

// readonly tested in t_construct
//   empty, isEmpty, ==, !=, size

void QhullPointSet_test::
t_element()
{
    RboxPoints rcube("c W0 1000");
    Qhull q(rcube,"Qc");  // cube with 1000 coplanar points
    QhullFacet f= q.firstFacet();
    QhullPointSet ps= f.coplanarPoints();
    QVERIFY(ps.count()>=3);  // Sometimes no coplanar points
    QhullPoint p= ps[0];
    QCOMPARE(p, ps[0]);
    QhullPoint p2= ps[ps.count()-1];
    QCOMPARE(ps.at(1), ps[1]);
    QCOMPARE(ps.second(), ps[1]);
    QCOMPARE(ps.first(), p);
    QCOMPARE(ps.front(), ps.first());
    QCOMPARE(ps.last(), p2);
    QCOMPARE(ps.back(), ps.last());
    QhullPoint p8(q);
    QCOMPARE(ps.value(2), ps[2]);
    QCOMPARE(ps.value(-1), p8);
    QCOMPARE(ps.value(ps.count()), p8);
    QCOMPARE(ps.value(ps.count(), p), p);
    QVERIFY(ps.value(1, p)!=p);
    QhullPointSet ps8= f.coplanarPoints();
    QhullPointSet::Iterator i= ps8.begin();
    foreach(QhullPoint p9, ps){  // Qt only
        QCOMPARE(p9.dimension(), 3);
        QCOMPARE(p9, *i++);
    }
}//t_element

void QhullPointSet_test::
t_iterator()
{
    RboxPoints rcube("c W0 1000");
    Qhull q(rcube,"Qc");  // cube with 1000 coplanar points
    QhullFacet f= q.firstFacet();
    QhullPointSet ps= f.coplanarPoints();
    QVERIFY(ps.count()>=3);  // Sometimes no coplanar points
    QhullPointSet::Iterator i= ps.begin();
    QhullPointSet::iterator i2= ps.begin();
    QVERIFY(i==i2);
    QVERIFY(i>=i2);
    QVERIFY(i<=i2);
    i= ps.begin();
    QVERIFY(i==i2);
    i2= ps.end();
    QVERIFY(i!=i2);
    QhullPoint p= *i;
    QCOMPARE(p.dimension(), q.dimension());
    QCOMPARE(p, ps[0]);
    i2--;
    QhullPoint p2= *i2;
    QCOMPARE(p2.dimension(), q.dimension());
    QCOMPARE(p2, ps.last());
    QhullPointSet::Iterator i5(i2);
    QCOMPARE(*i2, *i5);
    QhullPointSet::Iterator i3= i+1;
    QVERIFY(i!=i3);
    QCOMPARE(i[1], *i3);
    (i3= i)++;
    QCOMPARE((*i3)[0], ps[1][0]);
    QCOMPARE((*i3).dimension(), 3);

    QVERIFY(i==i);
    QVERIFY(i!=i3);
    QVERIFY(ii);
    QVERIFY(i3>=i);

    QhullPointSet::ConstIterator i4= ps.begin();
    QVERIFY(i==i4); // iterator COMP const_iterator
    QVERIFY(i<=i4);
    QVERIFY(i>=i4);
    QVERIFY(i4==i); // const_iterator COMP iterator
    QVERIFY(i4<=i);
    QVERIFY(i4>=i);
    QVERIFY(i>=i4);
    QVERIFY(i4<=i);
    QVERIFY(i2!=i4);
    QVERIFY(i2>i4);
    QVERIFY(i2>=i4);
    QVERIFY(i4!=i2);
    QVERIFY(i4i);
    QVERIFY(i4>=i);
    i4= ps.constBegin();
    QVERIFY(i==i4); // iterator COMP const_iterator
    QCOMPARE(i4+ps.count(), ps.constEnd());

    i= ps.begin();
    i2= ps.begin();
    QCOMPARE(i, i2++);
    QCOMPARE(*i2, ps[1]);
    QCOMPARE(++i, i2);
    QCOMPARE(i, i2--);
    QCOMPARE(i2, ps.begin());
    QCOMPARE(--i, i2);
    QCOMPARE(i2+=ps.count(), ps.end());
    QCOMPARE(i2-=ps.count(), ps.begin());
    QCOMPARE(i2+0, ps.begin());
    QCOMPARE(i2+ps.count(), ps.end());
    i2 += ps.count();
    i= i2-0;
    QCOMPARE(i, i2);
    i= i2-ps.count();
    QCOMPARE(i, ps.begin());
    QCOMPARE(i2-i, ps.count());

    //ps.begin end tested above

    // QhullPointSet is const-only
}//t_iterator

void QhullPointSet_test::
t_const_iterator()
{
    RboxPoints rcube("c W0 1000");
    Qhull q(rcube,"Qc");  // cube with 1000 coplanar points
    QhullFacet f= q.firstFacet();
    QhullPointSet ps= f.coplanarPoints();
    QVERIFY(ps.count()>=3);  // Sometimes no coplanar points
    QhullPointSet::ConstIterator i= ps.begin();
    QhullPointSet::const_iterator i2= ps.begin();
    QVERIFY(i==i2);
    QVERIFY(i>=i2);
    QVERIFY(i<=i2);

    // See t_iterator for const_iterator COMP iterator

    i= ps.begin();
    QVERIFY(i==i2);
    i2= ps.end();
    QVERIFY(i!=i2);
    QhullPoint p= *i; // QhullPoint is the base class for QhullPointSet::iterator
    QCOMPARE(p.dimension(), q.dimension());
    QCOMPARE(p, ps[0]);
    i2--;
    QhullPoint p2= *i2;
    QCOMPARE(p2.dimension(), q.dimension());
    QCOMPARE(p2, ps.last());
    QhullPointSet::ConstIterator i5(i2);
    QCOMPARE(*i2, *i5);


    QhullPointSet::ConstIterator i3= i+1;
    QVERIFY(i!=i3);
    QCOMPARE(i[1], *i3);

    QVERIFY(i==i);
    QVERIFY(i!=i3);
    QVERIFY(ii);
    QVERIFY(i3>=i);

    // QhullPointSet is const-only
}//t_const_iterator

void QhullPointSet_test::
t_search()
{
    RboxPoints rcube("c W0 1000");
    Qhull q(rcube,"Qc");  // cube with 1000 coplanar points
    QhullFacet f= q.firstFacet();
    QhullPointSet ps= f.coplanarPoints();
    QVERIFY(ps.count()>=3);  // Sometimes no coplanar points
    QhullPoint p= ps.first();
    QhullPoint p2= ps.last();
    QVERIFY(ps.contains(p));
    QVERIFY(ps.contains(p2));
    QVERIFY(p!=p2);
    QhullPoint p3= ps[2];
    QVERIFY(ps.contains(p3));
    QVERIFY(p!=p3);
    QCOMPARE(ps.indexOf(p), 0);
    QCOMPARE(ps.indexOf(p2), ps.count()-1);
    QCOMPARE(ps.indexOf(p3), 2);
    QhullPoint p4(q);
    QCOMPARE(ps.indexOf(p4), -1);
    QCOMPARE(ps.lastIndexOf(p), 0);
    QCOMPARE(ps.lastIndexOf(p2), ps.count()-1);
    QCOMPARE(ps.lastIndexOf(p3), 2);
    QCOMPARE(ps.lastIndexOf(p4), -1);
}//t_search

void QhullPointSet_test::
t_foreach()
{
    RboxPoints rcube("c W0 1000");
    Qhull q(rcube,"Qc");  // cube with 1000 coplanar points
    QhullFacet f= q.firstFacet();
    QhullPointSet ps= f.coplanarPoints();
    QVERIFY(ps.count()>=3);  // Sometimes no coplanar points
    QhullPoint p2= ps.at(1);

    bool isP2= false;
    int count= 0;
    foreach(QhullPoint p, f.coplanarPoints()){  // Qt only
        ++count;
        if(p==p2){
            isP2= true;
            QCOMPARE(count, 2);
        }
    }
    QVERIFY(isP2);
    QCOMPARE(count, ps.count());

    isP2= false;
    count= 0;
    for(QhullPoint p : f.coplanarPoints()){
        ++count;
        if(p==p2){
            isP2= true;
            QCOMPARE(count, 2);
        }
    }
    QVERIFY(isP2);
    QCOMPARE(count, ps.count());
}//t_foreach

void QhullPointSet_test::
t_pointset_iterator()
{
    RboxPoints rcube("c W0 1000");
    Qhull q(rcube,"Qc");  // cube with 1000 coplanar points
    QhullFacet f= q.firstFacet();
    QhullPointSet ps2= f.outsidePoints();
    QVERIFY(ps2.count()==0); // No outside points after constructing the convex hull
    QhullPointSetIterator i2= ps2;
    QCOMPARE(i2.countRemaining(), 0);
    QVERIFY(!i2.hasNext());
    QVERIFY(!i2.hasPrevious());
    i2.toBack();
    QVERIFY(!i2.hasNext());
    QVERIFY(!i2.hasPrevious());

    QhullPointSet ps= f.coplanarPoints();
    QVERIFY(ps.count()>=3);  // Sometimes no coplanar points
    QhullPointSetIterator i(ps);
    i2= ps;
    QCOMPARE(i2.countRemaining(), ps.count());
    QVERIFY(i2.hasNext());
    QVERIFY(!i2.hasPrevious());
    QVERIFY(i.hasNext());
    QVERIFY(!i.hasPrevious());
    i2.toBack();
    QCOMPARE(i2.countRemaining(), 0);
    i.toFront();
    QCOMPARE(i.countRemaining(), ps.count());
    QCOMPARE(i2.countRemaining(), 0);
    QVERIFY(!i2.hasNext());
    QVERIFY(i2.hasPrevious());
    QVERIFY(i.hasNext());
    QVERIFY(!i.hasPrevious());

    QhullPoint p= ps[0];
    QhullPoint p2(ps[0]);
    QCOMPARE(p, p2);
    QVERIFY(p==p2);
    QhullPoint p3(ps.last());
 // p2[0]= 0.0;
    QVERIFY(p==p2);
    QCOMPARE(i2.peekPrevious(), p3);
    QCOMPARE(i2.previous(), p3);
    QCOMPARE(i2.previous(), ps[ps.count()-2]);
    QVERIFY(i2.hasPrevious());
    QCOMPARE(i.peekNext(), p);
    // i.peekNext()= 1.0; // compiler error
    QCOMPARE(i.next(), p);
    QCOMPARE(i.countRemaining(), ps.count()-1);
    QhullPoint p4= i.peekNext();
    QVERIFY(p4!=p3);
    QCOMPARE(i.next(), p4);
    QVERIFY(i.hasNext());
    i.toFront();
    QCOMPARE(i.next(), p);
}//t_pointset_iterator

void QhullPointSet_test::
t_java_iterator()
{
    RboxPoints rcube("c W0 1000");
    Qhull q(rcube,"Qc");  // cube with 1000 coplanar points
    QhullFacet f= q.firstFacet();
    QhullPointSet ps= f.coplanarPoints();
    QVERIFY(ps.count()>=3);  // Sometimes no coplanar points
    QhullPoint p2= ps.at(1);

    bool isP2= false;
    int count= 0;
    QhullPointSetIterator i(f.coplanarPoints());
    while(i.hasNext()){
        QhullPoint p= i.next();
        QCOMPARE(i.peekPrevious(), p);
        ++count;
        if(p==p2){
            isP2= true;
            QCOMPARE(count, 2);
        }
    }
    QVERIFY(isP2);
    QCOMPARE(count, ps.count());
}//t_java_iterator

void QhullPointSet_test::
t_io()
{
    ostringstream os;
    RboxPoints rcube("c W0 120");
    Qhull q(rcube,"Qc");  // cube with 100 coplanar points
    QhullFacet f= q.firstFacet();
    QhullPointSet ps= f.coplanarPoints();
    QVERIFY(ps.count()>=3);  // Sometimes no coplanar points
    os << "QhullPointSet from coplanarPoints\n" << ps << endl;
    os << ps.print("\nWith message\n");
    os << ps.printIdentifiers("\nCoplanar points: ");
    os << "\nAs a point set:\n";
    os << ps;
    cout << os.str();
    QString s= QString::fromStdString(os.str());
    QCOMPARE(s.count(" 0.5\n"), 3*ps.count());
    QCOMPARE(s.count("p"), ps.count()+4);
}//t_io

}//orgQhull

#include "moc/QhullPointSet_test.moc"
qhull-2020.2/src/qhulltest/QhullPoints_test.cpp0000644060175106010010000003776413706643555020066 0ustar  bbarber/****************************************************************************
**
** Copyright (p) 2009-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/qhulltest/QhullPoints_test.cpp#3 $$Change: 3001 $
** $DateTime: 2020/07/24 20:43:28 $$Author: bbarber $
**
****************************************************************************/

//pre-compiled header
#include 
#include "qhulltest/RoadTest.h" // QT_VERSION

#include "libqhullcpp/QhullPoints.h"
#include "libqhullcpp/RboxPoints.h"
#include "libqhullcpp/Qhull.h"

using std::cout;
using std::endl;
using std::ostringstream;

namespace orgQhull {

class QhullPoints_test : public RoadTest
{
    Q_OBJECT

#//!\name Test slots
private slots:
    void cleanup();
    void t_construct_q();
    void t_construct_qh();
    void t_convert();
    void t_getset();
    void t_element();
    void t_iterator();
    void t_const_iterator();
    void t_foreach();
    void t_search();
    void t_points_iterator();
    void t_java_iterator();
    void t_io();
};//QhullPoints_test

void
add_QhullPoints_test()
{
    new QhullPoints_test();  // RoadTest::s_testcases
}

//Executed after each testcase
void QhullPoints_test::
cleanup()
{
    RoadTest::cleanup();
}

void QhullPoints_test::
t_construct_q()
{
    Qhull q;
    QhullPoints ps(q);
    QCOMPARE(ps.dimension(), 0);
    QVERIFY(ps.isEmpty());
    QCOMPARE(ps.count(), 0);
    QCOMPARE(ps.size(), 0u);
    QCOMPARE(ps.coordinateCount(), 0);
    coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
    QhullPoints ps2(q);
    ps2.defineAs(2, 6, c);
    QCOMPARE(ps2.dimension(), 2);
    QVERIFY(!ps2.isEmpty());
    QCOMPARE(ps2.count(), 3);
    QCOMPARE(ps2.size(), 3u);
    QCOMPARE(ps2.coordinates(), c);
    QhullPoints ps3(q, 2, 6, c);
    QCOMPARE(ps3.dimension(), 2);
    QVERIFY(!ps3.isEmpty());
    QCOMPARE(ps3.coordinates(), ps2.coordinates());
    QVERIFY(ps3==ps2);
    QVERIFY(ps3!=ps);
    QhullPoints ps4= ps3;
    QVERIFY(ps4==ps3);
    // ps4= ps3; //compiler error
    QhullPoints ps5(ps4);
    QVERIFY(ps5==ps4);
    QVERIFY(!(ps5!=ps4));
    coordT c2[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
    QhullPoints ps6(q, 2, 6, c2);
    QVERIFY(ps6==ps2);

    RboxPoints rbox("c D2");
    Qhull q2(rbox, "");
    QhullPoints ps8(q2);
    QCOMPARE(ps8.dimension(), 2);
    QCOMPARE(ps8.count(), 0);
    QCOMPARE(ps8.size(), 0u);
    QCOMPARE(ps8.coordinateCount(), 0);
    coordT c3[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
    QhullPoints ps9(q2, 6, c3);
    QCOMPARE(ps9.dimension(), 2);
    QCOMPARE(ps9.coordinateCount(), 6);
    QCOMPARE(ps9.count(), 3);
    QCOMPARE(ps9.coordinates(), c3);
    QCOMPARE(ps9, ps2);  // DISTround
    c3[1]= 1.0+1e-17;
    QCOMPARE(ps9, ps2);  // DISTround
    c3[1]= 1.0+1e-15;
    QVERIFY(ps9!=ps2);  // DISTround

    ps9.defineAs(6, c2);
    QCOMPARE(ps9.dimension(), 2);
    QCOMPARE(ps9.coordinateCount(), 6);
    QCOMPARE(ps9.count(), 3);
    QCOMPARE(ps9.coordinates(), c2);
}//t_construct_q

void QhullPoints_test::
t_construct_qh()
{
    Qhull q;
    QhullQh *qh= q.qh();
    QhullPoints ps(qh);
    QCOMPARE(ps.dimension(), 0);
    QVERIFY(ps.isEmpty());
    QCOMPARE(ps.count(), 0);
    QCOMPARE(ps.size(), 0u);
    QCOMPARE(ps.coordinateCount(), 0);
    coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
    QhullPoints ps2(qh);
    ps2.defineAs(2, 6, c);
    QCOMPARE(ps2.dimension(), 2);
    QVERIFY(!ps2.isEmpty());
    QCOMPARE(ps2.count(), 3);
    QCOMPARE(ps2.size(), 3u);
    QCOMPARE(ps2.coordinates(), c);
    QhullPoints ps3(qh, 2, 6, c);
    QCOMPARE(ps3.dimension(), 2);
    QVERIFY(!ps3.isEmpty());
    QCOMPARE(ps3.coordinates(), ps2.coordinates());
    QVERIFY(ps3==ps2);
    QVERIFY(ps3!=ps);
    QhullPoints ps4= ps3;
    QVERIFY(ps4==ps3);
    // ps4= ps3; //compiler error
    QhullPoints ps5(ps4);
    QVERIFY(ps5==ps4);
    QVERIFY(!(ps5!=ps4));
    coordT c2[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
    QhullPoints ps6(qh, 2, 6, c2);
    QVERIFY(ps6==ps2);

    RboxPoints rbox("c D2");
    Qhull q2(rbox, "");
    QhullPoints ps8(q2.qh());
    QCOMPARE(ps8.dimension(), 2);
    QCOMPARE(ps8.count(), 0);
    QCOMPARE(ps8.size(), 0u);
    QCOMPARE(ps8.coordinateCount(), 0);
    coordT c3[]= {10.0, 11.0, 12.0, 13.0, 14.0, 15.0};
    QhullPoints ps9(q2.qh(), 6, c3);
    QCOMPARE(ps9.dimension(), 2);
    QCOMPARE(ps9.coordinateCount(), 6);
    QCOMPARE(ps9.count(), 3);
    QCOMPARE(ps9.coordinates(), c3);
    ps9.defineAs(6, c2);
    QCOMPARE(ps9.dimension(), 2);
    QCOMPARE(ps9.coordinateCount(), 6);
    QCOMPARE(ps9.count(), 3);
    QCOMPARE(ps9.coordinates(), c2);
}//t_construct_qh

void QhullPoints_test::
t_convert()
{
    Qhull q;
    //defineAs tested above
    coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
    QhullPoints ps(q, 3, 6, c);
    QCOMPARE(ps.dimension(), 3);
    QCOMPARE(ps.size(), 2u);
    const coordT *c2= ps.constData();
    QCOMPARE(c, c2);
    const coordT *c3= ps.data();
    QCOMPARE(c, c3);
    coordT *c4= ps.data();
    QCOMPARE(c, c4);
    std::vector vs= ps.toStdVector();
    QCOMPARE(vs.size(), 2u);
    QhullPoint p= vs[1];
    QCOMPARE(p[2], 5.0);
    QList qs= ps.toQList();
    QCOMPARE(qs.size(), 2);
    QhullPoint p2= qs[1];
    QCOMPARE(p2[2], 5.0);
}//t_convert

void QhullPoints_test::
t_getset()
{
    Qhull q;
    //See t_construct for coordinates, count, defineAs, dimension, isempty, ==, !=, size
    coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
    QhullPoints ps(q, 3, 6, c);
    QhullPoints ps2(q, 3, 6, c);
    QCOMPARE(ps2.dimension(), 3);
    QCOMPARE(ps2.coordinates(), c);
    QCOMPARE(ps2.count(), 2);
    QCOMPARE(ps2.coordinateCount(), 6);
    coordT c2[]= {-1.0, -2.0, -3.0, -4.0, -5.0, -6.0};
    ps2.defineAs(6, c2);
    QCOMPARE(ps2.coordinates(), c2);
    QCOMPARE(ps2.count(), 2);
    QCOMPARE(ps2.size(), 2u);
    QCOMPARE(ps2.dimension(), 3);
    QVERIFY(!ps2.isEmpty());
    QVERIFY(ps!=ps2);
    // ps2= ps; // assignment not available, compiler error
    ps2.defineAs(ps);
    QVERIFY(ps==ps2);
    ps2.setDimension(2);
    QCOMPARE(ps2.dimension(), 2);
    QCOMPARE(ps2.coordinates(), c);
    QVERIFY(!ps2.isEmpty());
    QCOMPARE(ps2.count(), 3);
    QCOMPARE(ps2.size(), 3u);
    QVERIFY(ps!=ps2);
    QhullPoints ps3(ps2);
    ps3.setDimension(3);
    ps3.defineAs(5, c2);
    QCOMPARE(ps3.count(), 1);
    QCOMPARE(ps3.extraCoordinatesCount(), 2);
    QCOMPARE(ps3.extraCoordinates()[0], -4.0);
    QVERIFY(ps3.includesCoordinates(ps3.data()));
    QVERIFY(ps3.includesCoordinates(ps3.data()+ps3.count()-1));
    QVERIFY(!ps3.includesCoordinates(ps3.data()-1));
    QVERIFY(!ps3.includesCoordinates(ps3.data()+ps3.coordinateCount()));
}//t_getset


void QhullPoints_test::
t_element()
{
    Qhull q;
    coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
    QhullPoints ps(q, 2, 6, c);
    QCOMPARE(ps.count(), 3);
    QhullPoint p(q, 2, c);
    QCOMPARE(ps[0], p);
    QCOMPARE(ps.at(1), ps[1]);
    QCOMPARE(ps.first(), p);
    QCOMPARE(ps.front(), ps.first());
    QCOMPARE(ps.last(), ps.at(2));
    QCOMPARE(ps.back(), ps.last());
    QhullPoints ps2= ps.mid(2);
    QCOMPARE(ps2.count(), 1);
    QhullPoints ps3= ps.mid(3);
    QVERIFY(ps3.isEmpty());
    QhullPoints ps4= ps.mid(10);
    QVERIFY(ps4.isEmpty());
    QhullPoints ps5= ps.mid(-1);
    QVERIFY(ps5.isEmpty());
    QhullPoints ps6= ps.mid(1, 1);
    QCOMPARE(ps6.count(), 1);
    QCOMPARE(ps6[0], ps[1]);
    QhullPoints ps7= ps.mid(1, 10);
    QCOMPARE(ps7.count(), 2);
    QCOMPARE(ps7[1], ps[2]);
    QhullPoint p8(q);
    QCOMPARE(ps.value(2), ps[2]);
    QCOMPARE(ps.value(-1), p8);
    QCOMPARE(ps.value(3), p8);
    QCOMPARE(ps.value(3, p), p);
    QVERIFY(ps.value(1, p)!=p);
    foreach(QhullPoint p9, ps){  // Qt only
        QCOMPARE(p9.dimension(), 2);
        QVERIFY(p9[0]==0.0 || p9[0]==2.0 || p9[0]==4.0);
    }
}//t_element

void QhullPoints_test::
t_iterator()
{
    Qhull q;
    coordT c[]= {0.0, 1.0, 2.0};
    QhullPoints ps(q, 1, 3, c);
    QCOMPARE(ps.dimension(), 1);
    QhullPoints::Iterator i(ps);
    QhullPoints::iterator i2= ps.begin();
    QVERIFY(i==i2);
    QVERIFY(i>=i2);
    QVERIFY(i<=i2);
    i= ps.begin();
    QVERIFY(i==i2);
    i2= ps.end();
    QVERIFY(i!=i2);
    QhullPoint p(i); // QhullPoint is the base class for QhullPoints::iterator
    QCOMPARE(p.dimension(), ps.dimension());
    QCOMPARE(p.coordinates(), ps.coordinates());
    i2--;
    QhullPoint p2= *i2;
    QCOMPARE(p[0], 0.0);
    QCOMPARE(p2[0], 2.0);
    QhullPoints::Iterator i5(i2);
    QCOMPARE(*i2, *i5);
    coordT c3[]= {0.0, -1.0, -2.0};
    QhullPoints::Iterator i3(q, 1, c3);
    QVERIFY(i!=i3);
    QCOMPARE(*i, *i3);

    (i3= i)++;
    QCOMPARE((*i3)[0], 1.0);
    QCOMPARE(i3->dimension(), 1);
    QCOMPARE(i3[0][0], 1.0);
    QCOMPARE(i3[0], ps[1]);

    QVERIFY(i==i);
    QVERIFY(i!=i2);
    QVERIFY(ii);
    QVERIFY(i2>=i);

    QhullPoints::ConstIterator i4(q, 1, c);
    QVERIFY(i==i4); // iterator COMP const_iterator
    QVERIFY(i<=i4);
    QVERIFY(i>=i4);
    QVERIFY(i4==i); // const_iterator COMP iterator
    QVERIFY(i4<=i);
    QVERIFY(i4>=i);
    QVERIFY(i>=i4);
    QVERIFY(i4<=i);
    QVERIFY(i2!=i4);
    QVERIFY(i2>i4);
    QVERIFY(i2>=i4);
    QVERIFY(i4!=i2);
    QVERIFY(i4i);
    QVERIFY(i4>=i);

    i= ps.begin();
    i2= ps.begin();
    QCOMPARE(i, i2++);
    QCOMPARE(*i2, ps[1]);
    QCOMPARE(++i, i2);
    QCOMPARE(i, i2--);
    QCOMPARE(i2, ps.begin());
    QCOMPARE(--i, i2);
    QCOMPARE(i2+=3, ps.end());
    QCOMPARE(i2-=3, ps.begin());
    QCOMPARE(i2+0, ps.begin());
    QCOMPARE(i2+3, ps.end());
    i2 += 3;
    i= i2-0;
    QCOMPARE(i, i2);
    i= i2-3;
    QCOMPARE(i, ps.begin());
    QCOMPARE(i2-i, 3);

    //ps.begin end tested above

    // QhullPoints is const-only
}//t_iterator

void QhullPoints_test::
t_const_iterator()
{
    Qhull q;
    coordT c[]= {0.0, 1.0, 2.0};
    const QhullPoints ps(q, 1, 3, c);
    QhullPoints::ConstIterator i(ps);
    QhullPoints::const_iterator i2= ps.begin();
    QVERIFY(i==i2);
    QVERIFY(i>=i2);
    QVERIFY(i<=i2);
    i= ps.begin();
    QVERIFY(i==i2);
    i2= ps.end();
    QVERIFY(i!=i2);
    QhullPoint p(i);
    QCOMPARE(p.dimension(), ps.dimension());
    QCOMPARE(p.coordinates(), ps.coordinates());
    i2--;
    QhullPoint p2= *i2;
    QCOMPARE(p[0], 0.0);
    QCOMPARE(p2[0], 2.0);
    QhullPoints::ConstIterator i5(i2);
    QCOMPARE(*i2, *i5);
    coordT c3[]= {0.0, -1.0, -2.0};
    QhullPoints::ConstIterator i3(q, 1, c3);
    QVERIFY(i!=i3);
    QCOMPARE(*i, *i3);

    (i3= i)++;
    QCOMPARE((*i3)[0], 1.0);
    QCOMPARE(i3->dimension(), 1);
    QCOMPARE(i3[0][0], 1.0);
    QCOMPARE(i3[0][0], 1.0);
    QCOMPARE(i3[0], ps[1]);

    QVERIFY(i==i);
    QVERIFY(i!=i2);
    QVERIFY(ii);
    QVERIFY(i2>=i);

    // See t_iterator for const_iterator COMP iterator

    i= ps.begin();
    i2= ps.constBegin();
    QCOMPARE(i, i2++);
    QCOMPARE(*i2, ps[1]);
    QCOMPARE(++i, i2);
    QCOMPARE(i, i2--);
    QCOMPARE(i2, ps.constBegin());
    QCOMPARE(--i, i2);
    QCOMPARE(i2+=3, ps.constEnd());
    QCOMPARE(i2-=3, ps.constBegin());
    QCOMPARE(i2+0, ps.constBegin());
    QCOMPARE(i2+3, ps.constEnd());
    i2 += 3;
    i= i2-0;
    QCOMPARE(i, i2);
    i= i2-3;
    QCOMPARE(i, ps.constBegin());
    QCOMPARE(i2-i, 3);

    // QhullPoints is const-only
}//t_const_iterator

void QhullPoints_test::
t_foreach()
{
    RboxPoints rcube("c");
    Qhull q(rcube, "QR0");  // rotated unit cube
    QhullPoints ps= q.points();
    QhullPoint p2= ps.at(1);

    bool isP2= false;
    int count= 0;
    foreach(QhullPoint p, q.points()) { // Qt only
        ++count;
        if(p==p2){
            isP2= true;
        }
    }
    QVERIFY(isP2);
    QCOMPARE(count, ps.count());

    isP2= false;
    count= 0;
    for(QhullPoint p : q.points()) {
        ++count;
        if(p==p2){
            isP2= true;
        }
    }
    QVERIFY(isP2);
    QCOMPARE(count, ps.count());
}//t_foreach

void QhullPoints_test::
t_search()
{
    Qhull q;
    coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 0, 1};
    QhullPoints ps(q, 2, 8, c); //2-d array of 4 points
    QhullPoint p= ps.first();
    QhullPoint p2= ps.last();
    QVERIFY(ps.contains(p));
    QVERIFY(ps.contains(p2));
    QVERIFY(p==p2);
    QhullPoint p5= ps[2];
    QVERIFY(p!=p5);
    QVERIFY(ps.contains(p5));
    coordT c2[]= {0.0, 1.0, 2.0, 3.0};
    QhullPoint p3(q, 2, c2); //2-d point
    QVERIFY(ps.contains(p3));
    QhullPoint p4(q, 3, c2); //3-d point
    QVERIFY(!ps.contains(p4));
    p4.defineAs(2, c); //2-d point
    QVERIFY(ps.contains(p4));
    p4.defineAs(2, c+1); //2-d point
    QVERIFY(!ps.contains(p4));
    QhullPoint p6(q, 2, c2+2); //2-d point
    QCOMPARE(ps.count(p), 2);
    QCOMPARE(ps.count(p2), 2);
    QCOMPARE(ps.count(p3), 2);
    QCOMPARE(ps.count(p4), 0);
    QCOMPARE(ps.count(p6), 1);
    QCOMPARE(ps.indexOf(&ps[0][0]), 0);
    //QCOMPARE(ps.indexOf(ps.end()), -1); //ps.end() is a QhullPoint which may match
    QCOMPARE(ps.indexOf(0), -1);
    QCOMPARE(ps.indexOf(&ps[3][0]), 3);
    QCOMPARE(ps.indexOf(&ps[3][1], QhullError::NOthrow), 3);
    QCOMPARE(ps.indexOf(ps.data()+ps.coordinateCount(), QhullError::NOthrow), -1);
    QCOMPARE(ps.indexOf(p), 0);
    QCOMPARE(ps.indexOf(p2), 0);
    QCOMPARE(ps.indexOf(p3), 0);
    QCOMPARE(ps.indexOf(p4), -1);
    QCOMPARE(ps.indexOf(p5), 2);
    QCOMPARE(ps.indexOf(p6), 1);
    QCOMPARE(ps.lastIndexOf(p), 3);
    QCOMPARE(ps.lastIndexOf(p4), -1);
    QCOMPARE(ps.lastIndexOf(p6), 1);
    QhullPoints ps3(q);
    QCOMPARE(ps3.indexOf(ps3.data()), -1);
    QCOMPARE(ps3.indexOf(ps3.data()+1, QhullError::NOthrow), -1);
    QCOMPARE(ps3.indexOf(p), -1);
    QCOMPARE(ps3.lastIndexOf(p), -1);
    QhullPoints ps4(q, 2, 0, c);
    QCOMPARE(ps4.indexOf(p), -1);
    QCOMPARE(ps4.lastIndexOf(p), -1);
}//t_search

void QhullPoints_test::
t_points_iterator()
{
    Qhull q;
    coordT c2[]= {0.0};
    QhullPoints ps2(q, 0, 0, c2); // 0-dimensional
    QhullPointsIterator i2= ps2;
    QVERIFY(!i2.hasNext());
    QVERIFY(!i2.hasPrevious());
    i2.toBack();
    QVERIFY(!i2.hasNext());
    QVERIFY(!i2.hasPrevious());

    coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
    QhullPoints ps(q, 3, 6, c); // 3-dimensional
    QhullPointsIterator i(ps);
    i2= ps;
    QVERIFY(i2.hasNext());
    QVERIFY(!i2.hasPrevious());
    QVERIFY(i.hasNext());
    QVERIFY(!i.hasPrevious());
    i2.toBack();
    i.toFront();
    QVERIFY(!i2.hasNext());
    QVERIFY(i2.hasPrevious());
    QVERIFY(i.hasNext());
    QVERIFY(!i.hasPrevious());

    QhullPoint p= ps[0];
    QhullPoint p2(ps[0]);
    QCOMPARE(p, p2);
    QVERIFY(p==p2);
    QhullPoint p3(ps[1]);
 // p2[0]= 0.0;
    QVERIFY(p==p2);
    QCOMPARE(i2.peekPrevious(), p3);
    QCOMPARE(i2.previous(), p3);
    QCOMPARE(i2.previous(), p);
    QVERIFY(!i2.hasPrevious());
    QCOMPARE(i.peekNext(), p);
    // i.peekNext()= 1.0; // compiler error
    QCOMPARE(i.next(), p);
    QCOMPARE(i.peekNext(), p3);
    QCOMPARE(i.next(), p3);
    QVERIFY(!i.hasNext());
    i.toFront();
    QCOMPARE(i.next(), p);
}//t_points_iterator

void QhullPoints_test::
t_java_iterator()
{
    RboxPoints rcube("c");
    Qhull q(rcube, "QR0");  // rotated unit cube
    QhullPoints ps= q.points();
    QhullPoint p2= ps.at(1);

    bool isP2= false;
    int count= 0;
    QhullPointsIterator i(q.points());
    while(i.hasNext()){
        QhullPoint p= i.next();
        QCOMPARE(i.peekPrevious(), p);
        ++count;
        if(p==p2){
            isP2= true;
        }
    }
    QVERIFY(isP2);
    QCOMPARE(count, ps.count());
}//t_java_iterator

void QhullPoints_test::
t_io()
{
    Qhull q;
    QhullPoints ps(q);
    ostringstream os;
    os << "Empty QhullPoints\n" << ps << endl;
    coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
    QhullPoints ps2(q, 3, 6, c); // 3-dimensional explicit
    os << "QhullPoints from c[]\n" << ps2 << endl;

    RboxPoints rcube("c");
    Qhull q2(rcube,"Qt QR0");  // triangulation of rotated unit cube
    QhullPoints ps3= q2.points();
    os << "QhullPoints\n" << ps3;
    os << ps3.print("message\n");
    os << ps3.printWithIdentifier("w/ identifiers\n");
    cout << os.str();
    QString s= QString::fromStdString(os.str());
    QCOMPARE(s.count("p"), 8+1);
}//t_io

}//orgQhull

#include "moc/QhullPoints_test.moc"
qhull-2020.2/src/qhulltest/QhullPoint_test.cpp0000644060175106010010000003070413706714004017652 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/qhulltest/QhullPoint_test.cpp#5 $$Change: 3006 $
** $DateTime: 2020/07/29 18:28:16 $$Author: bbarber $
**
****************************************************************************/

//pre-compiled headers
#include 
#include "RoadTest.h" // QT_VERSION

#include "libqhullcpp/QhullPoint.h"
#include "libqhullcpp/Coordinates.h"
#include "libqhullcpp/RboxPoints.h"
#include "libqhullcpp/QhullError.h"
#include "libqhullcpp/QhullFacet.h"
#include "libqhullcpp/QhullPoint.h"
#include "libqhullcpp/Qhull.h"

#include 

using std::cout;
using std::endl;
using std::ostringstream;
using std::ostream;
using std::string;

namespace orgQhull {

class QhullPoint_test : public RoadTest
{
    Q_OBJECT

#//!\name Test slots
private slots:
    void cleanup();
    void t_construct();
    void t_convert();
    void t_readonly();
    void t_define();
    void t_operator();
    void t_iterator();
    void t_const_iterator();
    void t_foreach();
    void t_qhullpoint_iterator();
    void t_java_iterator();
    void t_method();
    void t_io();
};//QhullPoint_test

void
add_QhullPoint_test()
{
    new QhullPoint_test();  // RoadTest::s_testcases
}

//Executed after each test
void QhullPoint_test::
cleanup()
{
    RoadTest::cleanup();
}

void QhullPoint_test::
t_construct()
{
    QhullPoint p12;
    QVERIFY(!p12.isValid());
    QCOMPARE(p12.coordinates(), (coordT *)0);
    QCOMPARE(p12.dimension(), 0);
    QCOMPARE(p12.qh(), (QhullQh *)0);
    QCOMPARE(p12.id(), -3);
    QCOMPARE(p12.begin(), p12.end());
    QCOMPARE(p12.constBegin(), p12.constEnd());

    RboxPoints rcube("c");
    Qhull q(rcube, "Qt QR0");  // triangulation of rotated unit cube
    QhullPoint p(q);
    QVERIFY(!p.isValid());
    QCOMPARE(p.dimension(),3);
    QCOMPARE(p.coordinates(),static_cast(0));
    QhullPoint p7(q.qh());
    QCOMPARE(p, p7);

    // copy constructor and copy assignment
    QhullVertex v2(q.beginVertex());
    QhullPoint p2(v2.point());
    QVERIFY(p2.isValid());
    QCOMPARE(p2.dimension(),3);
    QVERIFY(p2!=p12);
    p= p2;
    QCOMPARE(p, p2);

    QhullPoint p3(q, p2.dimension(), p2.coordinates());
    QCOMPARE(p3, p2);
    QhullPoint p8(q, p2.coordinates()); // Qhull defines dimension
    QCOMPARE(p8, p2);
    QhullPoint p9(q.qh(), p2.dimension(), p2.coordinates());
    QCOMPARE(p9, p2);
    QhullPoint p10(q.qh(), p2.coordinates()); // Qhull defines dimension
    QCOMPARE(p10, p2);

    Coordinates c;
    c << 0.0 << 0.0 << 0.0;
    QhullPoint p6(q, c);
    QCOMPARE(p6, q.origin());
    QhullPoint p11(q.qh(), c);
    QCOMPARE(p11, q.origin());

    QhullPoint p5= p2; // copy constructor
    QVERIFY(p5==p2);
}//t_construct

void QhullPoint_test::
t_convert()
{
    RboxPoints rcube("c");
    Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
    QhullVertex v= q.firstVertex();
    QhullPoint p= v.point();
    std::vector vs= p.toStdVector();
    QCOMPARE(vs.size(), 3u);
    for(int k=3; k--; ){
        QCOMPARE(vs[k], p[k]);
    }
    QList qs= p.toQList();
    QCOMPARE(qs.size(), 3);
    for(int k=3; k--; ){
        QCOMPARE(qs[k], p[k]);
    }
}//t_convert

void QhullPoint_test::
t_readonly()
{
    RboxPoints rcube("c");
    {
        Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
        QhullVertexList vs= q.vertexList();
        cout << "Point ids in 'rbox c'\n";
        QhullVertexListIterator i(vs);
        while(i.hasNext()){
            QhullPoint p= i.next().point();
            int id= p.id();
            cout << "p" << id << endl;
            QVERIFY(p.isValid());
            QCOMPARE(p.dimension(),3);
            QCOMPARE(id, p.id());
            QVERIFY(p.id()>=0 && p.id()<9);
            const coordT *c= p.coordinates();
            coordT *c2= p.coordinates();
            QCOMPARE(c, c2);
            QCOMPARE(p.dimension(), 3);
            QCOMPARE(q.qh(), p.qh());
        }
        QhullPoint p2= vs.first().point();
        QhullPoint p3= vs.last().point();
        QVERIFY(p2!=p3);
        QVERIFY(p3.coordinates()!=p2.coordinates());
    }
}//t_readonly

void QhullPoint_test::
t_define()
{
    RboxPoints rcube("c");
    {
        Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
        QhullVertexList vs= q.vertexList();
        QhullPoint p= vs.first().point();
        QhullPoint p2= p;
        QVERIFY(p==p2);
        QhullPoint p3= vs.last().point();
        QVERIFY(p2!=p3);
        int idx= (p3.coordinates()-p2.coordinates())/p2.dimension();
        QVERIFY(idx>-8 && idx<8);
        p2.advancePoint(idx);
        QVERIFY(p2==p3);
        p2.advancePoint(-idx);
        QVERIFY(p2==p);
        p2.advancePoint(0);
        QVERIFY(p2==p);

        QhullPoint p4= p3;
        QVERIFY(p4==p3);
        p4.defineAs(p2);
        QVERIFY(p2==p4);
        QhullPoint p5= p3;
        p5.defineAs(p2.dimension(), p2.coordinates());
        QVERIFY(p2==p5);
        QhullPoint p6= p3;
        p6.setCoordinates(p2.coordinates());
        QCOMPARE(p2.coordinates(), p6.coordinates());
        QVERIFY(p2==p6);
        p6.setDimension(2);
        QCOMPARE(p6.dimension(), 2);
        QVERIFY(p2!=p6);
    }
}//t_define

void QhullPoint_test::
t_operator()
{
    RboxPoints rcube("c");
    Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
    const QhullPoint p= q.firstVertex().point();
    //operator== and operator!= tested elsewhere
    const coordT *c= p.coordinates();
    for(int k=p.dimension(); k--; ){
        QCOMPARE(c[k], p[k]);
    }
    //p[0]= 10.0; // compiler error, const
    QhullPoint p2= q.firstVertex().point();
    p2[0]= 10.0;  // Overwrites point coordinate
    QCOMPARE(p2[0], 10.0);
}//t_operator

void QhullPoint_test::
t_iterator()
{
    RboxPoints rcube("c");
    {
        Qhull q(rcube,"QR0");  // rotated unit cube
        QhullPoint p2(q);
        QCOMPARE(p2.begin(), p2.end());

        QhullPoint p= q.firstVertex().point();
        QhullPoint::Iterator i= p.begin();
        QhullPoint::iterator i2= p.begin();
        QVERIFY(i==i2);
        QVERIFY(i>=i2);
        QVERIFY(i<=i2);
        i= p.begin();
        QVERIFY(i==i2);
        i2= p.end();
        QVERIFY(i!=i2);
        double d3= *i;
        i2--;
        double d2= *i2;
        QCOMPARE(d3, p[0]);
        QCOMPARE(d2, p[2]);
        QhullPoint::Iterator i3(i2);
        QCOMPARE(*i2, *i3);

        (i3= i)++;
        QCOMPARE((*i3), p[1]);
        QVERIFY(i==i);
        QVERIFY(i!=i2);
        QVERIFY(ii);
        QVERIFY(i2>=i);

        QhullPoint::ConstIterator i4= p.begin();
        QVERIFY(i==i4); // iterator COMP const_iterator
        QVERIFY(i<=i4);
        QVERIFY(i>=i4);
        QVERIFY(i4==i); // const_iterator COMP iterator
        QVERIFY(i4<=i);
        QVERIFY(i4>=i);
        QVERIFY(i>=i4);
        QVERIFY(i4<=i);
        QVERIFY(i2!=i4);
        QVERIFY(i2>i4);
        QVERIFY(i2>=i4);
        QVERIFY(i4!=i2);
        QVERIFY(i4i);
        QVERIFY(i4>=i);

        i= p.begin();
        i2= p.begin();
        QCOMPARE(i, i2++);
        QCOMPARE(*i2, p[1]);
        QCOMPARE(++i, i2);
        QCOMPARE(i, i2--);
        QCOMPARE(i2, p.begin());
        QCOMPARE(--i, i2);
        QCOMPARE(i2 += 3, p.end());
        QCOMPARE(i2 -= 3, p.begin());
        QCOMPARE(i2+0, p.begin());
        QCOMPARE(i2+3, p.end());
        i2 += 3;
        i= i2-0;
        QCOMPARE(i, i2);
        i= i2-3;
        QCOMPARE(i, p.begin());
        QCOMPARE(i2-i, 3);

        //p.begin end tested above

        // QhullPoint is const-only
    }
}//t_iterator

void QhullPoint_test::
t_const_iterator()
{
    RboxPoints rcube("c");
    {
        Qhull q(rcube,"QR0");  // rotated unit cube
        QhullPoint p= q.firstVertex().point();
        QhullPoint::ConstIterator i= p.begin();
        QhullPoint::const_iterator i2= p.begin();
        QVERIFY(i==i2);
        QVERIFY(i>=i2);
        QVERIFY(i<=i2);
        i= p.begin();
        QVERIFY(i==i2);
        i2= p.end();
        QVERIFY(i!=i2);
        double d3= *i;
        i2--;
        double d2= *i2;
        QCOMPARE(d3, p[0]);
        QCOMPARE(d2, p[2]);
        QhullPoint::ConstIterator i3(i2);
        QCOMPARE(*i2, *i3);

        (i3= i)++;
        QCOMPARE((*i3), p[1]);
        QVERIFY(i==i);
        QVERIFY(i!=i2);
        QVERIFY(ii);
        QVERIFY(i2>=i);

        // See t_iterator for const_iterator COMP iterator

        i= p.begin();
        i2= p.constBegin();
        QCOMPARE(i, i2++);
        QCOMPARE(*i2, p[1]);
        QCOMPARE(++i, i2);
        QCOMPARE(i, i2--);
        QCOMPARE(i2, p.constBegin());
        QCOMPARE(--i, i2);
        QCOMPARE(i2+=3, p.constEnd());
        QCOMPARE(i2-=3, p.constBegin());
        QCOMPARE(i2+0, p.constBegin());
        QCOMPARE(i2+3, p.constEnd());
        i2 += 3;
        i= i2-0;
        QCOMPARE(i, i2);
        i= i2-3;
        QCOMPARE(i, p.constBegin());
        QCOMPARE(i2-i, 3);

        // QhullPoint is const-only
    }
}//t_const_iterator

void QhullPoint_test::
t_foreach()
{
    RboxPoints rcube("c");
    Qhull q(rcube, "QR0");  // rotated unit cube
    QhullPoint p= q.firstVertex().point();
    coordT c2= (p.coordinates())[1];

    bool isC2= false;
    int count= 0;
    foreach(coordT c, q.firstVertex().point()){  // Qt only
        ++count;
        if(c==c2){
            isC2= true;
            QCOMPARE(count, 2);
        }
    }
    QVERIFY(isC2);
    QCOMPARE(count, p.dimension());

    isC2= false;
    count= 0;
    for(coordT c : q.firstVertex().point()){
        ++count;
        if(c==c2){
            isC2= true;
            QCOMPARE(count, 2);
        }
    }
    QVERIFY(isC2);
    QCOMPARE(count, p.dimension());
}//t_foreach

void QhullPoint_test::
t_qhullpoint_iterator()
{
    RboxPoints rcube("c");
    Qhull q(rcube,"QR0");  // rotated unit cube

    QhullPoint p2(q);
    QhullPointIterator i= p2;
    QCOMPARE(p2.dimension(), 3);
    QVERIFY(!i.hasNext());
    QVERIFY(!i.hasPrevious());
    i.toBack();
    QVERIFY(!i.hasNext());
    QVERIFY(!i.hasPrevious());

    QhullPoint p= q.firstVertex().point();
    QhullPointIterator i2(p);
    QCOMPARE(p.dimension(), 3);
    i= p;
    QVERIFY(i2.hasNext());
    QVERIFY(!i2.hasPrevious());
    QVERIFY(i.hasNext());
    QVERIFY(!i.hasPrevious());
    i2.toBack();
    i.toFront();
    QVERIFY(!i2.hasNext());
    QVERIFY(i2.hasPrevious());
    QVERIFY(i.hasNext());
    QVERIFY(!i.hasPrevious());

    // i at front, i2 at end/back, 3 coordinates
    QCOMPARE(i.peekNext(), p[0]);
    QCOMPARE(i2.peekPrevious(), p[2]);
    QCOMPARE(i2.previous(), p[2]);
    QCOMPARE(i2.previous(), p[1]);
    QCOMPARE(i2.previous(), p[0]);
    QVERIFY(!i2.hasPrevious());
    QCOMPARE(i.peekNext(), p[0]);
    // i.peekNext()= 1.0; // compiler error, i is const
    QCOMPARE(i.next(), p[0]);
    QCOMPARE(i.peekNext(), p[1]);
    QCOMPARE(i.next(), p[1]);
    QCOMPARE(i.next(), p[2]);
    QVERIFY(!i.hasNext());
    i.toFront();
    QCOMPARE(i.next(), p[0]);
}//t_qhullpoint_iterator

void QhullPoint_test::
t_java_iterator()
{
    RboxPoints rcube("c");
    Qhull q(rcube, "QR0");  // rotated unit cube
    QhullPoint p= q.firstVertex().point();
    coordT c2= (p.coordinates())[1];

    bool isC2= false;
    int count= 0;
    QhullPointIterator i(q.firstVertex().point());
    while(i.hasNext()){
        coordT c= i.next();
        QCOMPARE(i.peekPrevious(), c);
        ++count;
        if(c==c2){
            isC2= true;
            QCOMPARE(count, 2);
        }
    }
    QVERIFY(isC2);
    QCOMPARE(count, p.dimension());
}//t_java_iterator

void QhullPoint_test::
t_method()
{
    // advancePoint tested above
    RboxPoints rcube("c");
    Qhull q(rcube, "");
    QhullPoint p= q.firstVertex().point();
    double dist= p.distance(q.origin());
    QCOMPARE(dist, sqrt(double(2.0+1.0))/2); // half diagonal of unit cube
}//t_qhullpoint_iterator

void QhullPoint_test::
t_io()
{
    RboxPoints rcube("c");
    {
        Qhull q(rcube, "");
        QhullPoint p= q.beginVertex().point();
        ostringstream os;
        os << "Point:\n";
        os << p;
        os << "Point w/ print:\n";
        os << p.print(" message ");
        os << p.printWithIdentifier(" Point with id and a message ");
        cout << os.str();
        QString s= QString::fromStdString(os.str());
        QCOMPARE(s.count("p"), 2);
    }
}//t_io

}//orgQhull

#include "moc/QhullPoint_test.moc"
qhull-2020.2/src/qhulltest/QhullRidge_test.cpp0000644060175106010010000001316313706641751017623 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/qhulltest/QhullRidge_test.cpp#4 $$Change: 3001 $
** $DateTime: 2020/07/24 20:43:28 $$Author: bbarber $
**
****************************************************************************/

//pre-compiled headers
#include 
#include "RoadTest.h" // QT_VERSION

#include "libqhullcpp/QhullRidge.h"
#include "libqhullcpp/QhullError.h"
#include "libqhullcpp/RboxPoints.h"
#include "libqhullcpp/QhullFacet.h"
#include "libqhullcpp/Qhull.h"

using std::cout;
using std::endl;
using std::ostringstream;
using std::ostream;
using std::string;

namespace orgQhull {

class QhullRidge_test : public RoadTest
{
    Q_OBJECT

#//!\name Test slots
private slots:
    void cleanup();
    void t_construct();
    void t_getSet();
    void t_foreach();
    void t_java_iterator();
    void t_io();
};//QhullRidge_test

void
add_QhullRidge_test()
{
    new QhullRidge_test();  // RoadTest::s_testcases
}

//Executed after each testcase
void QhullRidge_test::
cleanup()
{
    RoadTest::cleanup();
}

void QhullRidge_test::
t_construct()
{
    // Qhull.runQhull() constructs QhullFacets as facetT
    RboxPoints rcube("c");
    Qhull q(rcube,"QR0");  // triangulation of rotated unit cube
    QhullRidge r(q);
    QVERIFY(!r.isValid());
    QCOMPARE(r.dimension(),2);
    QhullFacet f(q.firstFacet());
    QhullRidgeSet rs(f.ridges());
    QVERIFY(!rs.isEmpty()); // Simplicial facets do not have ridges()
    QhullRidge r2(rs.first());
    QCOMPARE(r2.dimension(), 2); // One dimension lower than the facet
    r= r2;
    QVERIFY(r.isValid());
    QCOMPARE(r.dimension(), 2);
    QhullRidge r3(q, r2.getRidgeT());
    QCOMPARE(r,r3);
    QhullRidge r4(q, r2.getBaseT());
    QCOMPARE(r,r4);
    QhullRidge r5= r2; // copy constructor
    QVERIFY(r5==r2);
    QVERIFY(r5==r);
}//t_construct

void QhullRidge_test::
t_getSet()
{
    RboxPoints rcube("c");
    {
        Qhull q(rcube,"QR0");  // triangulation of rotated unit cube
        QCOMPARE(q.facetCount(), 6);
        QCOMPARE(q.vertexCount(), 8);
        QhullFacet f(q.firstFacet());
        QhullRidgeSet rs= f.ridges();
        QhullRidgeSetIterator i(rs);
        while(i.hasNext()){
            const QhullRidge r= i.next();
            cout << r.id() << endl;
            QhullRidge r2;
            r2.setRidgeT(r.qh(), r.getRidgeT());
            QCOMPARE(r, r2);
            QVERIFY(r.bottomFacet()!=r.topFacet());
            QCOMPARE(r.dimension(), 2); // Ridge one-dimension less than facet
            QVERIFY(r.id()>=0 && r.id()<9*27);
            QVERIFY(r.isValid());
            QVERIFY(r==r);
            QVERIFY(r==i.peekPrevious());
            QCOMPARE(r.otherFacet(r.bottomFacet()),r.topFacet());
            QCOMPARE(r.otherFacet(r.topFacet()),r.bottomFacet());
        }
    }
}//t_getSet

void QhullRidge_test::
t_foreach()
{
    RboxPoints rcube("c");  // cube
    {
        Qhull q(rcube, "QR0"); // rotated cube
        QhullFacet f(q.firstFacet());
        foreach(const QhullRidge &r, f.ridges()){  // Qt only
            QhullVertexSet vs= r.vertices();
            QCOMPARE(vs.count(), 2);
            foreach(const QhullVertex &v, vs){  // Qt only
                QVERIFY(f.vertices().contains(v));
            }
        }
        QhullRidgeSet rs= f.ridges();
        QhullRidge r= rs.first();
        QhullRidge r2= r;
        QList vs;
        int count= 0;
        while(!count || r2!=r){
            ++count;
            QhullVertex v(q);
            QVERIFY2(r2.hasNextRidge3d(f),"A cube should only have non-simplicial facets.");
            QhullRidge r3= r2.nextRidge3d(f, &v);
            QVERIFY(!vs.contains(v));
            vs << v;
            r2= r2.nextRidge3d(f);
            QCOMPARE(r3, r2);
        }
        QCOMPARE(vs.count(), rs.count());
        QCOMPARE(count, rs.count());

        r2= rs.at(1);
        bool isR2= false;
        count= 0;
        foreach(const QhullRidge &r, f.ridges()) {  // Qt only
            ++count;
            if(r==r2){
                isR2= true;
                QCOMPARE(count, 2);
            }
        }
        QVERIFY(isR2);
        QCOMPARE(count, rs.count());

        isR2= false;
        count= 0;
        for(const QhullRidge &r : f.ridges()) {
            ++count;
            if(r==r2){
                isR2= true;
                QCOMPARE(count, 2);
            }
        }
        QVERIFY(isR2);
        QCOMPARE(count, rs.count());
    }
}//t_foreach

void QhullRidge_test::
t_java_iterator()
{
    RboxPoints rcube("c");  // cube
    {
        Qhull q(rcube, "QR0"); // rotated cube
        QhullFacet f(q.firstFacet());
        QhullRidgeSet rs= f.ridges();
        QhullRidge r2= rs.at(1);

        bool isR2= false;
        int count= 0;
        QhullRidgeSetIterator i(f.ridges());
        while(i.hasNext()){
            QhullRidge r= i.next();
            QCOMPARE(i.peekPrevious(), r);
            ++count;
            if(r==r2){
                isR2= true;
                QCOMPARE(count, 2);
            }
        }
        QVERIFY(isR2);
        QCOMPARE(count, rs.count());
    }
}//t_java_iterator

void QhullRidge_test::
t_io()
{
    RboxPoints rcube("c");
    {
        Qhull q(rcube, "");
        QhullFacet f(q.firstFacet());
        QhullRidgeSet rs= f.ridges();
        QhullRidge r= rs.first();
        ostringstream os;
        os << "Ridges\n" << rs << "Ridge\n" << r;
        os << r.print("\nRidge with message");
        cout << os.str();
        QString s= QString::fromStdString(os.str());
        QCOMPARE(s.count(" r"), 6);
    }
}//t_io

}//orgQhull

#include "moc/QhullRidge_test.moc"
qhull-2020.2/src/qhulltest/QhullSet_test.cpp0000644060175106010010000003152013710652225017312 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2009-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/qhulltest/QhullSet_test.cpp#5 $$Change: 3009 $
** $DateTime: 2020/07/30 19:25:22 $$Author: bbarber $
**
****************************************************************************/

//pre-compiled headers
#include 
#include "RoadTest.h" // QT_VERSION

#include "libqhullcpp/QhullRidge.h"
#include "libqhullcpp/QhullFacetSet.h"
#include "libqhullcpp/Qhull.h"
#include "libqhullcpp/RboxPoints.h"

#include 

using std::cout;
using std::endl;

namespace orgQhull {

class QhullSet_test : public RoadTest
{
    Q_OBJECT

#//!\name Test slots
private slots:
    void cleanup();
    void t_qhullsetbase();
    void t_convert();
    void t_element();
    void t_search();
    void t_iterator();
    void t_const_iterator();
    void t_qhullset_iterator();
    void t_java_iterator();
    void t_io();
};//QhullSet_test

void
add_QhullSet_test()
{
    new QhullSet_test();  // RoadTest::s_testcases
}

//Executed after each testcase
void QhullSet_test::
cleanup()
{
    RoadTest::cleanup();
}

// Test QhullFacetSet and QhullSet.
// Use QhullRidgeSet to test methods overloaded by QhullFacetSet

void QhullSet_test::
t_qhullsetbase()
{
    RboxPoints rcube("c");
    {
        Qhull q(rcube,"QR0");  // triangulation of rotated unit cube
        // Fake an empty set.  Default constructor not defined.  No memory allocation.
        QhullFacet f4= q.beginFacet();
        QhullFacetSet fs= f4.neighborFacets();
        fs.defineAs(q.qh()->other_points); // Force an empty set
        QVERIFY(fs.isEmpty());
        QCOMPARE(fs.count(), 0);
        QCOMPARE(fs.size(), 0u);
        QCOMPARE(fs.begin(), fs.end()); // beginPointer(), endPointer()
        QVERIFY(QhullSetBase::isEmpty(fs.getSetT()));

        QhullRidgeSet rs= f4.ridges();
        QVERIFY(!rs.isEmpty());
        QCOMPARE(rs.count(), 4);
        QCOMPARE(rs.size(), 4u);
        QVERIFY(rs.begin()!=rs.end());
        QVERIFY(!QhullSetBase::isEmpty(rs.getSetT()));
        QhullRidgeSet rs2= rs; // copy constructor
        // rs= rs2; // disabled.  Would not copy ridges
        QCOMPARE(rs2, rs);

        QCOMPARE(q.facetCount(), 6);
        QhullFacet f= q.beginFacet();
        QhullFacetSet fs2= f.neighborFacets();
        QCOMPARE(fs2.count(), 4);
        QCOMPARE(fs2.size(), 4u);
        QVERIFY(!fs2.isEmpty());
        QVERIFY(!QhullSetBase::isEmpty(fs2.getSetT()));
        QVERIFY(fs!=fs2);
        setT *s= fs2.getSetT();
        fs.defineAs(s);
        QVERIFY(fs==fs2);
        QCOMPARE(fs[1], fs2[1]); // elementPointer
        QhullFacetSet fs3(fs2);
        QVERIFY(fs3==fs);
        // fs= fs2; // disabled.  Would not copy facets
        QhullFacetSet fs4= fs2; // copy constructor
        QVERIFY(fs4==fs2);
    }
}//t_qhullsetbase

// constructors tested by t_qhullsetbase

void QhullSet_test::
t_convert()
{
    RboxPoints rcube("c");
    {
        Qhull q(rcube,"QR0");  // rotated unit cube
        QhullFacet f= q.firstFacet();
        f= f.next();
        QhullRidgeSet rs= f.ridges();
        QCOMPARE(rs.count(),4);
        std::vector rv= rs.toStdVector();
        QCOMPARE(rv.size(), 4u);
        QList rv2= rs.toQList();
        QCOMPARE(rv2.size(), 4);
        std::vector::iterator i= rv.begin();
        foreach(QhullRidge r, rv2){  // Qt only
            QhullRidge r2= *i++;
            QCOMPARE(r, r2);
        }

        Qhull q2(rcube,"Qt QR0");  // triangulation of rotated unit cube
        QCOMPARE(q2.facetCount(), 12);
        QhullFacet f2= q2.beginFacet();
        QhullFacetSet fs= f2.neighborFacets();
        QCOMPARE(fs.size(), 3U);
        std::vector vs= fs.toStdVector();
        QCOMPARE(vs.size(), fs.size());
        for(int k= fs.count(); k--; ){
            QCOMPARE(vs[k], fs[k]);
        }
        QList qv= fs.toQList();
        QCOMPARE(qv.count(), fs.count());
        for(int k= fs.count(); k--; ){
            QCOMPARE(qv[k], fs[k]);
        }
    }
}//t_convert

//ReadOnly (count, isEmpty) tested by t_convert
//  operator== tested by t_search

void QhullSet_test::
t_element()
{
    RboxPoints rcube("c");
    Qhull q(rcube,"QR0");  // rotated unit cube
    QhullFacet f= q.beginFacet();
    QhullFacetSet fs= f.neighborFacets();

    QCOMPARE(fs.at(1), fs[1]);
    QCOMPARE(fs.first(), fs[0]);
    QCOMPARE(fs.front(), fs.first());
    QCOMPARE(fs.last(), fs.at(3));
    QCOMPARE(fs.back(), fs.last());
    facetT **d= fs.data();
    facetT * const *d2= fs.data();
    facetT * const *d3= fs.constData();
    QVERIFY(d==d2);
    QVERIFY(d2==d3);
    QCOMPARE(QhullFacet(q, *d), fs.first());
    QhullFacetSet::iterator i(q.qh(), d+4);
    QCOMPARE(i, fs.end());
    QCOMPARE(d[4], static_cast(0));
    QhullFacet f4(q, d[4]);
    QVERIFY(!f4.isValid());
    QCOMPARE(fs.second(), fs[1]);
    const QhullFacet f2= fs.second();
    QVERIFY(f2==fs[1]);
    const QhullFacet f3= fs[1];
    QCOMPARE(f2, f3);

    QCOMPARE(fs.value(2), fs[2]);
    QCOMPARE(fs.value(-1), QhullFacet());
    QCOMPARE(fs.value(10), QhullFacet());
    QCOMPARE(fs.value(2, f), fs[2]);
    QCOMPARE(fs.value(4, f), f);
    // mid() not available (read-only)
}//t_element

void QhullSet_test::
t_search()
{
    RboxPoints rcube("c");
    Qhull q(rcube,"QR0");  // rotated unit cube
    QhullFacet f= q.beginFacet();
    QhullFacetSet fs= f.neighborFacets();
    QhullFacet f2= *fs.begin();
    QhullFacet f3= fs.last();
    QVERIFY(fs.contains(f2));
    QVERIFY(fs.contains(f3));
    QVERIFY(!fs.contains(f));

    QhullFacetSet fs2= f2.neighborFacets();
    QVERIFY(fs==fs);
    QVERIFY(fs!=fs2);
    QCOMPARE(fs.count(f2), 1);
    QCOMPARE(fs.count(f3), 1);
    QCOMPARE(fs.count(f), 0);
    QCOMPARE(fs.indexOf(f2), 0);
    QCOMPARE(fs.indexOf(f3), 3);
    QCOMPARE(fs.indexOf(f), -1);
    QCOMPARE(fs.lastIndexOf(f2), 0);
    QCOMPARE(fs.lastIndexOf(f3), 3);
    QCOMPARE(fs.lastIndexOf(f), -1);
}//t_search

void QhullSet_test::
t_iterator()
{
    RboxPoints rcube("c");
    {
        Qhull q(rcube,"QR0");  // rotated unit cube
        QhullFacet f= q.beginFacet();
        QhullFacetSet fs= f.neighborFacets();
        QhullFacetSet::Iterator i= fs.begin();
        QhullFacetSet::iterator i2= fs.begin();
        QVERIFY(i==i2);
        QVERIFY(i>=i2);
        QVERIFY(i<=i2);
        i= fs.begin();
        QVERIFY(i==i2);
        i2= fs.end();
        QVERIFY(i!=i2);
        QhullFacet f3(*i);
        i2--;
        QhullFacet f2= *i2;
        QCOMPARE(f3.id(), fs[0].id());
        QCOMPARE(f2.id(), fs[3].id());
        QhullFacetSet::Iterator i3(i2);
        QCOMPARE(*i2, *i3);

        (i3= i)++;
        QCOMPARE((*i3).id(), fs[1].id());
        QVERIFY(i==i);
        QVERIFY(i!=i2);
        QVERIFY(ii);
        QVERIFY(i2>=i);

        QhullFacetSet::ConstIterator i4= fs.begin();
        QVERIFY(i==i4); // iterator COMP const_iterator
        QVERIFY(i<=i4);
        QVERIFY(i>=i4);
        QVERIFY(i4==i); // const_iterator COMP iterator
        QVERIFY(i4<=i);
        QVERIFY(i4>=i);
        QVERIFY(i>=i4);
        QVERIFY(i4<=i);
        QVERIFY(i2!=i4);
        QVERIFY(i2>i4);
        QVERIFY(i2>=i4);
        QVERIFY(i4!=i2);
        QVERIFY(i4i);
        QVERIFY(i4>=i);

        i= fs.begin();
        i2= fs.begin();
        QCOMPARE(i, i2++);
        QCOMPARE(*i2, fs[1]);
        QCOMPARE(++i, i2);
        QCOMPARE(i, i2--);
        QCOMPARE(i2, fs.begin());
        QCOMPARE(--i, i2);
        QCOMPARE(i2 += 4, fs.end());
        QCOMPARE(i2 -= 4, fs.begin());
        QCOMPARE(i2+0, fs.begin());
        QCOMPARE(i2+4, fs.end());
        i2 += 4;
        i= i2-0;
        QCOMPARE(i, i2);
        i= i2-4;
        QCOMPARE(i, fs.begin());
        QCOMPARE(i2-i, 4);

        //fs.begin end tested above

        // QhullFacetSet is const-only
    }
}//t_iterator

void QhullSet_test::
t_const_iterator()
{
    RboxPoints rcube("c");
    {
        Qhull q(rcube,"QR0");  // rotated unit cube
        QhullFacet f= q.beginFacet();
        QhullFacetSet fs= f.neighborFacets();
        QhullFacetSet::ConstIterator i= fs.begin();
        QhullFacetSet::const_iterator i2= fs.begin();
        QVERIFY(i==i2);
        QVERIFY(i>=i2);
        QVERIFY(i<=i2);
        i= fs.begin();
        QVERIFY(i==i2);
        i2= fs.end();
        QVERIFY(i!=i2);
        QhullFacet f3(*i);
        i2--;
        QhullFacet f2= *i2;
        QCOMPARE(f3.id(), fs[0].id());
        QCOMPARE(f2.id(), fs[3].id());
        QhullFacetSet::ConstIterator i3(i2);
        QCOMPARE(*i2, *i3);

        (i3= i)++;
        QCOMPARE((*i3).id(), fs[1].id());
        QVERIFY(i==i);
        QVERIFY(i!=i2);
        QVERIFY(ii);
        QVERIFY(i2>=i);

        // See t_iterator for const_iterator COMP iterator

        i= fs.begin();
        i2= fs.constBegin();
        QCOMPARE(i, i2++);
        QCOMPARE(*i2, fs[1]);
        QCOMPARE(++i, i2);
        QCOMPARE(i, i2--);
        QCOMPARE(i2, fs.constBegin());
        QCOMPARE(--i, i2);
        QCOMPARE(i2+=4, fs.constEnd());
        QCOMPARE(i2-=4, fs.constBegin());
        QCOMPARE(i2+0, fs.constBegin());
        QCOMPARE(i2+4, fs.constEnd());
        i2 += 4;
        i= i2-0;
        QCOMPARE(i, i2);
        i= i2-4;
        QCOMPARE(i, fs.constBegin());
        QCOMPARE(i2-i, 4);

        // QhullFacetSet is const-only
    }
}//t_const_iterator

void QhullSet_test::
t_qhullset_iterator()
{
    RboxPoints rcube("c");
    Qhull q(rcube,"QR0");  // rotated unit cube
    // Fake an empty set.  Default constructor not defined.  No memory allocation.
    QhullFacet f= q.beginFacet();
    QhullFacetSet fs= f.neighborFacets();
    fs.defineAs(q.qh()->other_points);
    QhullFacetSetIterator i(fs);
    QCOMPARE(fs.count(), 0);
    QVERIFY(!i.hasNext());
    QVERIFY(!i.hasPrevious());
    i.toBack();
    QVERIFY(!i.hasNext());
    QVERIFY(!i.hasPrevious());

    QhullFacet f2= q.beginFacet();
    QhullFacetSet fs2= f2.neighborFacets();
    QhullFacetSetIterator i2(fs2);
    QCOMPARE(fs2.count(), 4);
    i= fs2;
    QVERIFY(i2.hasNext());
    QVERIFY(!i2.hasPrevious());
    QVERIFY(i.hasNext());
    QVERIFY(!i.hasPrevious());
    i2.toBack();
    i.toFront();
    QVERIFY(!i2.hasNext());
    QVERIFY(i2.hasPrevious());
    QVERIFY(i.hasNext());
    QVERIFY(!i.hasPrevious());

    // i at front, i2 at end/back, 4 neighbors
    QhullFacetSet fs3= f2.neighborFacets(); // same as fs2
    QhullFacet f3(fs2[0]);
    QhullFacet f4= fs3[0];
    QCOMPARE(f3, f4);
    QVERIFY(f3==f4);
    QhullFacet f5(fs3[1]);
    QVERIFY(f4!=f5);
    QhullFacet f6(fs3[2]);
    QhullFacet f7(fs3[3]);
    QCOMPARE(i2.peekPrevious(), f7);
    QCOMPARE(i2.previous(), f7);
    QCOMPARE(i2.previous(), f6);
    QCOMPARE(i2.previous(), f5);
    QCOMPARE(i2.previous(), f4);
    QVERIFY(!i2.hasPrevious());
    QCOMPARE(i.peekNext(), f4);
    // i.peekNext()= 1.0; // compiler error
    QCOMPARE(i.next(), f4);
    QCOMPARE(i.peekNext(), f5);
    QCOMPARE(i.next(), f5);
    QCOMPARE(i.next(), f6);
    QCOMPARE(i.next(), f7);
    QVERIFY(!i.hasNext());
    i.toFront();
    QCOMPARE(i.next(), f4);
}//t_qhullset_iterator

void QhullSet_test::
t_java_iterator()
{
    RboxPoints rcube("c");
    Qhull q(rcube, "QR0");  // rotated unit cube
    QhullVertexSet vs= q.firstFacet().vertices();
    QhullVertex v2= vs.at(1);

    bool isV2= false;
    int count= 0;
    QhullVertexSetIterator i(q.firstFacet().vertices());
    while(i.hasNext()){
        QhullVertex v= i.next();
        QCOMPARE(i.peekPrevious(), v);
        ++count;
        if(v==v2){
            isV2= true;
            QCOMPARE(count, 2);
        }
    }
    QVERIFY(isV2);
    QCOMPARE(count, vs.count());

    QhullRidgeSet rs= q.firstFacet().ridges();
    QhullRidge r2= rs.at(1);

    bool isR2= false;
    count= 0;
    QhullRidgeSetIterator ir(q.firstFacet().ridges());
    while(ir.hasNext()){
        QhullRidge r= ir.next();
        QCOMPARE(ir.peekPrevious(), r);
        ++count;
        if(r==r2){
            isR2= true;
            QCOMPARE(count, 2);
        }
    }
    QVERIFY(isR2);
    QCOMPARE(count, rs.count());
}//t_java_iterator

void QhullSet_test::
t_io()
{
    RboxPoints rcube("c");
    Qhull q(rcube,"QR0");  // rotated unit cube
    // Fake an empty set.  Default constructor not defined.  No memory allocation.
    QhullFacet f= q.beginFacet();
    QhullFacetSet fs= f.neighborFacets();
    fs.defineAs(q.qh()->other_points);
    cout << "INFO:     empty set" << fs << std::endl;
    QhullFacet f2= q.beginFacet();
    QhullFacetSet fs2= f2.neighborFacets();
    cout << "INFO:   Neighboring facets\n";
    cout << fs2 << std::endl;

    QhullRidgeSet rs= f.ridges();
    cout << "INFO:   Ridges for a facet\n";
    cout << rs << std::endl;
}//t_io

}//namespace orgQhull

#include "moc/QhullSet_test.moc"
qhull-2020.2/src/qhulltest/qhulltest.cpp0000644060175106010010000000534013706660515016546 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/qhulltest/qhulltest.cpp#5 $$Change: 3001 $
** $DateTime: 2020/07/24 20:43:28 $$Author: bbarber $
**
****************************************************************************/

//pre-compiled headers
#include "libqhull_r/user_r.h"

#include 
#include "RoadTest.h" // QT_VERSION

#include "libqhullcpp/RoadError.h"
#include "libqhull_r/qhull_ra.h"

#include 
#include 
#include 

using std::cout;
using std::endl;

namespace orgQhull {

void addQhullTests(QStringList &args)
{
    // Default tests, use Qhull_test for qhulltest-ok.txt
    TESTadd_(add_PointCoordinates_test);
    TESTadd_(add_Qhull_test);

    if(args.contains("--all")){
        args.removeAll("--all");
        // up-to-date
        TESTadd_(add_Coordinates_test);
        TESTadd_(add_PointCoordinates_test);
        TESTadd_(add_QhullFacet_test);
        TESTadd_(add_QhullFacetList_test);
        TESTadd_(add_QhullFacetSet_test);
        TESTadd_(add_QhullHyperplane_test);
        TESTadd_(add_QhullLinkedList_test);
        TESTadd_(add_QhullPoint_test);
        TESTadd_(add_QhullPoints_test);
        TESTadd_(add_QhullPointSet_test);
        TESTadd_(add_QhullRidge_test);
        TESTadd_(add_QhullSet_test);
        TESTadd_(add_QhullVertex_test);
        TESTadd_(add_QhullVertexSet_test);
        TESTadd_(add_RboxPoints_test);
        // qhullStat
        TESTadd_(add_Qhull_test);
    }//--all
}//addQhullTests

int main(int argc, char *argv[])
{

    QCoreApplication app(argc, argv);
    QStringList args= app.arguments();
    bool isAll= args.contains("--all");

    QHULL_LIB_CHECK /* Check for compatible library */

    addQhullTests(args);
    int status=1010;
    try{
        status= RoadTest::runTests(args);
    }catch(const std::exception &e){
        cout << "FAIL!  : runTests() did not catch error\n";
        cout << e.what() << endl;
        if(!RoadError::emptyGlobalLog()){
            cout << RoadError::stringGlobalLog() << endl;
            RoadError::clearGlobalLog();
        }
    }
    if(!RoadError::emptyGlobalLog()){
        cout << RoadError::stringGlobalLog() << endl;
        RoadError::clearGlobalLog();
    }
    if(isAll){
        cout << "Finished test of libqhullcpp.  Test libqhull_r with eg/q_test after building libqhull_r/Makefile" << endl;
    }else{
        cout << "Finished test of one class.  Test all classes with 'qhulltest --all'" << endl;
    }
    RoadTest::deleteTests();
    return status;
}

}//namespace orgQhull

int main(int argc, char *argv[])
{
    return orgQhull::main(argc, argv); // Needs RoadTest:: for TESTadd_() linkage
}

qhull-2020.2/src/qhulltest/qhulltest.pro0000644060175106010010000000177512503152740016562 0ustar  bbarber# -------------------------------------------------
# qhulltest.pro -- Qt project for qhulltest.exe (QTestLib)
# cd $qh/build/qhulltest && qmake -tp vc -r ../../src/qhulltest/qhulltest.pro
# -------------------------------------------------

include(../qhull-app-cpp.pri)

TARGET = qhulltest
QT += testlib
MOC_DIR = moc
INCLUDEPATH += ..  # for MOC_DIR

PRECOMPILED_HEADER = RoadTest.h

HEADERS += RoadTest.h

SOURCES += ../libqhullcpp/qt-qhull.cpp
SOURCES += Coordinates_test.cpp
SOURCES += PointCoordinates_test.cpp
SOURCES += Qhull_test.cpp
SOURCES += QhullFacet_test.cpp
SOURCES += QhullFacetList_test.cpp
SOURCES += QhullFacetSet_test.cpp
SOURCES += QhullHyperplane_test.cpp
SOURCES += QhullLinkedList_test.cpp
SOURCES += QhullPoint_test.cpp
SOURCES += QhullPoints_test.cpp
SOURCES += QhullPointSet_test.cpp
SOURCES += QhullRidge_test.cpp
SOURCES += QhullSet_test.cpp
SOURCES += qhulltest.cpp
SOURCES += QhullVertex_test.cpp
SOURCES += QhullVertexSet_test.cpp
SOURCES += RboxPoints_test.cpp
SOURCES += RoadTest.cpp

qhull-2020.2/src/qhulltest/QhullVertexSet_test.cpp0000644060175106010010000001225413710652225020513 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/qhulltest/QhullVertexSet_test.cpp#4 $$Change: 3009 $
** $DateTime: 2020/07/30 19:25:22 $$Author: bbarber $
**
****************************************************************************/

//pre-compiled headers
#include 
#include "qhulltest/RoadTest.h" // QT_VERSION

#include "libqhullcpp/QhullVertexSet.h"
#include "libqhullcpp/QhullVertex.h"
#include "libqhullcpp/Qhull.h"
#include "libqhullcpp/QhullError.h"
#include "libqhullcpp/QhullFacet.h"
#include "libqhullcpp/RboxPoints.h"

using std::cout;
using std::endl;
using std::ostringstream;
using std::ostream;
using std::string;

namespace orgQhull {

class QhullVertexSet_test : public RoadTest
{
    Q_OBJECT

#//!\name Test slots
private slots:
    void cleanup();
    void t_construct();
    void t_convert();
    void t_readonly();
    void t_foreach();
    void t_java_iterator();
    void t_io();
};//QhullVertexSet_test

void
add_QhullVertexSet_test()
{
    new QhullVertexSet_test();  // RoadTest::s_testcases
}

//Executed after each testcase
void QhullVertexSet_test::
cleanup()
{
    RoadTest::cleanup();
}

void QhullVertexSet_test::
t_construct()
{
    RboxPoints rcube("c");
    Qhull q(rcube,"QR0");  // rotated unit cube
    cout << "INFO   : Cube rotated by QR" << q.rotateRandom() << std::endl;
    QhullFacet f= q.firstFacet();
    QhullVertexSet vs= f.vertices();
    QVERIFY(!vs.isEmpty());
    QCOMPARE(vs.count(),4);
    QhullVertexSet vs4= vs; // copy constructor
    QVERIFY(vs4==vs);
    QhullVertexSet vs3(q, q.qh()->del_vertices);
    QVERIFY(vs3.isEmpty());
}//t_construct

void QhullVertexSet_test::
t_convert()
{
    RboxPoints rcube("c");
    Qhull q(rcube,"QR0 QV2");  // rotated unit cube with "good" facets adjacent to point 0
    cout << "INFO   : Cube rotated by QR" << q.rotateRandom() << std::endl;
    QhullFacet f= q.firstFacet();
    QhullVertexSet vs2= f.vertices();
    QCOMPARE(vs2.count(),4);
    std::vector fv= vs2.toStdVector();
    QCOMPARE(fv.size(), 4u);
    QList fv2= vs2.toQList();
    QCOMPARE(fv2.size(), 4);
    std::vector fv3= vs2.toStdVector();
    QCOMPARE(fv3.size(), 4u);
    QList fv4= vs2.toQList();
    QCOMPARE(fv4.size(), 4);
}//t_convert

//! Spot check properties and read-only.  See QhullSet_test
void QhullVertexSet_test::
t_readonly()
{
    RboxPoints rcube("c");
    Qhull q(rcube,"QV0");  // good facets are adjacent to point 0
    QhullVertexSet vs= q.firstFacet().vertices();
    QCOMPARE(vs.count(), 4);
    QCOMPARE(vs.count(), 4);
    QhullVertex v= vs.first();
    QhullVertex v2= vs.last();
    QVERIFY(vs.contains(v));
    QVERIFY(vs.contains(v2));
}//t_readonly

void QhullVertexSet_test::
t_foreach()
{
    RboxPoints rcube("c");
    // Spot check predicates and accessors.  See QhullLinkedList_test
    Qhull q(rcube,"QR0");  // rotated unit cube
    cout << "INFO   : Cube rotated by QR" << q.rotateRandom() << std::endl;
    QhullVertexSet vs= q.firstFacet().vertices();
    QVERIFY(vs.contains(vs.first()));
    QVERIFY(vs.contains(vs.last()));
    QCOMPARE(vs.first(), *vs.begin());
    QCOMPARE(*(vs.end()-1), vs.last());
    QhullVertex v2= vs.at(1);

    bool isV2= false;
    int count= 0;
    foreach(QhullVertex v, q.firstFacet().vertices()){ // Qt only
        ++count;
        if(v==v2){
            isV2= true;
        }
    }
    QVERIFY(isV2);
    QCOMPARE(count, vs.count());

    isV2= false;
    count= 0;
    for(QhullVertex v : q.firstFacet().vertices()){
        ++count;
        if(v==v2){
            isV2= true;
        }
    }
    QVERIFY(isV2);
    QCOMPARE(count, vs.count());
}//t_foreach

void QhullVertexSet_test::
t_java_iterator()
{
    RboxPoints rcube("c");
    Qhull q(rcube, "QR0");  // rotated unit cube
    QhullVertexSet vs= q.firstFacet().vertices();
    QhullVertex v2= vs.at(1);

    bool isV2= false;
    int count= 0;
    QhullVertexSetIterator i(q.firstFacet().vertices());
    while(i.hasNext()){
        QhullVertex v= i.next();
        QCOMPARE(i.peekPrevious(), v);
        ++count;
        if(v==v2){
            isV2= true;
            QCOMPARE(count, 2);
        }
    }
    QVERIFY(isV2);
    QCOMPARE(count, vs.count());
}//t_java_iterator

void QhullVertexSet_test::
t_io()
{
    RboxPoints rcube("c");
    {
        Qhull q(rcube,"QR0 QV0");   // good facets are adjacent to point 0
        cout << "INFO   : Cube rotated by QR" << q.rotateRandom() << std::endl;
        QhullVertexSet vs= q.firstFacet().vertices();
        ostringstream os;
        os << vs.print("Vertices of first facet with point 0");
        os << vs.printIdentifiers("\nVertex identifiers: ");
        cout<< os.str();
        QString vertices= QString::fromStdString(os.str());
        QCOMPARE(vertices.count(QRegExp(" v[0-9]")), 4);
    }
}//t_io

#ifdef QHULL_USES_QT
QList QhullVertexSet::
toQList() const
{
    QhullSetIterator i(*this);
    QList vs;
    while(i.hasNext()){
        QhullVertex v= i.next();
        vs.append(v);
    }
    return vs;
}//toQList
#endif //QHULL_USES_QT

}//orgQhull

#include "moc/QhullVertexSet_test.moc"
qhull-2020.2/src/qhulltest/QhullVertex_test.cpp0000644060175106010010000001465513706626762020062 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/qhulltest/QhullVertex_test.cpp#4 $$Change: 3001 $
** $DateTime: 2020/07/24 20:43:28 $$Author: bbarber $
**
****************************************************************************/

//pre-compiled headers
#include 
#include "RoadTest.h" // QT_VERSION

#include "libqhullcpp/QhullVertex.h"
#include "libqhullcpp/Coordinates.h"
#include "libqhullcpp/QhullError.h"
#include "libqhullcpp/RboxPoints.h"
#include "libqhullcpp/QhullFacet.h"
#include "libqhullcpp/QhullFacetSet.h"
#include "libqhullcpp/QhullVertexSet.h"
#include "libqhullcpp/Qhull.h"

using std::cout;
using std::endl;
using std::ostringstream;
using std::ostream;
using std::string;

namespace orgQhull {

class QhullVertex_test : public RoadTest
{
    Q_OBJECT

#//!\name Test slots
private slots:
    void cleanup();
    void t_constructConvert();
    void t_getSet();
    void t_foreach();
    void t_io();
};//QhullVertex_test

void
add_QhullVertex_test()
{
    new QhullVertex_test();  // RoadTest::s_testcases
}

//Executed after each testcase
void QhullVertex_test::
cleanup()
{
    RoadTest::cleanup();
}

void QhullVertex_test::
t_constructConvert()
{
    QhullVertex v6;
    QVERIFY(!v6.isValid());
    QCOMPARE(v6.dimension(),0);
    // Qhull.runQhull() constructs QhullFacets as facetT
    RboxPoints rcube("c");
    Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
    QhullVertex v(q);
    QVERIFY(!v.isValid());
    QCOMPARE(v.dimension(),3);
    QhullVertex v2(q.beginVertex());
    QCOMPARE(v2.dimension(),3);
    v= v2;  // copy assignment
    QVERIFY(v.isValid());
    QCOMPARE(v.dimension(),3);
    QhullVertex v5= v2; // copy constructor
    QVERIFY(v5==v2);
    QVERIFY(v5==v);
    QhullVertex v3(q, v2.getVertexT());
    QCOMPARE(v,v3);
    QhullVertex v4(q, v2.getBaseT());
    QCOMPARE(v,v4);
}//t_constructConvert

void QhullVertex_test::
t_getSet()
{
    RboxPoints rcube("c");
    {
        Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
        QCOMPARE(q.facetCount(), 12);
        QCOMPARE(q.vertexCount(), 8);

        // Also spot-test QhullVertexList.  See QhullLinkedList_test.cpp
        QhullVertexList vs= q.vertexList();
        QhullVertexListIterator i(vs);
        while(i.hasNext()){
            const QhullVertex v= i.next();
            cout << v.id() << endl;
            QCOMPARE(v.dimension(),3);
            QVERIFY(v.id()>=0 && v.id()<9);
            QVERIFY(v.isValid());
            QhullVertex v2;
            v2.setVertexT(v.qh(), v.getVertexT());
            QCOMPARE(v, v2);
            if(i.hasNext()){
                QCOMPARE(v.next(), i.peekNext());
                QVERIFY(v.next()!=v);
                QCOMPARE(v.next().previous(), v);
                QVERIFY(v.hasNext());
                QVERIFY(v.next().hasPrevious());
            }else
              QVERIFY(!v.hasNext());
            QVERIFY(i.hasPrevious());
            QCOMPARE(v, i.peekPrevious());
        }
        while(i.hasPrevious()){
          const QhullVertex v= i.previous();
          cout << v.id() << endl;
          QVERIFY(v.isValid());
          if(i.hasPrevious()){
            QVERIFY(v.hasPrevious());
            QCOMPARE(v.previous(), i.peekPrevious());
            QVERIFY(v.previous()!=v);
            QVERIFY(v.previous().hasNext());
            QCOMPARE(v.previous().next(), v);
          }else
            QVERIFY(!v.hasPrevious());
          QVERIFY(i.hasNext());
          QCOMPARE(v, i.peekNext());
        }

        // test point()
        foreach (QhullVertex v, q.vertexList()){  // Qt only
            QhullPoint p= v.point();
            int j= p.id();
            cout << "Point " << j << ":\n" << p << endl;
            QVERIFY(j>=0 && j<8);
        }
    }
}//t_getSet

void QhullVertex_test::
t_foreach()
{
    //!\see QhullLinkedList_test::t_java_iterator for test of QhullVertexListIterator
    RboxPoints rcube("c W0 300");  // 300 points on surface of cube
    {
        Qhull q(rcube, "QR0 Qc"); // keep coplanars, thick facet, and rotate the cube
        int count= 0;
        foreach(QhullVertex v, q.vertexList()){  // Qt only
            ++count;
            QhullFacetSet fs= v.neighborFacets();
            QCOMPARE(fs.count(), 3);
            foreach(QhullFacet f, v.neighborFacets()){  // Qt only
                QVERIFY(f.vertices().contains(v));
            }
        }
        QCOMPARE(count, q.vertexCount());

        count= 0;
        for(QhullVertex v : q.vertexList()) { 
            ++count;
            QhullFacetSet fs= v.neighborFacets();
            QCOMPARE(fs.count(), 3);
            foreach(QhullFacet f, v.neighborFacets()){
                QVERIFY(f.vertices().contains(v));
            }
        }
        QCOMPARE(count, q.vertexCount());
    }
}//t_foreach

void QhullVertex_test::
t_io()
{
    RboxPoints rcube("c");
    {
        Qhull q(rcube, "");
        QhullVertex v= q.beginVertex();
        ostringstream os;
        os << "Vertex and vertices:\n";
        os << v;
        QhullVertexSet vs= q.firstFacet().vertices();
        os << vs;
        os << "\nVertex and vertices with message:\n";
        os << v.print("Vertex");
        os << vs.print("\nVertices:");
        cout << os.str();
        QString s= QString::fromStdString(os.str());
        QCOMPARE(s.count("(v"), 10);
        QCOMPARE(s.count(": f"), 2);
    }
    RboxPoints r10("10 D3");  // Without QhullVertex::facetNeighbors
    {
        Qhull q(r10, "");
        QhullVertex v= q.beginVertex();
        ostringstream os;
        os << "\nTry again with simplicial facets.  No neighboring facets listed for vertices.\n";
        os << "Vertex and vertices:\n";
        os << v;
        q.defineVertexNeighborFacets();
        os << "This time with neighborFacets() defined for all vertices:\n";
        os << v;
        cout << os.str();
        QString s= QString::fromStdString(os.str());
        QCOMPARE(s.count(": f"), 1);

        Qhull q2(r10, "v"); // Voronoi diagram
        QhullVertex v2= q2.beginVertex();
        ostringstream os2;
        os2 << "\nTry again with Voronoi diagram of simplicial facets.  Neighboring facets automatically defined for vertices.\n";
        os2 << "Vertex and vertices:\n";
        os2 << v2;
        cout << os2.str();
        QString s2= QString::fromStdString(os2.str());
        QCOMPARE(s2.count(": f"), 1);
    }
}//t_io

}//orgQhull

#include "moc/QhullVertex_test.moc"
qhull-2020.2/src/qhulltest/Qhull_test.cpp0000644060175106010010000003213013710657073016642 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/qhulltest/Qhull_test.cpp#9 $$Change: 3010 $
** $DateTime: 2020/07/30 22:14:11 $$Author: bbarber $
**
****************************************************************************/

//pre-compiled headers
#include 
#include  // setw

#include "qhulltest/RoadTest.h" // QT_VERSION

#include "libqhullcpp/Qhull.h"
#include "libqhullcpp/QhullError.h"
#include "libqhullcpp/RboxPoints.h"
#include "libqhullcpp/QhullFacetList.h"
#include "libqhullcpp/QhullFacetSet.h"
#include "libqhullcpp/QhullVertexSet.h"

using std::cout;
using std::endl;
using std::string;

namespace orgQhull{

//! Test C++ interface to Qhull
//! See eg/q_test for tests of Qhull commands
class Qhull_test : public RoadTest
{
    Q_OBJECT

#//!\name Test slots
private slots:
    void cleanup();
    void t_construct();
    void t_attribute();
    void t_message();
    void t_getSet();
    void t_getQh();
    void t_getValue();
    void t_foreach();
    void t_diamond();
};//Qhull_test

void
add_Qhull_test()
{
    new Qhull_test();  // RoadTest::s_testcases
}

//Executed after each testcase
void Qhull_test::
cleanup()
{
    RoadTest::cleanup();
}

void Qhull_test::
t_construct()
{
   {
        Qhull q;
        QCOMPARE(q.dimension(),0);
        QVERIFY(q.qh()!=0);
        QCOMPARE(QString(q.qhullCommand()),QString(""));
        QCOMPARE(QString(q.rboxCommand()),QString(""));
        try{
            QCOMPARE(q.area(),0.0);
            QFAIL("area() did not fail.");
        }catch (const std::exception &e){
            cout << "INFO   : Caught " << e.what();
        }
    }
   {
        RboxPoints rbox("10000");
        Qhull q(rbox, "QR0"); // Random points in a randomly rotated cube.
        QCOMPARE(q.dimension(),3);
        QVERIFY(q.volume() < 1.0);
        QVERIFY(q.volume() > 0.99);
    }
   {
        double points[]={
            0, 0,
            1, 0,
            1, 1
        };
        Qhull q("triangle", 2, 3, points, "");
        QCOMPARE(q.dimension(),2);
        QCOMPARE(q.facetCount(),3);
        QCOMPARE(q.vertexCount(),3);
        QCOMPARE(q.dimension(),2);
        double area= (2.0 + sqrt(2.0));
        double delta= fabs(q.area() - area);
        double qtDelta= 0.000000000001 * area;
        cout << "area delta " << delta << ". qFuzzyCompare delta " << qtDelta << endl;
        QCOMPARE(q.area(), 2.0+sqrt(2.0)); // length of boundary
        QCOMPARE(q.volume(), 0.5);        // the 2-d area
    }
}//t_construct

void Qhull_test::
t_attribute()
{
    RboxPoints rcube("c");
   {
        double normals[]={
            0,  -1, -0.5,
           -1,   0, -0.5,
            1,   0, -0.5,
            0,   1, -0.5
        };
        Qhull q;
        Coordinates feasible;
        feasible << 0.0 << 0.0;
        q.setFeasiblePoint(feasible);
        Coordinates c(std::vector(2, 0.0));
        QVERIFY(q.feasiblePoint()==c);
        q.setOutputStream(&cout);
        q.runQhull("normals of square", 3, 4, normals, "H"); // halfspace intersect
        QVERIFY(q.feasiblePoint()==c); // from qh.feasible_point after runQhull()
        QCOMPARE(q.facetList().count(), 4); // Vertices of square
        cout << "Expecting summary of halfspace intersection\n";
        q.outputQhull();
        q.qh()->disableOutputStream();  // Same as q.disableOutputStream()
        cout << "Expecting no output from qh_fprintf() in Qhull.cpp\n";
        q.outputQhull();
        cout << "Expecting output from ~Qhull\n";
    }
}//t_attribute

//! No QhullMessage for errors outside of qhull
void Qhull_test::
t_message()
{
    RboxPoints rcube("c");
   {
        Qhull q;
        QCOMPARE(q.qhullMessage(), string(""));
        QCOMPARE(q.qhullStatus(), qh_ERRnone);
        QVERIFY(!q.hasQhullMessage());
        try{
            q.runQhull(rcube, "Fd");
            QFAIL("runQhull Fd did not fail.");
        }catch (const std::exception &e){
            const char *s= e.what();
            cout << "INFO   : Caught " << s;
            QCOMPARE(QString::fromStdString(s).left(6), QString("QH6029"));
            // QH11025 FIX: review decision to clearQhullMessage at QhullError()            // Cleared when copied to QhullError
            QVERIFY(!q.hasQhullMessage());
            // QCOMPARE(q.qhullMessage(), QString::fromStdString(s).remove(0, 7));
            // QCOMPARE(q.qhullStatus(), 6029);
            q.clearQhullMessage();
            QVERIFY(!q.hasQhullMessage());
        }
        q.appendQhullMessage("Append 1");
        QVERIFY(q.hasQhullMessage());
        QCOMPARE(QString::fromStdString(q.qhullMessage()), QString("Append 1"));
        q.appendQhullMessage("\nAppend 2\n");
        QCOMPARE(QString::fromStdString(q.qhullMessage()), QString("Append 1\nAppend 2\n"));
        q.clearQhullMessage();
        QVERIFY(!q.hasQhullMessage());
        QCOMPARE(QString::fromStdString(q.qhullMessage()), QString(""));
    }
   {
        cout << "INFO   : Error stream without output stream\n";
        Qhull q;
        q.setErrorStream(&cout);
        q.setOutputStream(0);
        try{
            q.runQhull(rcube, "Fd");
            QFAIL("runQhull Fd did not fail.");
        }catch (const QhullError &e){
            cout << "INFO   : Caught " << e;
            QCOMPARE(e.errorCode(), 6029);
        }
        //QH11025 FIX: Qhullmessage cleared when QhullError thrown.  Switched to e
        //QVERIFY(q.hasQhullMessage());
        //QCOMPARE(QString::fromStdString(q.qhullMessage()).left(6), QString("QH6029"));
        q.clearQhullMessage();
        QVERIFY(!q.hasQhullMessage());
    }
   {
        cout << "INFO   : Error output sent to output stream without error stream\n";
        Qhull q;
        q.setErrorStream(0);
        q.setOutputStream(&cout);
        try{
            q.runQhull(rcube, "Tz H0");
            QFAIL("runQhull TZ did not fail.");
        }catch (const std::exception &e){
            const char *s= e.what();
            cout << "INFO   : Caught " << s;
            QCOMPARE(QString::fromLatin1(s).left(6), QString("QH6023"));
        }
        //QH11025 FIX: Qhullmessage cleared when QhullError thrown.  Switched to e
        //QVERIFY(q.hasQhullMessage());
        //QCOMPARE(QString::fromStdString(q.qhullMessage()).left(17), QString("qhull: no message"));
        //QCOMPARE(q.qhullStatus(), 6023);
        q.clearQhullMessage();
        QVERIFY(!q.hasQhullMessage());
    }
   {
        cout << "INFO   : No error stream or output stream\n";
        Qhull q;
        q.setErrorStream(0);
        q.setOutputStream(0);
        try{
            q.runQhull(rcube, "Fd");
            QFAIL("outputQhull did not fail.");
        }catch (const std::exception &e){
            const char *s= e.what();
            cout << "INFO   : Caught " << s;
            QCOMPARE(QString::fromLatin1(s).left(6), QString("QH6029"));
        }
        //QH11025 FIX: QhullMessage cleared when QhullError thrown.  Switched to e
        //QVERIFY(q.hasQhullMessage());
        //QCOMPARE(QString::fromStdString(q.qhullMessage()).left(9), QString("qhull err"));
        //QCOMPARE(q.qhullStatus(), 6029);
        q.clearQhullMessage();
        QVERIFY(!q.hasQhullMessage());
    }
}//t_message

void Qhull_test::
t_getSet()
{
    RboxPoints rcube("c");
   {
        Qhull q;
        QVERIFY(!q.initialized());
        q.runQhull(rcube, "s");
        QVERIFY(q.initialized());
        QCOMPARE(q.dimension(), 3);
        QhullPoint p= q.origin();
        QCOMPARE(p.dimension(), 3);
        QCOMPARE(p[0]+p[1]+p[2], 0.0);
        q.setErrorStream(&cout);
        q.outputQhull();
    }
   {
        Qhull q;
        q.runQhull(rcube, "");
        q.setOutputStream(&cout);
        q.outputQhull();
    }
}//t_getSet

void Qhull_test::
t_getQh()
{
    RboxPoints rcube("c");
   {
        Qhull q;
        q.runQhull(rcube, "s");
        QCOMPARE(QString(q.qhullCommand()), QString("qhull s"));
        QCOMPARE(QString(q.rboxCommand()), QString("rbox \"c\""));
        QCOMPARE(q.facetCount(), 6);
        QCOMPARE(q.vertexCount(), 8);
        // Sample fields from Qhull's qhT [libqhull.h]
        QCOMPARE(q.qh()->ALLpoints, 0u);
        QCOMPARE(q.qh()->GOODpoint, 0);
        QCOMPARE(q.qh()->IStracing, 0);
        QCOMPARE(q.qh()->MAXcoplanar+1.0, 1.0); // fuzzy compare
        QCOMPARE(q.qh()->MERGING, 1u);
        QCOMPARE(q.qh()->input_dim, 3);
        QCOMPARE(QString(q.qh()->qhull_options).left(8), QString("  run-id"));
        QCOMPARE(q.qh()->num_facets, 6);
        QCOMPARE(q.qh()->hasTriangulation, 0u);
        QCOMPARE(q.qh()->max_outside - q.qh()->min_vertex + 1.0, 1.0); // fuzzy compare
        QCOMPARE(*q.qh()->gm_matrix+1.0, 1.0); // fuzzy compare
    }
}//t_getQh

void Qhull_test::
t_getValue()
{
    RboxPoints rcube("c");
   {
        Qhull q;
        q.runQhull(rcube, "");
        QCOMPARE(q.area(), 6.0);
        QCOMPARE(q.volume(), 1.0);
    }
}//t_getValue

void Qhull_test::
t_foreach()
{
    RboxPoints rcube("c");
   {
        Qhull q;
        QCOMPARE(q.beginFacet(),q.endFacet());
        QCOMPARE(q.beginVertex(),q.endVertex());
        q.runQhull(rcube, "");
        QCOMPARE(q.facetList().count(), 6);

        // defineVertexNeighborFacets() tested in QhullVertex_test::t_io()

        QhullFacetList facets(q.beginFacet(), q.endFacet());
        QCOMPARE(facets.count(), 6);
        QCOMPARE(q.firstFacet(), q.beginFacet());
        QhullVertexList vertices(q.beginVertex(), q.endVertex());
        QCOMPARE(vertices.count(), 8);
        QCOMPARE(q.firstVertex(), q.beginVertex());
        QhullPoints ps= q.points();
        QCOMPARE(ps.count(), 8);
        QhullPointSet ps2= q.otherPoints();
        QCOMPARE(ps2.count(), 0);
        // ps2= q.otherPoints(); //disabled, would not copy the points
        QCOMPARE(q.facetCount(), 6);
        QCOMPARE(q.vertexCount(), 8);
        coordT *c= q.pointCoordinateBegin(); // of q.points()
        QVERIFY(*c==0.5 || *c==-0.5);
        coordT *c3= q.pointCoordinateEnd();
        QVERIFY(c3[-1]==0.5 || c3[-1]==-0.5);
        QCOMPARE(c3-c, 8*3);
        QhullVertexList vertexList= q.vertexList();
        QCOMPARE(vertexList.count(), 8);
    }
}//t_foreach

void Qhull_test::
t_diamond()
{
    //addPoint() tested in t_foreach
    RboxPoints diamond("d");
    Qhull q(diamond, "o");
    q.setOutputStream(&cout);
    cout << "Expecting vertexList and facetList of a 3-d diamond.\n";
    q.outputQhull();

    cout << "Expecting the same output using std::vector and Qhull classes\n";
    int dim= q.hullDimension();
    int numfacets= q.facetList().count();
    int totneighbors= numfacets*dim;  /* incorrect for non-simplicial facets, see qh_countfacets */
    cout << dim << "\n" << q.points().size() << " " << numfacets << " " << totneighbors/2 << "\n";
    std::vector > points;
    for(QhullPoint point : q.points()){
        points.push_back(point.toStdVector());
    }
    for(std::vector point : points){
        size_t n= point.size();
        for(size_t i= 0; i < n; ++i){
            if(i < n - 1){
                cout << std::setw(6) << point[i] << " ";
            }else{
                cout << std::setw(6) << point[i] << "\n";
            }
        }
    }
    QhullFacetList facets= q.facetList();
    std::vector > facetVertices;
    for(QhullFacet f : facets){
        std::vector vertices;
        if(!f.isTopOrient() && f.isSimplicial()){ /* orient the vertices like option 'o' */
            QhullVertexSet vs= f.vertices();
            vertices.push_back(vs[1].point().id());
            vertices.push_back(vs[0].point().id());
            for(int i= 2; i < (int)vs.size(); ++i){
                vertices.push_back(vs[i].point().id());
            }
        }else{  /* note: for non-simplicial facets, this code does not duplicate option 'o', see qh_facet3vertex and qh_printfacetNvertex_nonsimplicial */
            for(QhullVertex vertex : f.vertices()){
                QhullPoint p= vertex.point();
                vertices.push_back(p.id());
            }
        }
        facetVertices.push_back(vertices);
    }
    for(std::vector vertices : facetVertices){
        size_t n= vertices.size();
        cout << n << " ";
        for(size_t i= 0; i char * QTest::
toString(const std::string &s)
{
    QByteArray ba= s.c_str();
    return qstrdup(ba.data());
}
#endif

#include "moc/Qhull_test.moc"
qhull-2020.2/src/qhulltest/RboxPoints_test.cpp0000644060175106010010000001452113710657016017665 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2006-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/qhulltest/RboxPoints_test.cpp#5 $$Change: 3010 $
** $DateTime: 2020/07/30 22:14:11 $$Author: bbarber $
**
****************************************************************************/

//pre-compiled headers
#include 
#include "RoadTest.h" // QT_VERSION

#include "libqhullcpp/RboxPoints.h"
#include "libqhullcpp/QhullError.h"

using std::cout;
using std::endl;
using std::ostringstream;
using std::string;
using std::stringstream;

namespace orgQhull {

//! Test C++ interface to Rbox
//! See eg/q_test for tests of rbox commands
class RboxPoints_test : public RoadTest
{
    Q_OBJECT

#//!\name Test slots
private slots:
    void t_construct();
    void t_error();
    void t_test();
    void t_getSet();
    void t_foreach();
    void t_change();
    void t_ostream();
};

void
add_RboxPoints_test()
{
    new RboxPoints_test();  // RoadTest::s_testcases
}

void RboxPoints_test::
t_construct()
{
    RboxPoints rp;
    QCOMPARE(rp.dimension(), 0);
    QCOMPARE(rp.count(), 0);
    QVERIFY(QString::fromStdString(rp.comment()) != QString(""));
    QVERIFY(rp.isEmpty());
    QVERIFY(!rp.hasRboxMessage());
    QCOMPARE(rp.rboxStatus(), qh_ERRnone);
    QCOMPARE(QString::fromStdString(rp.rboxMessage()), QString("rbox warning: no points generated\n"));

    RboxPoints rp2("c"); // 3-d cube
    QCOMPARE(rp2.dimension(), 3);
    QCOMPARE(rp2.count(), 8);
    QCOMPARE(QString::fromStdString(rp2.comment()), QString("rbox \"c\""));
    QVERIFY(!rp2.isEmpty());
    QVERIFY(!rp2.hasRboxMessage());
    QCOMPARE(rp2.rboxStatus(), qh_ERRnone);
    QCOMPARE(QString::fromStdString(rp2.rboxMessage()), QString("rbox: OK\n"));
}//t_construct

void RboxPoints_test::
t_error()
{
    RboxPoints rp;
    try{
        rp.appendPoints("D0 c");
        QFAIL("'D0 c' did not fail.");
    }catch (const std::exception &e) {
        const char *s= e.what();
        cout << "INFO   : Caught " << s;
        QCOMPARE(QString(s).left(6), QString("QH6189"));
        QVERIFY(rp.hasRboxMessage());
        QCOMPARE(QString::fromStdString(rp.rboxMessage()).left(8), QString("rbox err"));
        QCOMPARE(rp.rboxStatus(), 6189);
        rp.clearRboxMessage();
        QVERIFY(!rp.hasRboxMessage());
    }
    try{
        RboxPoints rp2;
        rp2.setDimension(-1);
        QFAIL("setDimension(-1) did not fail.");
    }catch (const RoadError &e) {
        const char *s= e.what();
        cout << "INFO   : Caught " << s;
        QCOMPARE(QString(s).left(7), QString("QH10062"));
        QCOMPARE(e.errorCode(), 10062);
        QCOMPARE(QString::fromStdString(e.what()), QString(s));
        RoadLogEvent logEvent= e.roadLogEvent();
        QCOMPARE(logEvent.int1(), -1);
    }
}//t_error

void RboxPoints_test::
t_test()
{
    // isEmpty -- t_construct
}//t_test

void RboxPoints_test::
t_getSet()
{
    // comment -- t_construct
    // count -- t_construct
    // dimension -- t_construct

    RboxPoints rp;
    QCOMPARE(rp.dimension(), 0);
    rp.setDimension(2);
    QCOMPARE(rp.dimension(), 2);
    try{
        rp.setDimension(102);
        QFAIL("setDimension(102) did not fail.");
    }catch (const std::exception &e) {
        cout << "INFO   : Caught " << e.what();
    }
    QCOMPARE(rp.newCount(), 0);
    rp.appendPoints("D2 P1 P2");
    QCOMPARE(rp.count(), 2);
    QCOMPARE(rp.newCount(), 2); // From previous appendPoints();
    PointCoordinates pc(rp.qh(), 2, "Test qh() and <<");
    pc << 1.0 << 0.0 << 2.0 << 0.0;
    QCOMPARE(pc.dimension(), 2);
    QCOMPARE(pc.count(), 2);
    QVERIFY(rp==pc);
    rp.setNewCount(10);  // Normally only used by appendPoints for rbox processing
    QCOMPARE(rp.newCount(), 10);
    rp.reservePoints();
    QVERIFY(rp==pc);
}//t_getSet

void RboxPoints_test::
t_foreach()
{
    RboxPoints rp("c");
    Coordinates::ConstIterator cci= rp.beginCoordinates();
    orgQhull::Coordinates::Iterator ci= rp.beginCoordinates();
    QCOMPARE(*cci, -0.5);
    QCOMPARE(*ci, *cci);
    int i=1;
    while(++cci
#include "RoadTest.h" // QT_VERSION

#include 

using std::cout;
using std::endl;

namespace orgQhull {

#//!\name class variable

QList RoadTest::
s_testcases;

int RoadTest::
s_test_count= 0;

int RoadTest::
s_test_fail= 0;

QStringList RoadTest::
s_failed_tests;

#//!\name Slot

//! Executed after each test
void RoadTest::
cleanup()
{
    s_test_count++;
    if(QTest::currentTestFailed()){
        recordFailedTest();
    }
}//cleanup

#//!\name Helper

void RoadTest::
recordFailedTest()
{
    s_test_fail++;
    QString className= metaObject()->className();
    s_failed_tests << className + "::" + QTest::currentTestFunction();
}

#//!\name class function

void RoadTest::
deleteTests()
{
    foreach(RoadTest *testcase, s_testcases){
        delete testcase;
    }
    s_failed_tests.clear();
}

int RoadTest::
runTests(QStringList arguments)
{
    int result= 0; // assume success

    foreach(RoadTest *testcase, s_testcases){
        try{
            result += QTest::qExec(testcase, arguments);
        }catch(const std::exception &e){
            cout << "FAIL!  : Threw error ";
            cout << e.what() << endl;
    s_test_count++;
            testcase->recordFailedTest();
            // Qt 4.5.2 OK.  In Qt 4.3.3, qtestcase did not clear currentTestObject
        }
    }
    if(s_test_fail){
        cout << "Failed " << s_test_fail << " of " << s_test_count << " tests.\n";
        cout << s_failed_tests.join("\n").toLocal8Bit().constData() << std::endl;
    }else{
        cout << "Passed " << s_test_count << " tests.\n";
    }
    return result;
}//runTests

}//orgQhull

#include "moc/moc_RoadTest.cpp"
qhull-2020.2/src/qhulltest/RoadTest.h0000644060175106010010000000423113710651703015703 0ustar  bbarber/****************************************************************************
**
** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
** $Id: //main/2019/qhull/src/qhulltest/RoadTest.h#3 $$Change: 3009 $
** $Date: 2020/07/30 $$Author: bbarber $
**
****************************************************************************/

#ifndef ROADTEST_H
#define ROADTEST_H

//pre-compiled with RoadTest.h
#include     // Qt C++ Framework
#include 

#define QHULL_USES_QT 1

namespace orgQhull {

#//!\name Defined here

    //! RoadTest -- Generic test for Qt's QTest
    class RoadTest;
    //! TESTadd_(t) -- Add a RoadTest

/** Test Name objects using Qt's QTestLib

Template:

class Name_test : public RoadTest
{
    Q_OBJECT
#//!\name Test slot
private slots:
    void t_name();
    //Executed before any test
    void initTestCase();
    void init();          // Each test
    //Executed after each test
    void cleanup(); //RoadTest::cleanup();
    // Executed after last test
    void cleanupTestCase();
};

void
add_Name_test()
{
    new Name_test();  // RoadTest::s_testcases
}

Send additional output to cout
*/

class RoadTest : public QObject
{
    Q_OBJECT

#//!\name Class globals
protected:
    static QList
                        s_testcases;    //! List of testcases to execute.  Initialized via add_...()
    static int          s_test_count;   //! Total number of tests executed
    static int          s_test_fail;    //! Number of failed tests
    static QStringList  s_failed_tests; //! List of failed tests

#//!\name Test slots
public slots:
    void cleanup();

public:
#//!\name Constructors, etc.
                        RoadTest()  { s_testcases.append(this); }
    virtual             ~RoadTest() {} // Derived from QObject

#//!\name Helper
    void                recordFailedTest();


#//!\name Class functions
    static void         deleteTests();
    static int          runTests(QStringList arguments);

};//RoadTest

#define TESTadd_(t) extern void t(); t();


}//orgQhull

namespace QTest{

template<>
inline char *
toString(const std::string &s)
{
    return qstrdup(s.c_str());
}

}//namespace QTest

#endif //ROADTEST_H

qhull-2020.2/src/qvoronoi/0000755060175106010010000000000013724321432013632 5ustar  bbarberqhull-2020.2/src/qvoronoi/qvoronoi.c0000644060175106010010000002712213661631132015657 0ustar  bbarber/*
  ---------------------------------

   qvoronoi.c
     compute Voronoi diagrams and furthest-point Voronoi
     diagrams using qhull

   see unix.c for full interface

   Copyright (c) 1993-2020, The Geometry Center
*/

#include "libqhull/libqhull.h"

#include 
#include 
#include 
#include 
#include 

#if defined(_MSC_VER)
#include 
#define isatty _isatty
/* int _isatty(int); */

#else
int isatty(int);  /* returns 1 if stdin is a tty
                   if "Undefined symbol" this can be deleted along with call in main() */
#endif

/*---------------------------------

  qh_prompt
    long prompt for qhull

  notes:
    restricted version of libqhull.c
    same text as unix.c
    see concise prompt below
    limit maximum literal to 1800 characters
*/

/* duplicated in qvoron_f.htm and qvoronoi.htm
   QJ and Qt are deprecated, but allowed for backwards compatibility
*/
char hidden_options[]=" d n m v H U Qb QB Qc Qf Qg Qi Qm Qr Qv Qx TR E V Fa FA FC FM Fp FS Ft FV Gt Pv Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 Q10 Q11 Q15 ";

char qh_prompta[]= "\n\
qvoronoi -- compute the Voronoi diagram\n\
    http://www.qhull.org  %s\n\
\n\
input (stdin):\n\
    first lines: dimension and number of points (or vice-versa).\n\
    other lines: point coordinates, best if one point per line\n\
    comments:    start with a non-numeric character\n\
\n\
options:\n\
    Qu   - compute furthest-site Voronoi diagram\n\
\n\
Qhull control options:\n\
    Qa   - allow input with fewer or more points than coordinates\n\
    QRn  - random rotation (n=seed, n=0 time, n=-1 time/no rotate)\n\
    Qs   - search all points for the initial simplex\n\
    Qz   - add point-at-infinity to Voronoi diagram\n\
%s%s%s%s";  /* split up qh_prompt for Visual C++ */
char qh_promptb[]= "\
\n\
Qhull extra options:\n\
    QGn  - Voronoi vertices if visible from point n, -n if not\n\
    QVn  - Voronoi vertices for input point n, -n if not\n\
    Qw   - allow option warnings\n\
    Q12  - allow wide facets and wide dupridge\n\
    Q14  - merge pinched vertices that create a dupridge\n\
\n\
T options:\n\
    TFn  - report summary when n or more facets created\n\
    TI file - input file, may be enclosed in single quotes\n\
    TO file - output file, may be enclosed in single quotes\n\
    Ts   - statistics\n\
    Tv   - verify result: structure, convexity, and in-circle test\n\
    Tz   - send all output to stdout\n\
\n\
";
char qh_promptc[]= "\
Trace options:\n\
    T4   - trace at level n, 4=all, 5=mem/gauss, -1= events\n\
    Ta   - annotate output with message codes\n\
    TAn  - stop qhull after adding n vertices\n\
     TCn - stop qhull after building cone for point n\n\
     TVn - stop qhull after adding point n, -n for before\n\
    Tc   - check frequently during execution\n\
    Tf   - flush each qh_fprintf for debugging segfaults\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\
\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, summary to stdout):\n\
    p    - Voronoi vertices\n\
    s    - summary to stderr\n\
    f    - facet dump\n\
    i    - Delaunay regions (use 'Pp' to avoid warning)\n\
    o    - OFF format (dim, Voronoi vertices, and Voronoi regions)\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 output (2-d only)\n\
    Ga   - all points as dots\n\
     Gp  -  coplanar points and vertices as radii\n\
     Gv  -  vertices as spheres\n\
    Gc   - centrums\n\
    GDn  - drop dimension n in 3-d and 4-d output\n\
    Gh   - hyperplane intersections\n\
    Gi   - inner planes only\n\
     Gn  -  no planes\n\
     Go  -  outer planes only\n\
    Gr   - ridges\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\
    PFn  - keep Voronoi vertices whose 'area' is at least n\n\
    Pg   - print good Voronoi vertices (needs 'QGn' or 'QVn')\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\
    -?   - help with examples\n\
    -V   - version\n\
";
/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */

/*---------------------------------

  qh_prompt2
    synopsis for qhull
*/
char qh_prompt2[]= "\n\
qvoronoi -- compute the Voronoi diagram.  Qhull %s\n\
    input (stdin): dimension, number of points, point coordinates\n\
    comments start with a non-numeric character\n\
\n\
options (qvoronoi.htm):\n\
    Qu   - compute furthest-site Voronoi diagram\n\
    Tv   - verify result: structure, convexity, and in-circle test\n\
    .    - concise list of all options\n\
    -    - one-line description of all options\n\
    -?   - this message\n\
    -V   - version\n\
\n\
output options (subset):\n\
    Fi   - separating hyperplanes for bounded regions, 'Fo' for unbounded\n\
    FN   - count and Voronoi vertices for each Voronoi region\n\
    Fv   - Voronoi diagram as Voronoi vertices between adjacent input sites\n\
    G    - Geomview output (2-d only)\n\
    o    - OFF file format (dim, Voronoi vertices, and Voronoi regions)\n\
    p    - Voronoi vertices\n\
    QVn  - Voronoi vertices for input point n, -n if not\n\
    s    - summary of results (default)\n\
    TI file - input file, may be enclosed in single quotes\n\
    TO file - output file, may be enclosed in single quotes\n\
\n\
examples:\n\
    rbox c P0 D2 | qvoronoi s o         rbox c P0 D2 | qvoronoi Fi\n\
    rbox c P0 D2 | qvoronoi Fo          rbox c P0 D2 | qvoronoi Fv\n\
    rbox c P0 D2 | qvoronoi s Qu Fv     rbox c P0 D2 | qvoronoi Qu Fo\n\
    rbox c G1 d D2 | qvoronoi s p       rbox c P0 D2 | qvoronoi s Fv QV0\n\
\n\
";
/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */

/*---------------------------------

  qh_prompt3
    concise prompt for qhull
*/
char qh_prompt3[]= "\n\
Qhull %s\n\
Except for 'F.' and 'PG', upper-case options take an argument.\n\
\n\
 facet-dump     Geomview       i-delaunay     off-format     p-vertices\n\
 summary\n\
\n\
 Fcoincident    Fd-cdd-in      FD-cdd-out     FF-dump-xridge Fi-bounded\n\
 FIDs           Fmerges        Fneighbors     FNeigh-region  Fo-unbounded\n\
 FOptions       FPoint-near    FQvoronoi      Fsummary       Fvoronoi\n\
 Fxtremes\n\
\n\
 Gall-points    Gcentrums      GDrop-dim      Ghyperplanes   Ginner\n\
 Gno-planes     Gouter         Gpoints        Gridges        Gvertices\n\
\n\
 PArea-keep     Pdrop-d0:0D0   PFacet-area-keep  Pgood       PGood-neighbors\n\
 PMerge-keep    Poutput-forced Pprecision-not\n\
\n\
 Qallow-short   QG-vertex-good QRotate        Qsearch-all    Qupper-voronoi\n\
 QV-point-good  Qwarn-allow    Qzinfinite     Q12-allow-wide Q14-merge-pinched\n\
\n\
 TFacet-log     TInput-file    TOutput-file   Tstatistics    Tverify\n\
 Tz-stdout\n\
\n\
 T4-trace       Tannotate      TAdd-stop      Tcheck-often   TCone-stop\n\
 Tflush         TMerge-trace   TPoint-trace   TVertex-stop   TWide-trace\n\
\n\
 Angle-max      Centrum-size   Random-dist    Wide-outside\n\
";

/*---------------------------------

  main( argc, argv )
    processes the command line, calls qhull() to do the work, and exits

  design:
    initializes data structures
    reads points
    finishes initialization
    computes convex hull and other structures
    checks the result
    writes the output
    frees memory
*/
int main(int argc, char *argv[]) {
  int curlong, totlong; /* used !qh_NOmem */
  int exitcode, numpoints, dim;
  coordT *points;
  boolT ismalloc;

  QHULL_LIB_CHECK /* Check for compatible library */

  if ((argc == 1) && isatty( 0 /*stdin*/)) {
    fprintf(stdout, qh_prompt2, qh_version);
    exit(qh_ERRnone);
  }
  if (argc > 1 && *argv[1] == '-' && (*(argv[1] + 1) == '?' || *(argv[1] + 1) == '-')) { /* -? or --help */
    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);
  }
  if (argc > 1 && *argv[1] == '-' && *(argv[1]+1)=='V') {
      fprintf(stdout, "%s\n", qh_version2);
      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 NOerrexit= False;
    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);
    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(qh_ALL);
#else
  qh_freeqhull(!qh_ALL);
  qh_memfreeshort(&curlong, &totlong);
  if (curlong || totlong)
    qh_fprintf_stderr(7079, "qhull internal warning (main): did not free %d bytes of long memory(%d pieces)\n",
       totlong, curlong);
#endif
  return exitcode;
} /* main */

qhull-2020.2/src/qvoronoi/qvoronoi.pro0000644060175106010010000000034211545631652016236 0ustar  bbarber# -------------------------------------------------
# qvoronoi.pro -- Qt project file for qvoronoi.exe
# -------------------------------------------------

include(../qhull-app-c.pri)

TARGET = qvoronoi

SOURCES += qvoronoi.c
qhull-2020.2/src/qvoronoi/qvoronoi_r.c0000644060175106010010000002740313661634115016206 0ustar  bbarber/*
  ---------------------------------

   qvoronoi_r.c
     compute Voronoi diagrams and furthest-point Voronoi
     diagrams using qhull

   see unix_r.c for full interface

   Copyright (c) 1993-2020, The Geometry Center
*/

#include "libqhull_r/libqhull_r.h"

#include 
#include 
#include 
#include 
#include 

#ifdef __cplusplus
extern "C" {
  int isatty(int);
}

#elif defined(_MSC_VER)
#include 
#define isatty _isatty
/* int _isatty(int); */

#else
int isatty(int);  /* returns 1 if stdin is a tty
                   if "Undefined symbol" this can be deleted along with call in main() */
#endif

/*---------------------------------

  qh_prompt
    long prompt for qhull

  notes:
    restricted version of libqhull_r.c
    same text as unix_r.c
    see concise prompt below
    limit maximum literal to 1800 characters
*/

/* duplicated in qvoron_f.htm and qvoronoi.htm
   QJ and Qt are deprecated, but allowed for backwards compatibility
*/
char hidden_options[]=" d n m v H U Qb QB Qc Qf Qg Qi Qm Qr Qv Qx TR E V Fa FA FC FM Fp FS Ft FV Gt Pv Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 Q10 Q11 Q15 ";

char qh_prompta[]= "\n\
qvoronoi -- compute the Voronoi diagram\n\
    http://www.qhull.org  %s\n\
\n\
input (stdin):\n\
    first lines: dimension and number of points (or vice-versa).\n\
    other lines: point coordinates, best if one point per line\n\
    comments:    start with a non-numeric character\n\
\n\
options:\n\
    Qu   - compute furthest-site Voronoi diagram\n\
\n\
Qhull control options:\n\
    Qa   - allow input with fewer or more points than coordinates\n\
    QRn  - random rotation (n=seed, n=0 time, n=-1 time/no rotate)\n\
    Qs   - search all points for the initial simplex\n\
    Qz   - add point-at-infinity to Voronoi diagram\n\
%s%s%s%s";  /* split up qh_prompt for Visual C++ */
char qh_promptb[]= "\
\n\
Qhull extra options:\n\
    QGn  - Voronoi vertices if visible from point n, -n if not\n\
    QVn  - Voronoi vertices for input point n, -n if not\n\
    Qw   - allow option warnings\n\
    Q12  - allow wide facets and wide dupridge\n\
    Q14  - merge pinched vertices that create a dupridge\n\
\n\
T options:\n\
    TFn  - report summary when n or more facets created\n\
    TI file - input file, may be enclosed in single quotes\n\
    TO file - output file, may be enclosed in single quotes\n\
    Ts   - statistics\n\
    Tv   - verify result: structure, convexity, and in-circle test\n\
    Tz   - send all output to stdout\n\
\n\
";
char qh_promptc[]= "\
Trace options:\n\
    T4   - trace at level n, 4=all, 5=mem/gauss, -1= events\n\
    Ta   - annotate output with message codes\n\
    TAn  - stop qhull after adding n vertices\n\
     TCn - stop qhull after building cone for point n\n\
     TVn - stop qhull after adding point n, -n for before\n\
    Tc   - check frequently during execution\n\
    Tf   - flush each qh_fprintf for debugging segfaults\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\
\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, summary to stdout):\n\
    p    - Voronoi vertices\n\
    s    - summary to stderr\n\
    f    - facet dump\n\
    i    - Delaunay regions (use 'Pp' to avoid warning)\n\
    o    - OFF format (dim, Voronoi vertices, and Voronoi regions)\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 output (2-d only)\n\
    Ga   - all points as dots\n\
     Gp  -  coplanar points and vertices as radii\n\
     Gv  -  vertices as spheres\n\
    Gc   - centrums\n\
    GDn  - drop dimension n in 3-d and 4-d output\n\
    Gh   - hyperplane intersections\n\
    Gi   - inner planes only\n\
     Gn  -  no planes\n\
     Go  -  outer planes only\n\
    Gr   - ridges\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\
    PFn  - keep Voronoi vertices whose 'area' is at least n\n\
    Pg   - print good Voronoi vertices (needs 'QGn' or 'QVn')\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\
    -?   - help with examples\n\
    -V   - version\n\
";
/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */

/*---------------------------------

  qh_prompt2
    synopsis for qhull
*/
char qh_prompt2[]= "\n\
qvoronoi -- compute the Voronoi diagram.  Qhull %s\n\
    input (stdin): dimension, number of points, point coordinates\n\
    comments start with a non-numeric character\n\
\n\
options (qvoronoi.htm):\n\
    Qu   - compute furthest-site Voronoi diagram\n\
    Tv   - verify result: structure, convexity, and in-circle test\n\
    .    - concise list of all options\n\
    -    - one-line description of all options\n\
    -?   - this message\n\
    -V   - version\n\
\n\
output options (subset):\n\
    Fi   - separating hyperplanes for bounded regions, 'Fo' for unbounded\n\
    FN   - count and Voronoi vertices for each Voronoi region\n\
    Fv   - Voronoi diagram as Voronoi vertices between adjacent input sites\n\
    G    - Geomview output (2-d only)\n\
    o    - OFF file format (dim, Voronoi vertices, and Voronoi regions)\n\
    p    - Voronoi vertices\n\
    QVn  - Voronoi vertices for input point n, -n if not\n\
    s    - summary of results (default)\n\
    TI file - input file, may be enclosed in single quotes\n\
    TO file - output file, may be enclosed in single quotes\n\
\n\
examples:\n\
    rbox c P0 D2 | qvoronoi s o         rbox c P0 D2 | qvoronoi Fi\n\
    rbox c P0 D2 | qvoronoi Fo          rbox c P0 D2 | qvoronoi Fv\n\
    rbox c P0 D2 | qvoronoi s Qu Fv     rbox c P0 D2 | qvoronoi Qu Fo\n\
    rbox c G1 d D2 | qvoronoi s p       rbox c P0 D2 | qvoronoi s Fv QV0\n\
\n\
";
/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */

/*---------------------------------

  qh_prompt3
    concise prompt for qhull
*/
char qh_prompt3[]= "\n\
Qhull %s\n\
Except for 'F.' and 'PG', upper-case options take an argument.\n\
\n\
 facet-dump     Geomview       i-delaunay     off-format     p-vertices\n\
 summary\n\
\n\
 Fcoincident    Fd-cdd-in      FD-cdd-out     FF-dump-xridge Fi-bounded\n\
 FIDs           Fmerges        Fneighbors     FNeigh-region  Fo-unbounded\n\
 FOptions       FPoint-near    FQvoronoi      Fsummary       Fvoronoi\n\
 Fxtremes\n\
\n\
 Gall-points    Gcentrums      GDrop-dim      Ghyperplanes   Ginner\n\
 Gno-planes     Gouter         Gpoints        Gridges        Gvertices\n\
\n\
 PArea-keep     Pdrop-d0:0D0   PFacet-area-keep  Pgood       PGood-neighbors\n\
 PMerge-keep    Poutput-forced Pprecision-not\n\
\n\
 Qallow-short   QG-vertex-good QRotate        Qsearch-all    Qupper-voronoi\n\
 QV-point-good  Qwarn-allow    Qzinfinite     Q12-allow-wide Q14-merge-pinched\n\
\n\
 TFacet-log     TInput-file    TOutput-file   Tstatistics    Tverify\n\
 Tz-stdout\n\
\n\
 T4-trace       Tannotate      TAdd-stop      Tcheck-often   TCone-stop\n\
 Tflush         TMerge-trace   TPoint-trace   TVertex-stop   TWide-trace\n\
\n\
 Angle-max      Centrum-size   Random-dist    Wide-outside\n\
";

/*---------------------------------

  main( argc, argv )
    processes the command line, calls qhull() to do the work, and exits

  design:
    initializes data structures
    reads points
    finishes initialization
    computes convex hull and other structures
    checks the result
    writes the output
    frees memory
*/
int main(int argc, char *argv[]) {
  int curlong, totlong; /* used !qh_NOmem */
  int exitcode, numpoints, dim;
  coordT *points;
  boolT ismalloc;
  qhT qh_qh;
  qhT *qh= &qh_qh;

  QHULL_LIB_CHECK /* Check for compatible library */

  if ((argc == 1) && isatty( 0 /*stdin*/)) {
    fprintf(stdout, qh_prompt2, qh_version);
    exit(qh_ERRnone);
  }
  if (argc > 1 && *argv[1] == '-' && (*(argv[1] + 1) == '?' || *(argv[1] + 1) == '-')) { /* -? or --help */
    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);
  }
  if (argc > 1 && *argv[1] == '-' && *(argv[1]+1)=='V') {
      fprintf(stdout, "%s\n", qh_version2);
      exit(qh_ERRnone);
  }
  qh_init_A(qh, stdin, stdout, stderr, argc, argv);  /* sets qh->qhull_command */
  exitcode= setjmp(qh->errexit); /* simple statement for CRAY J916 */
  if (!exitcode) {
    qh->NOerrexit= False;
    qh_option(qh, "voronoi  _bbound-last  _coplanar-keep", NULL, NULL);
    qh->DELAUNAY= True;     /* 'v'   */
    qh->VORONOI= True;
    qh->SCALElast= True;    /* 'Qbb' */
    qh_checkflags(qh, qh->qhull_command, hidden_options);
    qh_initflags(qh, qh->qhull_command);
    points= qh_readpoints(qh, &numpoints, &dim, &ismalloc);
    qh_init_B(qh, points, numpoints, dim, ismalloc);
    qh_qhull(qh);
    qh_check_output(qh);
    qh_produce_output(qh);
    if (qh->VERIFYoutput && !qh->FORCEoutput && !qh->STOPpoint && !qh->STOPcone)
      qh_check_points(qh);
    exitcode= qh_ERRnone;
  }
  qh->NOerrexit= True;  /* no more setjmp */
#ifdef qh_NOmem
  qh_freeqhull(qh, qh_ALL);
#else
  qh_freeqhull(qh, !qh_ALL);
  qh_memfreeshort(qh, &curlong, &totlong);
  if (curlong || totlong)
    qh_fprintf_stderr(7079, "qhull internal warning (main): did not free %d bytes of long memory(%d pieces)\n",
       totlong, curlong);
#endif
  return exitcode;
} /* main */

qhull-2020.2/src/rbox/0000755060175106010010000000000013724321433012731 5ustar  bbarberqhull-2020.2/src/rbox/rbox.c0000644060175106010010000000714513562152300014051 0ustar  bbarber/*
  ---------------------------------

   rbox.c
     rbox program for generating input points for qhull.

   notes:
     50 points generated for 'rbox D4'

*/

#include "libqhull/libqhull.h"
#include "libqhull/random.h"

#include 
#include 
#include 
#include 

#ifdef _MSC_VER  /* Microsoft Visual C++ -- warning level 4 */
#pragma warning( disable : 4706)  /* assignment within conditional function */
#endif

char prompt[]= "\n\
rbox -- generate various point distributions.  Default is random in cube.\n\
\n\
args (any order, space separated):                    Version: 2019/11/10\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\
  Cn,r,m  add n nearly adjacent points within radius r of m points\n\
  Pn,m,r  add point [n,m,r] first, pads with 0, maybe repeated\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\
";
/* Not including 'V' for rbox version, clumsy coordination with rboxlib.c */

/*--------------------------------------------
-rbox-  main procedure of rbox application
*/
int main(int argc, char **argv) {
  char *command;
  int command_size;
  int return_status;

  QHULL_LIB_CHECK_RBOX

  if (argc == 1) {
    printf(prompt, qh_DEFAULTbox, qh_DEFAULTzbox);
    return qh_ERRnone;
  }
  if (argc == 2 && strcmp(argv[1], "D4")==0)
    qh_fprintf_stderr(0, "\nStarting the rbox smoketest for qhull.  An immediate failure indicates\nthat non-reentrant rbox was linked to reentrant routines.  An immediate\nfailure of qhull may indicate that qhull was linked to the wrong\nqhull library.  Also try 'rbox D4 | qhull T1'\n");

  command_size= qh_argv_to_command_size(argc, argv);
  if (command_size < 1) {
    qh_fprintf_stderr(6419, "rbox internal error: expecting qh_argv_to_command_size >= 1.  Got %d.  Exit with error\n", command_size);
    return_status= qh_ERRqhull;
  }else if ((command= (char *)qh_malloc((size_t)command_size))) {
    if (!qh_argv_to_command(argc, argv, command, command_size)) {
      qh_fprintf_stderr(6264, "rbox internal error: allocated insufficient memory (%d) for arguments\n", command_size);
      return_status= qh_ERRqhull;
    }else {
      return_status= qh_rboxpoints(stdout, stderr, command);
    }
    qh_free(command);
  }else {
    qh_fprintf_stderr(6265, "rbox error: insufficient memory for %d bytes\n", command_size);
    return_status= qh_ERRmem;
  }
  return return_status;
}/*main*/

qhull-2020.2/src/rbox/rbox.pro0000644060175106010010000000034112500174704014421 0ustar  bbarber# -------------------------------------------------
# rbox.pro -- Qt project for rbox.exe with libqhullstatic
# -------------------------------------------------

include(../qhull-app-c.pri)

TARGET = rbox

SOURCES += rbox.c
qhull-2020.2/src/rbox/rbox_r.c0000644060175106010010000000612713562152334014400 0ustar  bbarber
/*
  ---------------------------------

   rbox_r.c
     rbox program for generating input points for qhull.

   notes:
     50 points generated for 'rbox D4'

*/

#include "libqhull_r/libqhull_r.h"
#include "libqhull_r/random_r.h"

#include 
#include 
#include 
#include 

#ifdef _MSC_VER  /* Microsoft Visual C++ -- warning level 4 */
#pragma warning( disable : 4706)  /* assignment within conditional function */
#endif

char prompt[]= "\n\
rbox -- generate various point distributions.  Default is random in cube.\n\
\n\
args (any order, space separated):                    Version: 2019/11/10\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\
  Cn,r,m  add n nearly adjacent points within radius r of m points\n\
  Pn,m,r  add point [n,m,r] first, pads with 0, maybe repeated\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\
";
/* Not including 'V' for rbox version, clumsy coordination with rboxlib_r.c */

/*--------------------------------------------
-rbox-  main procedure of rbox application
*/
int main(int argc, char **argv) {
  char *command;
  int command_size;
  int return_status;
  qhT qh_qh;
  qhT *qh= &qh_qh;

  QHULL_LIB_CHECK_RBOX

  if (argc == 1) {
    printf(prompt, qh_DEFAULTbox, qh_DEFAULTzbox);
    return qh_ERRnone;
  }
  if (argc == 2 && strcmp(argv[1], "D4")==0)
    qh_fprintf_stderr(0, "\nStarting the rbox smoketest for qhull.  An immediate failure indicates\nthat reentrant rbox was linked to non-reentrant routines.  An immediate\nfailure of qhull may indicate that qhull was linked to the wrong\nqhull library.  Also try 'rbox D4 | qhull T1'\n");

  qh_init_A(qh, stdin, stdout, stderr, argc, argv);  /*no qh_errexit, sets qh->qhull_command */
  return_status= qh_rboxpoints(qh, qh->qhull_command); /* Traps its own errors, qh_errexit_rbox() */
  return return_status;
}/*main*/

qhull-2020.2/src/testqset/0000755060175106010010000000000013724321433013633 5ustar  bbarberqhull-2020.2/src/testqset/testqset.c0000644060175106010010000010507113661631132015657 0ustar  bbarber/*
  ---------------------------------

   testset.c -- test qset.c and its use of mem.c

   The test sets are pointers to int.  Normally a set is a pointer to a type (e.g., facetT, ridgeT, etc.).
   For consistency in notation, an "int" is typedef'd to i2T

Functions and macros from qset.h.  Counts occurrences in this test.  Does not correspond to thoroughness.
    qh_setaddsorted -- 4 tests
    qh_setaddnth -- 1 test
    qh_setappend -- 7 tests
    qh_setappend_set -- 1 test
    qh_setappend2ndlast -- 1 test
    qh_setcheck -- lots of tests
    qh_setcompact -- 7 tests
    qh_setcopy -- 3 tests
    qh_setdel -- 1 tests
    qh_setdellast -- 1 tests
    qh_setdelnth -- 2 tests
    qh_setdelnthsorted -- 2 tests
    qh_setdelsorted -- 1 test
    qh_setduplicate -- not testable here
    qh_setequal -- 4 tests
    qh_setequal_except -- 2 tests
    qh_setequal_skip -- 2 tests
    qh_setfree -- 11+ tests
    qh_setfree2 -- not testable here
    qh_setfreelong -- 2 tests
    qh_setin -- 3 tests
    qh_setindex -- 4 tests
    qh_setlarger -- 1 test
    qh_setlast -- 2 tests
    qh_setnew -- 6 tests
    qh_setnew_delnthsorted
    qh_setprint -- tested elsewhere
    qh_setreplace -- 1 test
    qh_setsize -- 9+ tests
    qh_settemp -- 2 tests
    qh_settempfree -- 1 test
    qh_settempfree_all -- 1 test
    qh_settemppop -- 1 test
    qh_settemppush -- 1 test
    qh_settruncate -- 3 tests
    qh_setunique -- 3 tests
    qh_setzero -- 1 test
    FOREACHint_ -- 2 test
    FOREACHint4_
    FOREACHint_i_ -- 1 test
    FOREACHintreverse_
    FOREACHintreverse12_
    FOREACHsetelement_ -- 1 test
    FOREACHsetelement_i_ -- 1 test
    FOREACHsetelementreverse_ -- 1 test
    FOREACHsetelementreverse12_ -- 1 test
    SETelem_ -- 3 tests
    SETelemaddr_ -- 2 tests
    SETelemt_ -- not tested (generic)
    SETempty_ -- 1 test
    SETfirst_ -- 4 tests
    SETfirstt_ -- 2 tests
    SETindex_ -- 2 tests
    SETref_ -- 2 tests
    SETreturnsize_ -- 2 tests
    SETsecond_ -- 1 test
    SETsecondt_ -- 2 tests
    SETtruncate_ -- 2 tests

    Copyright (c) 2012-2020 C.B. Barber. All rights reserved.
    $Id: //main/2019/qhull/src/testqset/testqset.c#7 $$Change: 2953 $
    $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
*/

#include "libqhull/user.h"  /* QHULL_CRTDBG */
#include "libqhull/qset.h"
#include "libqhull/mem.h"

#include 
#include 
#include 
#include 

typedef int i2T;
#define MAXerrorCount 100 /* quit after n errors */

#define FOREACHint_( ints ) FOREACHsetelement_(i2T, ints, i2)
#define FOREACHint_i_(ints) FOREACHsetelement_i_(i2T, ints, i2)
/* not tested -- #define FOREACHint4_( ints ) FOREACHsetelement_(i2T, ints, i4) */
/* not tested -- #define FOREACHintreverse_(ints) FOREACHsetelementreverse_(i2T, ints, i2) */
/* not tested -- #define FOREACHintreverse12_( ints ) FOREACHsetelementreverse12_(i2T, ints, i2) */

enum {
    MAXint= 0x7fffffff
};

char prompt[]= "testqset N [M] [T5] -- Test non-rentrant qset.c and mem.c\n\
  \n\
  If this test fails then non-rentrant Qhull will not work.\n\
  \n\
  Test qsets of 0..N integers with a check every M iterations (default ~log10)\n\
  Additional checking and logging if M is 1\n\
  \n\
  T5 turns on memory logging (qset does not log)\n\
  \n\
  For example:\n\
    testqset 10000\n\
";

int error_count= 0;  /* Global error_count.  checkSetContents() keeps its own error count.  It exits on too many errors */

/* Macros normally defined in geom.h */
#define fmax_( a,b )  ( ( a ) < ( b ) ? ( b ) : ( a ) )

/* Macros normally defined in user.h */

#define realT double
#define qh_ERRinput 1    /* input inconsistency */
#define qh_ERRmem   4    /* insufficient memory, matches mem.h */
#define qh_ERRqhull 5    /* internal error detected, matches mem.h, calls qh_printhelp_internal */
#define qh_MEMalign ((int)(fmax_(sizeof(realT), sizeof(void *))))
#define qh_MEMbufsize 0x10000       /* allocate 64K memory buffers */
#define qh_MEMinitbuf 0x20000      /* initially allocate 128K buffer */

/* Macros normally defined in QhullSet.h */

/* Functions normally defined in user.h for usermem.c */

void    qh_exit(int exitcode);
void    qh_fprintf_stderr(int msgcode, const char *fmt, ... );
void    qh_free(void *mem);
void   *qh_malloc(size_t size);

/* Normally defined in user.c, use void instead of facetT/ridgeT for testqset.c */

void    qh_errexit(int exitcode, void *f, void *r);
void    qh_errexit(int exitcode, void *f, void *r)
{
    (void)f; /* unused */
    (void)r; /* unused */
    qh_exit(exitcode);
}

/* Normally defined in userprintf.c */

void    qh_fprintf(FILE *fp, int msgcode, const char *fmt, ... );
void    qh_fprintf(FILE *fp, int msgcode, const char *fmt, ... )
{
    static int needs_cr= 0;  /* True if qh_fprintf needs a CR. testqset is not itself reentrant */

    size_t fmtlen= strlen(fmt);
    va_list args;

    if (!fp) {
        /* Do not use qh_fprintf_stderr.  This is a standalone program */
        fprintf(stderr, "QH6232 testqset (qh_fprintf): fp not defined for '%s'\n", fmt);
        qh_errexit(qh_ERRqhull, NULL, NULL);
    }
    if(fmtlen>0){
        if(fmt[fmtlen-1]=='\n'){
            if(needs_cr && fmtlen>1){
                fprintf(fp, "\n");
            }
            needs_cr= 0;
        }else{
            needs_cr= 1;
        }
    }
    if(msgcode>=6000 && msgcode<7000){
        fprintf(fp, "Error QH%d ", msgcode);
    }
    va_start(args, fmt);
    vfprintf(fp, fmt, args);
    va_end(args);
}

/* Defined below in order of use */
int main(int argc, char **argv);
void readOptions(int argc, char **argv, const char *promptstr, int *numInts, int *checkEvery, int *traceLevel);
void setupMemory(int tracelevel, int numInts, int **intarray);

void testSetappendSettruncate(int numInts, int *intarray, int checkEvery);
void testSetdelSetadd(int numInts, int *intarray, int checkEvery);
void testSetappendSet(int numInts, int *intarray, int checkEvery);
void testSetcompactCopy(int numInts, int *intarray, int checkEvery);
void testSetequalInEtc(int numInts, int *intarray, int checkEvery);
void testSettemp(int numInts, int *intarray, int checkEvery);
void testSetlastEtc(int numInts, int *intarray, int checkEvery);
void testSetdelsortedEtc(int numInts, int *intarray, int checkEvery);

int log_i(setT *set, const char *s, int i, int numInts, int checkEvery);
void checkSetContents(const char *name, setT *set, int count, int rangeA, int rangeB, int rangeC);

int main(int argc, char **argv) {
    int *intarray= NULL;
    int numInts;
    int checkEvery= MAXint;
    int curlong, totlong;  /* used if !qh_NOmem */
    int traceLevel= 4; /* 4 normally, no tracing since qset does not log.  Option 'T5' for memory tracing */


#if defined(_MSC_VER) && defined(_DEBUG) && defined(QHULL_CRTDBG)  /* user.h */
    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_DELAY_FREE_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) );
    _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG );
    _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR );
#endif

    readOptions(argc, argv, prompt, &numInts, &checkEvery, &traceLevel);
    setupMemory(traceLevel, numInts, &intarray);

    testSetappendSettruncate(numInts, intarray, checkEvery);
    testSetdelSetadd(numInts, intarray, checkEvery);
    testSetappendSet(numInts, intarray, checkEvery);
    testSetcompactCopy(numInts, intarray, checkEvery);
    testSetequalInEtc(numInts, intarray, checkEvery);
    testSettemp(numInts, intarray, checkEvery);
    testSetlastEtc(numInts, intarray, checkEvery);
    testSetdelsortedEtc(numInts, intarray, checkEvery);
    qh_fprintf(stderr, 8083, "\nNot testing qh_setduplicate and qh_setfree2.  These routines use heap-allocated,\n\
set contents.  See qhull tests in eg/q_test and bin/qhulltest.\n\n");

    qh_memstatistics(stderr);
#ifndef qh_NOmem
    qh_memfreeshort(&curlong, &totlong);
    if (curlong || totlong){
        qh_fprintf(stderr, 8084, "testqset: did not free %d bytes of long memory(%d pieces)\n", totlong, curlong);
        error_count++;
    }
#endif
    fflush(NULL);
    if(error_count){
        qh_fprintf(stderr, 8088, "testqset: %d errors\n\n", error_count);
        exit(qh_ERRqhull);
    }else{
        printf("testqset: OK\n\n");
    }
    return 0;
}/*main*/

void readOptions(int argc, char **argv, const char *promptstr, int *numInts, int *checkEvery, int *traceLevel)
{
    long numIntsArg;
    long checkEveryArg;
    char *endp;
    int isTracing= 0;

    if (argc < 2 || argc > 4) {
        printf("%s", promptstr);
        exit(0);
    }
    numIntsArg= strtol(argv[1], &endp, 10);
    if(numIntsArg<1){
        qh_fprintf(stderr, 6301, "testqset: First argument should be 1 or greater.  Got '%s'\n", argv[1]);
        exit(qh_ERRinput);
    }
    if(numIntsArg>MAXint){
        qh_fprintf(stderr, 6302, "testqset: qset does not currently support 64-bit ints.  Maximum count is %d\n", MAXint);
        exit(qh_ERRinput);
    }
    *numInts= (int)numIntsArg;

    if(argc==3 && argv[2][0]=='T' && argv[2][1]=='5' ){
        isTracing= 1;
        *traceLevel= 5;
    }
    if(argc==4 || (argc==3 && !isTracing)){
        checkEveryArg= strtol(argv[2], &endp, 10);
        if(checkEveryArg<1){
            qh_fprintf(stderr, 6321, "testqset: checkEvery argument should be 1 or greater.  Got '%s'\n", argv[2]);
            exit(qh_ERRinput);
        }
        if(checkEveryArg>MAXint){
            qh_fprintf(stderr, 6322, "testqset: qset does not currently support 64-bit ints.  Maximum checkEvery is %d\n", MAXint);
            exit(qh_ERRinput);
        }
        if(argc==4){
            if(argv[3][0]=='T' && argv[3][1]=='5' ){
                isTracing= 1;
                *traceLevel= 5;
            }else{
                qh_fprintf(stderr, 6242, "testqset: Optional third argument must be 'T5'.  Got '%s'\n", argv[3]);
                exit(qh_ERRinput);
            }
        }
        *checkEvery= (int)checkEveryArg;
    }
}/*readOptions*/

void setupMemory(int tracelevel, int numInts, int **intarray)
{
    int i;
    if(numInts<0 || numInts*(int)sizeof(int)<0){
        qh_fprintf(stderr, 6303, "testqset: qset does not currently support 64-bit ints.  Integer overflow\n");
        exit(qh_ERRinput);
    }
    *intarray= (int *)qh_malloc((unsigned int)numInts * sizeof(int));
    if(!*intarray){
        qh_fprintf(stderr, 6304, "testqset: Failed to allocate %d bytes of memory\n", numInts * (int)sizeof(int));
        exit(qh_ERRmem);
    }
    for(i= 0; i=2){
        isCheck= log_i(ints, "n", numInts/2, numInts, checkEvery);
        qh_settruncate(ints, numInts/2);
        checkSetContents("qh_settruncate by half", ints, numInts/2, 0, -1, -1);
    }
    isCheck= log_i(ints, "n", 0, numInts, checkEvery);
    qh_settruncate(ints, 0);
    checkSetContents("qh_settruncate", ints, 0, -1, -1, -1);

    qh_fprintf(stderr, 8122, "\n\nTesting qh_setappend2ndlast 0,0..%d.  Test 0", numInts-1);
    qh_setfree(&ints);
    ints= qh_setnew(4);
    qh_setappend(&ints, intarray+0);
    for(i= 0; i=2){
        isCheck= log_i(ints, "n", numInts/2, numInts, checkEvery);
        SETtruncate_(ints, numInts/2);
        checkSetContents("SETtruncate_ by half", ints, numInts/2, 0, -1, -1);
    }
    isCheck= log_i(ints, "n", 0, numInts, checkEvery);
    SETtruncate_(ints, 0);
    checkSetContents("SETtruncate_", ints, 0, -1, -1, -1);

    qh_setfree(&ints);
}/*testSetappendSettruncate*/

void testSetdelSetadd(int numInts, int *intarray, int checkEvery)
{
    setT *ints=qh_setnew(1);
    int i,j,isCheck;

    qh_fprintf(stderr, 8147, "\n\nTesting qh_setdelnthsorted and qh_setaddnth 1..%d. Test", numInts-1);
    for(j=1; j3){
                qh_setdelsorted(ints, intarray+i/2);
                checkSetContents("qh_setdelsorted", ints, j-1, 0, i/2+1, -1);
                qh_setaddsorted(&ints, intarray+i/2);
                checkSetContents("qh_setaddsorted i/2", ints, j, 0, 0, -1);
            }
            qh_setdellast(ints);
            checkSetContents("qh_setdellast", ints, (j ? j-1 : 0), 0, -1, -1);
            if(j>0){
                qh_setaddsorted(&ints, intarray+j-1);
                checkSetContents("qh_setaddsorted j-1", ints, j, 0, -1, -1);
            }
            if(j>4){
                qh_setdelnthsorted(ints, i/2);
                if (checkEvery==1)
                  checkSetContents("qh_setdelnthsorted", ints, j-1, 0, i/2+1, -1);
                /* test qh_setdelnth and move-to-front */
                qh_setdelsorted(ints, intarray+i/2+1);
                checkSetContents("qh_setdelsorted 2", ints, j-2, 0, i/2+2, -1);
                qh_setaddsorted(&ints, intarray+i/2+1);
                if (checkEvery==1)
                  checkSetContents("qh_setaddsorted i/2+1", ints, j-1, 0, i/2+1, -1);
                qh_setaddsorted(&ints, intarray+i/2);
                checkSetContents("qh_setaddsorted i/2 again", ints, j, 0, -1, -1);
            }
            qh_setfree(&ints2);
            ints2= qh_setcopy(ints, 0);
            qh_setcompact(ints);
            qh_setcompact(ints2);
            checkSetContents("qh_setcompact", ints, j, 0, 0, -1);
            checkSetContents("qh_setcompact 2", ints2, j, 0, 0, -1);
            qh_setcompact(ints);
            checkSetContents("qh_setcompact 3", ints, j, 0, 0, -1);
            qh_setfree(&ints2);
        }
    }
    qh_setfreelong(&ints);
    if(ints){
        qh_setfree(&ints); /* Was quick memory */
    }
}/*testSetdelsortedEtc*/

void testSetequalInEtc(int numInts, int *intarray, int checkEvery)
{
    setT *ints= NULL;
    setT *ints2= NULL;
    setT *ints3= NULL;
    int i,j,n;

    qh_fprintf(stderr, 8151, "\n\nTesting qh_setequal*, qh_setin*, qh_setdel, qh_setdelnth, and qh_setlarger 0..%d. Test", numInts-1);
    for(j=0; j0){
                if(qh_setequal(ints, ints2)){
                    qh_fprintf(stderr, 6324, "testqset (testSetequalInEtc): non-empty set equal to empty set\n", j);
                    error_count++;
                }
                qh_setfree(&ints3);
                ints3= qh_setcopy(ints, 0);
                checkSetContents("qh_setreplace", ints3, j, 0, -1, -1);
                qh_setreplace(ints3, intarray+j/2, intarray+j/2+1);
                if(j==1){
                    checkSetContents("qh_setreplace 2", ints3, j, j/2+1, -1, -1);
                }else if(j==2){
                    checkSetContents("qh_setreplace 3", ints3, j, 0, j/2+1, -1);
                }else{
                    checkSetContents("qh_setreplace 3", ints3, j, 0, j/2+1, j/2+1);
                }
                if(qh_setequal(ints, ints3)){
                    qh_fprintf(stderr, 6325, "testqset (testSetequalInEtc): modified set equal to original set at %d/2\n", j);
                    error_count++;
                }
                if(!qh_setequal_except(ints, intarray+j/2, ints3, intarray+j/2+1)){
                    qh_fprintf(stderr, 6326, "testqset (qh_setequal_except): modified set not equal to original set except modified\n", j);
                    error_count++;
                }
                if(qh_setequal_except(ints, intarray+j/2, ints3, intarray)){
                    qh_fprintf(stderr, 6327, "testqset (qh_setequal_except): modified set equal to original set with wrong excepts\n", j);
                    error_count++;
                }
                if(!qh_setequal_skip(ints, j/2, ints3, j/2)){
                    qh_fprintf(stderr, 6328, "testqset (qh_setequal_skip): modified set not equal to original set except modified\n", j);
                    error_count++;
                }
                if(j>2 && qh_setequal_skip(ints, j/2, ints3, 0)){
                    qh_fprintf(stderr, 6329, "testqset (qh_setequal_skip): modified set equal to original set with wrong excepts\n", j);
                    error_count++;
                }
                if(intarray+j/2+1!=qh_setdel(ints3, intarray+j/2+1)){
                    qh_fprintf(stderr, 6330, "testqset (qh_setdel): failed to find added element\n", j);
                    error_count++;
                }
                checkSetContents("qh_setdel", ints3, j-1, 0, j-1, (j==1 ? -1 : j/2+1));  /* swaps last element with deleted element */
                if(j>3){
                    qh_setdelnth(ints3, j/2); /* Delete at the same location as the original replace, for only one out-of-order element */
                    checkSetContents("qh_setdelnth", ints3, j-2, 0, j-2, (j==2 ? -1 : j/2+1));
                }
                if(qh_setin(ints3, intarray+j/2)){
                    qh_fprintf(stderr, 6331, "testqset (qh_setin): found deleted element\n");
                    error_count++;
                }
                if(j>4 && !qh_setin(ints3, intarray+1)){
                    qh_fprintf(stderr, 6332, "testqset (qh_setin): did not find second element\n");
                    error_count++;
                }
                if(j>4 && !qh_setin(ints3, intarray+j-2)){
                    qh_fprintf(stderr, 6333, "testqset (qh_setin): did not find last element\n");
                    error_count++;
                }
                if(-1!=qh_setindex(ints2, intarray)){
                    qh_fprintf(stderr, 6334, "testqset (qh_setindex): found element in empty set\n");
                    error_count++;
                }
                if(-1!=qh_setindex(ints3, intarray+j/2)){
                    qh_fprintf(stderr, 6335, "testqset (qh_setindex): found deleted element in set\n");
                    error_count++;
                }
                if(0!=qh_setindex(ints, intarray)){
                    qh_fprintf(stderr, 6336, "testqset (qh_setindex): did not find first in set\n");
                    error_count++;
                }
                if(j-1!=qh_setindex(ints, intarray+j-1)){
                    qh_fprintf(stderr, 6337, "testqset (qh_setindex): did not find last in set\n");
                    error_count++;
                }
            }
            qh_setfree(&ints2);
        }
    }
    qh_setfree(&ints3);
    qh_setfreelong(&ints);
    if(ints){
        qh_setfree(&ints); /* Was quick memory */
    }
}/*testSetequalInEtc*/


void testSetlastEtc(int numInts, int *intarray, int checkEvery)
{
    setT *ints= NULL;
    setT *ints2= NULL;
    int i,j,prepend;

    qh_fprintf(stderr, 8152, "\n\nTesting qh_setlast, qh_setnew_delnthsorted, qh_setunique, and qh_setzero 0..%d. Test", numInts-1);
    for(j=0; j0){
                if(intarray+j-1!=qh_setlast(ints)){
                    qh_fprintf(stderr, 6338, "testqset (qh_setlast): wrong last element\n");
                    error_count++;
                }
                prepend= (j<100 ? j/4 : 0);
                ints2= qh_setnew_delnthsorted(ints, qh_setsize(ints), j/2, prepend);
                if(qh_setsize(ints2)!=j+prepend-1){
                    qh_fprintf(stderr, 6345, "testqset (qh_setnew_delnthsorted): Expecting %d elements, got %d\n", j+prepend-1, qh_setsize(ints2));
                    error_count++;
                }
                /* Define prepended elements.  Otherwise qh_setdelnthsorted may fail */
                for(i= 0; i2){
                    qh_setzero(ints2, j/2, j-1);  /* max size may be j-1 */
                    if(qh_setsize(ints2)!=j-1){
                        qh_fprintf(stderr, 6342, "testqset (qh_setzero): Expecting %d elements, got %d\n", j, qh_setsize(ints2));
                        error_count++;
                    }
                    qh_setcompact(ints2);
                    checkSetContents("qh_setzero", ints2, j/2, 0, -1, -1);
                }
            }
            qh_setfree(&ints2);
        }
    }
    qh_setfreelong(&ints);
    if(ints){
        qh_setfree(&ints); /* Was quick memory */
    }
}/*testSetlastEtc*/

void testSettemp(int numInts, int *intarray, int checkEvery)
{
    setT *ints= NULL;
    setT *ints2= NULL;
    setT *ints3= NULL;
    int i,j;

    qh_fprintf(stderr, 8153, "\n\nTesting qh_settemp* 0..%d. Test", numInts-1);
    for(j=0; j0){
                qh_settemppush(ints);
                ints3= qh_settemppop();
                if(ints!=ints3){
                    qh_fprintf(stderr, 6343, "testqset (qh_settemppop): didn't pop the push\n");
                    error_count++;
                }
            }
            qh_settempfree(&ints2);
        }
    }
    qh_setfreelong(&ints);
    if(ints){
        qh_setfree(&ints); /* Was quick memory */
    }
}/*testSettemp*/

/* Check that a set contains count elements
   Ranges are consecutive (e.g., 1,2,3,...) starting with first, mid, and last
   Use -1 for missing ranges
   Returns -1 if should check results
*/
int log_i(setT *set, const char *s, int i, int numInts, int checkEvery)
{
    int j= i;
    int scale= 1;
    int e= 0;
    int *i2, **i2p;

    if(*s || checkEvery==1){
        if(i<10){
            qh_fprintf(stderr, 8154, " %s%d", s, i);
        }else{
            if(i==11 && checkEvery==1){
                qh_fprintf(stderr, 8155, "\nResults after 10: ");
                FOREACHint_(set){
                    qh_fprintf(stderr, 8156, " %d", *i2);
                }
                qh_fprintf(stderr, 8157, " Continue");
            }
            while((j= j/10)>=1){
                scale *= 10;
                e++;
            }
            if(i==numInts-1){
                qh_fprintf(stderr, 8158, " %s%d", s, i);
            }else if(i==scale){
                if(i<=1000){
                    qh_fprintf(stderr, 8159, " %s%d", s, i);
                }else{
                    qh_fprintf(stderr, 8160, " %s1e%d", s, e);
                }
            }
        }
    }
    if(i<1000 || i%checkEvery==0 || i== scale || i==numInts-1){
        return 1;
    }
    return 0;
}/*log_i*/

/* Check that a set contains count elements
   Ranges are consecutive (e.g., 1,2,3,...) starting with first, mid, and last
   Use -1 for missing ranges
*/
void checkSetContents(const char *name, setT *set, int count, int rangeA, int rangeB, int rangeC)
{

    i2T *i2, **i2p;
    int i2_i, i2_n;
    int prev= -1; /* avoid warning */
    int i;
    int first= -3;
    int second= -3;
    int rangeCount=1;
    int actualSize= 0;

    qh_setcheck(set, name, 0);
    if(set){
        SETreturnsize_(set, actualSize);  /* normally used only when speed is critical */
        if(*qh_setendpointer(set)!=NULL){
            qh_fprintf(stderr, 6344, "testqset (%s): qh_setendpointer(set), 0x%x, is not NULL terminator of set 0x%x\n", name, qh_setendpointer(set), set);
            error_count++;
        }
    }
    if(actualSize!=qh_setsize(set)){
        qh_fprintf(stderr, 6305, "testqset (%s): SETreturnsize_() returned %d while qh_setsize() returns %d\n", name, actualSize, qh_setsize(set));
        error_count++;
    }else if(actualSize!=count){
        qh_fprintf(stderr, 6306, "testqset (%s): Expecting %d elements for set.  Got %d elements\n", name, count, actualSize);
        error_count++;
    }
    if(SETempty_(set)){
        if(count!=0){
            qh_fprintf(stderr, 6307, "testqset (%s): Got empty set instead of count %d, rangeA %d, rangeB %d, rangeC %d\n", name, count, rangeA, rangeB, rangeC);
            error_count++;
        }
    }else{
        /* Must be first, otherwise trips msvc 8 */
        i2T **p= SETaddr_(set, i2T);
        if(*p!=SETfirstt_(set, i2T)){
            qh_fprintf(stderr, 6309, "testqset (%s): SETaddr_(set, i2t) [%p] is not the same as SETfirst_(set) [%p]\n", name, SETaddr_(set, i2T), SETfirst_(set));
            error_count++;
        }
        first= *(int *)SETfirst_(set);
        if(SETfirst_(set)!=SETfirstt_(set, i2T)){
            qh_fprintf(stderr, 6308, "testqset (%s): SETfirst_(set) [%p] is not the same as SETfirstt_(set, i2T [%p]\n", name, SETfirst_(set), SETfirstt_(set, i2T));
            error_count++;
        }
        if(qh_setsize(set)>1){
            second= *(int *)SETsecond_(set);
            if(SETsecond_(set)!=SETsecondt_(set, i2T)){
                qh_fprintf(stderr, 6310, "testqset (%s): SETsecond_(set) [%p] is not the same as SETsecondt_(set, i2T) [%p]\n", name, SETsecond_(set), SETsecondt_(set, i2T));
                error_count++;
            }
        }
    }
    /* Test first run of ints in set*/
    i= 0;
    FOREACHint_(set){
        if(i2!=SETfirst_(set) && *i2!=prev+1){
            break;
        }
        prev= *i2;
        if(SETindex_(set, i2)!=i){
            qh_fprintf(stderr, 6311, "testqset (%s): Expecting SETindex_(set, pointer-to-%d) to be %d.  Got %d\n", name, *i2, i, SETindex_(set, i2));
            error_count++;;
        }
        if(i2!=SETref_(i2)){
            qh_fprintf(stderr, 6312, "testqset (%s): SETref_(i2) [%p] does not point to i2 (the %d'th element)\n", name, SETref_(i2), i);
            error_count++;;
        }
        i++;
    }
    FOREACHint_i_(set){
        /* Must be first conditional, otherwise it trips up msvc 8 */
        i2T **p= SETelemaddr_(set, i2_i, i2T);
        if(i2!=*p){
            qh_fprintf(stderr, 6320, "testqset (%s): SETelemaddr_(set, %d, i2T) [%p] does not point to i2\n", name, i2_i, SETelemaddr_(set, i2_i, int));
            error_count++;;
        }
        if(i2_i==0){
            if(first!=*i2){
                qh_fprintf(stderr, 6314, "testqset (%s): First element is %d instead of SETfirst %d\n", name, *i2, first);
                error_count++;;
            }
            if(rangeA!=*i2){
                qh_fprintf(stderr, 6315, "testqset (%s): starts with %d instead of rangeA %d\n", name, *i2, rangeA);
                error_count++;;
            }
            prev= rangeA;
        }else{
            if(i2_i==1 && second!=*i2){
                qh_fprintf(stderr, 6316, "testqset (%s): Second element is %d instead of SETsecond %d\n", name, *i2, second);
                error_count++;;
            }
            if(prev+1==*i2){
                prev++;
            }else{
                if(*i2==rangeB){
                    prev= rangeB;
                    rangeB= -1;
                    rangeCount++;
                }else if(rangeB==-1 && *i2==rangeC){
                    prev= rangeC;
                    rangeC= -1;
                    rangeCount++;
                }else{
                    prev++;
                    qh_fprintf(stderr, 6317, "testqset (%s): Expecting %d'th element to be %d.  Got %d\n", name, i2_i, prev, *i2);
                    error_count++;
                }
            }
        }
        if(i2!=SETelem_(set, i2_i)){
            qh_fprintf(stderr, 6318, "testqset (%s): SETelem_(set, %d) [%p] is not i2 [%p] (the %d'th element)\n", name, i2_i, SETelem_(set, i2_i), i2, i2_i);
            error_count++;;
        }
        if(SETelemt_(set, i2_i, i2T)!=SETelem_(set, i2_i)){   /* Normally SETelemt_ is used for generic sets */
            qh_fprintf(stderr, 6319, "testqset (%s): SETelemt_(set, %d, i2T) [%p] is not SETelem_(set, %d) [%p] (the %d'th element)\n", name, i2_i, SETelemt_(set, i2_i, int), i2_i, SETelem_(set, i2_i), i2_i);
            error_count++;;
        }
    }
    if(error_count>=MAXerrorCount){
        qh_fprintf(stderr, 8161, "testqset (checkSetContents): Stop testing after %d errors\n", error_count);
        exit(1);
    }
}/*checkSetContents*/

qhull-2020.2/src/testqset/testqset.pro0000644060175106010010000000120512611572064016231 0ustar  bbarber# -------------------------------------------------
# testqset.pro -- Qt project file for testqset.exe
# -------------------------------------------------

include(../qhull-warn.pri)

TARGET = testqset

DESTDIR = ../../bin
TEMPLATE = app
CONFIG += console warn_on
CONFIG -= qt
CONFIG += qhull_warn_conversion

build_pass:CONFIG(debug, debug|release){
   OBJECTS_DIR = Debug
}else:build_pass:CONFIG(release, debug|release){
   OBJECTS_DIR = Release
}

INCLUDEPATH += ..

SOURCES += testqset.c
SOURCES += ../libqhull/qset.c
SOURCES += ../libqhull/mem.c
SOURCES += ../libqhull/usermem.c

HEADERS += ../libqhull/mem.h
HEADERS += ../libqhull/qset.h

qhull-2020.2/src/testqset_r/0000755060175106010010000000000013724321434014155 5ustar  bbarberqhull-2020.2/src/testqset_r/testqset_r.c0000644060175106010010000010727113661631132016525 0ustar  bbarber/*
  ---------------------------------

   testset_r.c -- test qset_r.c and its use of mem_r.c

   The test sets are pointers to int.  Normally a set is a pointer to a type (e.g., facetT, ridgeT, etc.).
   For consistency in notation, an "int" is typedef'd to i2T

Functions and macros from qset_r.h.  Counts occurrences in this test.  Does not correspond to thoroughness.
    qh_setaddsorted -- 4 tests
    qh_setaddnth -- 1 test
    qh_setappend -- 7 tests
    qh_setappend_set -- 1 test
    qh_setappend2ndlast -- 1 test
    qh_setcheck -- lots of tests
    qh_setcompact -- 7 tests
    qh_setcopy -- 3 tests
    qh_setdel -- 1 tests
    qh_setdellast -- 1 tests
    qh_setdelnth -- 2 tests
    qh_setdelnthsorted -- 2 tests
    qh_setdelsorted -- 1 test
    qh_setduplicate -- not testable here
    qh_setequal -- 4 tests
    qh_setequal_except -- 2 tests
    qh_setequal_skip -- 2 tests
    qh_setfree -- 11+ tests
    qh_setfree2 -- not testable here
    qh_setfreelong -- 2 tests
    qh_setin -- 3 tests
    qh_setindex -- 4 tests
    qh_setlarger -- 1 test
    qh_setlast -- 2 tests
    qh_setnew -- 6 tests
    qh_setnew_delnthsorted
    qh_setprint -- tested elsewhere
    qh_setreplace -- 1 test
    qh_setsize -- 9+ tests
    qh_settemp -- 2 tests
    qh_settempfree -- 1 test
    qh_settempfree_all -- 1 test
    qh_settemppop -- 1 test
    qh_settemppush -- 1 test
    qh_settruncate -- 3 tests
    qh_setunique -- 3 tests
    qh_setzero -- 1 test
    FOREACHint_ -- 2 test
    FOREACHint4_
    FOREACHint_i_ -- 1 test
    FOREACHintreverse_
    FOREACHintreverse12_
    FOREACHsetelement_ -- 1 test
    FOREACHsetelement_i_ -- 1 test
    FOREACHsetelementreverse_ -- 1 test
    FOREACHsetelementreverse12_ -- 1 test
    SETelem_ -- 3 tests
    SETelemaddr_ -- 2 tests
    SETelemt_ -- not tested (generic)
    SETempty_ -- 1 test
    SETfirst_ -- 4 tests
    SETfirstt_ -- 2 tests
    SETindex_ -- 2 tests
    SETref_ -- 2 tests
    SETreturnsize_ -- 2 tests
    SETsecond_ -- 1 test
    SETsecondt_ -- 2 tests
    SETtruncate_ -- 2 tests

    Copyright (c) 2012-2020 C.B. Barber. All rights reserved.
    $Id: //main/2019/qhull/src/testqset_r/testqset_r.c#5 $$Change: 2953 $
    $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
*/

#include "libqhull_r/user_r.h"  /* QHULL_CRTDBG */
#include "libqhull_r/qset_r.h"
#include "libqhull_r/mem_r.h"
#include "libqhull_r/libqhull_r.h"

#include 
#include 
#include 
#include 

typedef int i2T;
#define MAXerrorCount 100 /* quit after n errors */

#define FOREACHint_( ints ) FOREACHsetelement_(i2T, ints, i2)
#define FOREACHint_i_(qh, ints) FOREACHsetelement_i_(qh, i2T, ints, i2)
/* not tested -- #define FOREACHint4_( ints ) FOREACHsetelement_(i2T, ints, i4) */
/* not tested -- #define FOREACHintreverse_(qh, ints) FOREACHsetelementreverse_(qh, i2T, ints, i2) */
/* not tested -- #define FOREACHintreverse12_( ints ) FOREACHsetelementreverse12_(i2T, ints, i2) */

enum {
    MAXint= 0x7fffffff
};

char prompt[]= "testqset_r N [M] [T5] -- Test reentrant qset_r.c and mem_r.c\n\
  \n\
  If this test fails then reentrant Qhull will not work.\n\
  \n\
  Test qsets of 0..N integers with a check every M iterations (default ~log10)\n\
  Additional checking and logging if M is 1\n\
  \n\
  T5 turns on memory logging (qset does not log)\n\
  \n\
  For example:\n\
    testqset_r 10000\n\
";

int error_count= 0;  /* Global error_count.  checkSetContents(qh) keeps its own error count.  It exits on too many errors */

/* Macros normally defined in geom_r.h */
#define fmax_( a,b )  ( ( a ) < ( b ) ? ( b ) : ( a ) )

/* Macros normally defined in QhullSet.h */

/* Functions normally defined in user_r.h for usermem_r.c */

void    qh_exit(int exitcode);
void    qh_fprintf_stderr(int msgcode, const char *fmt, ... );
void    qh_free(void *mem);
void   *qh_malloc(size_t size);

/* Normally defined in user_r.c, use void instead of facetT/ridgeT for testqset_r.c */

void    qh_errexit(qhT *qh, int exitcode, facetT *f, ridgeT *r);
void    qh_errexit(qhT *qh, int exitcode, facetT *f, ridgeT *r)
{
    (void)f; /* unused */
    (void)r; /* unused */
    (void)qh; /* unused */
    qh_exit(exitcode);
}

/* Normally defined in userprintf_r.c */

void    qh_fprintf(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... );
void    qh_fprintf(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... )
{
    static int needs_cr= 0;  /* True if qh_fprintf needs a CR. testqset_r is not itself reentrant */

    size_t fmtlen= strlen(fmt);
    va_list args;

    if (!fp) {
        /* Do not use qh_fprintf_stderr.  This is a standalone program */
        if(!qh)
            fprintf(stderr, "QH6043 testqset_r (qh_fprintf): fp and qh not defined for '%s'\n", fmt);
        else
            fprintf(stderr, "QH6232 testqset_r (qh_fprintf): fp is 0.  Was wrong qh_fprintf called for '%s'\n", fmt);
        qh_errexit(qh, qh_ERRqhull, NULL, NULL);
    }
    if(fmtlen>0){
        if(fmt[fmtlen-1]=='\n'){
            if(needs_cr && fmtlen>1){
                fprintf(fp, "\n");
            }
            needs_cr= 0;
        }else{
            needs_cr= 1;
        }
    }
    if(msgcode>=6000 && msgcode<7000){
        fprintf(fp, "Error QH%d ", msgcode);
    }
    va_start(args, fmt);
    vfprintf(fp, fmt, args);
    va_end(args);
}

/* Defined below in order of use */
int main(int argc, char **argv);
void readOptions(qhT *qh, int argc, char **argv, const char *promptstr, int *numInts, int *checkEvery, int *traceLevel);
void setupMemory(qhT *qh, int tracelevel, int numInts, int **intarray);

void testSetappendSettruncate(qhT *qh, int numInts, int *intarray, int checkEvery);
void testSetdelSetadd(qhT *qh, int numInts, int *intarray, int checkEvery);
void testSetappendSet(qhT *qh, int numInts, int *intarray, int checkEvery);
void testSetcompactCopy(qhT *qh, int numInts, int *intarray, int checkEvery);
void testSetequalInEtc(qhT *qh, int numInts, int *intarray, int checkEvery);
void testSettemp(qhT *qh, int numInts, int *intarray, int checkEvery);
void testSetlastEtc(qhT *qh, int numInts, int *intarray, int checkEvery);
void testSetdelsortedEtc(qhT *qh, int numInts, int *intarray, int checkEvery);

int log_i(qhT *qh, setT *set, const char *s, int i, int numInts, int checkEvery);
void checkSetContents(qhT *qh, const char *name, setT *set, int count, int rangeA, int rangeB, int rangeC);

int main(int argc, char **argv) {
    int *intarray= NULL;
    int numInts;
    int checkEvery= MAXint;
    int curlong, totlong;  /* used if !qh_NOmem */
    int traceLevel= 4; /* 4 normally, no tracing since qset does not log.  Option 'T5' for memory tracing */
    qhT qh_qh;
    qhT *qh= &qh_qh;

#if defined(_MSC_VER) && defined(_DEBUG) && defined(QHULL_CRTDBG)  /* user_r.h */
    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_DELAY_FREE_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) );
    _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG );
    _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR );
#endif

    readOptions(qh, argc, argv, prompt, &numInts, &checkEvery, &traceLevel);
    setupMemory(qh, traceLevel, numInts, &intarray);

    testSetappendSettruncate(qh, numInts, intarray, checkEvery);
    testSetdelSetadd(qh, numInts, intarray, checkEvery);
    testSetappendSet(qh, numInts, intarray, checkEvery);
    testSetcompactCopy(qh, numInts, intarray, checkEvery);
    testSetequalInEtc(qh, numInts, intarray, checkEvery);
    testSettemp(qh, numInts, intarray, checkEvery);
    testSetlastEtc(qh, numInts, intarray, checkEvery);
    testSetdelsortedEtc(qh, numInts, intarray, checkEvery);
    qh_fprintf(qh, stderr, 8083, "\nNot testing qh_setduplicate and qh_setfree2.  These routines use heap-allocated,\n\
set contents.  See qhull tests in eg/q_test and bin/qhulltest.\n\n");

    qh_memstatistics(qh, stderr);
#ifndef qh_NOmem
    qh_memfreeshort(qh, &curlong, &totlong);
    if (curlong || totlong){
        qh_fprintf(qh, stderr, 8084, "testqset_r: did not free %d bytes of long memory(%d pieces)\n", totlong, curlong);
        error_count++;
    }
#endif
    fflush(NULL);
    if(error_count){
        qh_fprintf(qh, stderr, 8088, "testqset_r: %d errors\n\n", error_count);
        exit(qh_ERRqhull);
    }else{
        printf("testqset_r: OK\n\n");
    }
    return 0;
}/*main*/

void readOptions(qhT *qh, int argc, char **argv, const char *promptstr, int *numInts, int *checkEvery, int *traceLevel)
{
    long numIntsArg;
    long checkEveryArg;
    char *endp;
    int isTracing= 0;

    if (argc < 2 || argc > 4) {
        printf("%s", promptstr);
        exit(0);
    }
    numIntsArg= strtol(argv[1], &endp, 10);
    if(numIntsArg<1){
        qh_fprintf(qh, stderr, 6301, "testqset_r: First argument should be 1 or greater.  Got '%s'\n", argv[1]);
        exit(qh_ERRinput);
    }
    if(numIntsArg>MAXint){
        qh_fprintf(qh, stderr, 6302, "testqset_r: qset does not currently support 64-bit ints.  Maximum count is %d\n", MAXint);
        exit(qh_ERRinput);
    }
    *numInts= (int)numIntsArg;

    if(argc==3 && argv[2][0]=='T' && argv[2][1]=='5' ){
        isTracing= 1;
        *traceLevel= 5;
    }
    if(argc==4 || (argc==3 && !isTracing)){
        checkEveryArg= strtol(argv[2], &endp, 10);
        if(checkEveryArg<1){
            qh_fprintf(qh, stderr, 6321, "testqset_r: checkEvery argument should be 1 or greater.  Got '%s'\n", argv[2]);
            exit(qh_ERRinput);
        }
        if(checkEveryArg>MAXint){
            qh_fprintf(qh, stderr, 6322, "testqset_r: qset does not currently support 64-bit ints.  Maximum checkEvery is %d\n", MAXint);
            exit(qh_ERRinput);
        }
        if(argc==4){
            if(argv[3][0]=='T' && argv[3][1]=='5' ){
                isTracing= 1;
                *traceLevel= 5;
            }else{
                qh_fprintf(qh, stderr, 6242, "testqset_r: Optional third argument must be 'T5'.  Got '%s'\n", argv[3]);
                exit(qh_ERRinput);
            }
        }
        *checkEvery= (int)checkEveryArg;
    }
}/*readOptions*/

void setupMemory(qhT *qh, int tracelevel, int numInts, int **intarray)
{
    int i;
    if(numInts<0 || numInts*(int)sizeof(int)<0){
        qh_fprintf(qh, stderr, 6303, "testqset_r: qset does not currently support 64-bit ints.  Integer overflow\n");
        exit(qh_ERRinput);
    }
    *intarray= (int *)qh_malloc((unsigned int)numInts * sizeof(int));
    if(!*intarray){
        qh_fprintf(qh, stderr, 6304, "testqset_r: Failed to allocate %d bytes of memory\n", numInts * (int)sizeof(int));
        exit(qh_ERRmem);
    }
    for(i= 0; i=2){
        isCheck= log_i(qh, ints, "n", numInts/2, numInts, checkEvery);
        qh_settruncate(qh, ints, numInts/2);
        checkSetContents(qh, "qh_settruncate by half", ints, numInts/2, 0, -1, -1);
    }
    isCheck= log_i(qh, ints, "n", 0, numInts, checkEvery);
    qh_settruncate(qh, ints, 0);
    checkSetContents(qh, "qh_settruncate", ints, 0, -1, -1, -1);

    qh_fprintf(qh, stderr, 8122, "\n\nTesting qh_setappend2ndlast 0,0..%d.  Test 0", numInts-1);
    qh_setfree(qh, &ints);
    ints= qh_setnew(qh, 4);
    qh_setappend(qh, &ints, intarray+0);
    for(i= 0; i=2){
        isCheck= log_i(qh, ints, "n", numInts/2, numInts, checkEvery);
        SETtruncate_(ints, numInts/2);
        checkSetContents(qh, "SETtruncate_ by half", ints, numInts/2, 0, -1, -1);
    }
    isCheck= log_i(qh, ints, "n", 0, numInts, checkEvery);
    SETtruncate_(ints, 0);
    checkSetContents(qh, "SETtruncate_", ints, 0, -1, -1, -1);

    qh_setfree(qh, &ints);
}/*testSetappendSettruncate*/

void testSetdelSetadd(qhT *qh, int numInts, int *intarray, int checkEvery)
{
    setT *ints=qh_setnew(qh, 1);
    int i,j,isCheck;

    qh_fprintf(qh, stderr, 8147, "\n\nTesting qh_setdelnthsorted and qh_setaddnth 1..%d. Test", numInts-1);
    for(j=1; j3){
                qh_setdelsorted(ints, intarray+i/2);
                checkSetContents(qh, "qh_setdelsorted", ints, j-1, 0, i/2+1, -1);
                qh_setaddsorted(qh, &ints, intarray+i/2);
                checkSetContents(qh, "qh_setaddsorted i/2", ints, j, 0, 0, -1);
            }
            qh_setdellast(ints);
            checkSetContents(qh, "qh_setdellast", ints, (j ? j-1 : 0), 0, -1, -1);
            if(j>0){
                qh_setaddsorted(qh, &ints, intarray+j-1);
                checkSetContents(qh, "qh_setaddsorted j-1", ints, j, 0, -1, -1);
            }
            if(j>4){
                qh_setdelnthsorted(qh, ints, i/2);
                if (checkEvery==1)
                  checkSetContents(qh, "qh_setdelnthsorted", ints, j-1, 0, i/2+1, -1);
                /* test qh_setdelnth and move-to-front */
                qh_setdelsorted(ints, intarray+i/2+1);
                checkSetContents(qh, "qh_setdelsorted 2", ints, j-2, 0, i/2+2, -1);
                qh_setaddsorted(qh, &ints, intarray+i/2+1);
                if (checkEvery==1)
                  checkSetContents(qh, "qh_setaddsorted i/2+1", ints, j-1, 0, i/2+1, -1);
                qh_setaddsorted(qh, &ints, intarray+i/2);
                checkSetContents(qh, "qh_setaddsorted i/2 again", ints, j, 0, -1, -1);
            }
            qh_setfree(qh, &ints2);
            ints2= qh_setcopy(qh, ints, 0);
            qh_setcompact(qh, ints);
            qh_setcompact(qh, ints2);
            checkSetContents(qh, "qh_setcompact", ints, j, 0, 0, -1);
            checkSetContents(qh, "qh_setcompact 2", ints2, j, 0, 0, -1);
            qh_setcompact(qh, ints);
            checkSetContents(qh, "qh_setcompact 3", ints, j, 0, 0, -1);
            qh_setfree(qh, &ints2);
        }
    }
    qh_setfreelong(qh, &ints);
    if(ints){
        qh_setfree(qh, &ints); /* Was quick memory */
    }
}/*testSetdelsortedEtc*/

void testSetequalInEtc(qhT *qh, int numInts, int *intarray, int checkEvery)
{
    setT *ints= NULL;
    setT *ints2= NULL;
    setT *ints3= NULL;
    int i,j,n;

    qh_fprintf(qh, stderr, 8151, "\n\nTesting qh_setequal*, qh_setin*, qh_setdel, qh_setdelnth, and qh_setlarger 0..%d. Test", numInts-1);
    for(j=0; j0){
                if(qh_setequal(ints, ints2)){
                    qh_fprintf(qh, stderr, 6324, "testqset_r (testSetequalInEtc): non-empty set equal to empty set\n", j);
                    error_count++;
                }
                qh_setfree(qh, &ints3);
                ints3= qh_setcopy(qh, ints, 0);
                checkSetContents(qh, "qh_setreplace", ints3, j, 0, -1, -1);
                qh_setreplace(qh, ints3, intarray+j/2, intarray+j/2+1);
                if(j==1){
                    checkSetContents(qh, "qh_setreplace 2", ints3, j, j/2+1, -1, -1);
                }else if(j==2){
                    checkSetContents(qh, "qh_setreplace 3", ints3, j, 0, j/2+1, -1);
                }else{
                    checkSetContents(qh, "qh_setreplace 3", ints3, j, 0, j/2+1, j/2+1);
                }
                if(qh_setequal(ints, ints3)){
                    qh_fprintf(qh, stderr, 6325, "testqset_r (testSetequalInEtc): modified set equal to original set at %d/2\n", j);
                    error_count++;
                }
                if(!qh_setequal_except(ints, intarray+j/2, ints3, intarray+j/2+1)){
                    qh_fprintf(qh, stderr, 6326, "testqset_r (qh_setequal_except): modified set not equal to original set except modified\n", j);
                    error_count++;
                }
                if(qh_setequal_except(ints, intarray+j/2, ints3, intarray)){
                    qh_fprintf(qh, stderr, 6327, "testqset_r (qh_setequal_except): modified set equal to original set with wrong excepts\n", j);
                    error_count++;
                }
                if(!qh_setequal_skip(ints, j/2, ints3, j/2)){
                    qh_fprintf(qh, stderr, 6328, "testqset_r (qh_setequal_skip): modified set not equal to original set except modified\n", j);
                    error_count++;
                }
                if(j>2 && qh_setequal_skip(ints, j/2, ints3, 0)){
                    qh_fprintf(qh, stderr, 6329, "testqset_r (qh_setequal_skip): modified set equal to original set with wrong excepts\n", j);
                    error_count++;
                }
                if(intarray+j/2+1!=qh_setdel(ints3, intarray+j/2+1)){
                    qh_fprintf(qh, stderr, 6330, "testqset_r (qh_setdel): failed to find added element\n", j);
                    error_count++;
                }
                checkSetContents(qh, "qh_setdel", ints3, j-1, 0, j-1, (j==1 ? -1 : j/2+1));  /* swaps last element with deleted element */
                if(j>3){
                    qh_setdelnth(qh, ints3, j/2); /* Delete at the same location as the original replace, for only one out-of-order element */
                    checkSetContents(qh, "qh_setdelnth", ints3, j-2, 0, j-2, (j==2 ? -1 : j/2+1));
                }
                if(qh_setin(ints3, intarray+j/2)){
                    qh_fprintf(qh, stderr, 6331, "testqset_r (qh_setin): found deleted element\n");
                    error_count++;
                }
                if(j>4 && !qh_setin(ints3, intarray+1)){
                    qh_fprintf(qh, stderr, 6332, "testqset_r (qh_setin): did not find second element\n");
                    error_count++;
                }
                if(j>4 && !qh_setin(ints3, intarray+j-2)){
                    qh_fprintf(qh, stderr, 6333, "testqset_r (qh_setin): did not find last element\n");
                    error_count++;
                }
                if(-1!=qh_setindex(ints2, intarray)){
                    qh_fprintf(qh, stderr, 6334, "testqset_r (qh_setindex): found element in empty set\n");
                    error_count++;
                }
                if(-1!=qh_setindex(ints3, intarray+j/2)){
                    qh_fprintf(qh, stderr, 6335, "testqset_r (qh_setindex): found deleted element in set\n");
                    error_count++;
                }
                if(0!=qh_setindex(ints, intarray)){
                    qh_fprintf(qh, stderr, 6336, "testqset_r (qh_setindex): did not find first in set\n");
                    error_count++;
                }
                if(j-1!=qh_setindex(ints, intarray+j-1)){
                    qh_fprintf(qh, stderr, 6337, "testqset_r (qh_setindex): did not find last in set\n");
                    error_count++;
                }
            }
            qh_setfree(qh, &ints2);
        }
    }
    qh_setfree(qh, &ints3);
    qh_setfreelong(qh, &ints);
    if(ints){
        qh_setfree(qh, &ints); /* Was quick memory */
    }
}/*testSetequalInEtc*/


void testSetlastEtc(qhT *qh, int numInts, int *intarray, int checkEvery)
{
    setT *ints= NULL;
    setT *ints2= NULL;
    int i,j,prepend;

    qh_fprintf(qh, stderr, 8152, "\n\nTesting qh_setlast, qh_setnew_delnthsorted, qh_setunique, and qh_setzero 0..%d. Test", numInts-1);
    for(j=0; j0){
                if(intarray+j-1!=qh_setlast(ints)){
                    qh_fprintf(qh, stderr, 6338, "testqset_r (qh_setlast): wrong last element\n");
                    error_count++;
                }
                prepend= (j<100 ? j/4 : 0);
                ints2= qh_setnew_delnthsorted(qh, ints, qh_setsize(qh, ints), j/2, prepend);
                if(qh_setsize(qh, ints2)!=j+prepend-1){
                    qh_fprintf(qh, stderr, 6345, "testqset_r (qh_setnew_delnthsorted): Expecting %d elements, got %d\n", j+prepend-1, qh_setsize(qh, ints2));
                    error_count++;
                }
                /* Define prepended elements.  Otherwise qh_setdelnthsorted may fail */
                for(i= 0; i2){
                    qh_setzero(qh, ints2, j/2, j-1);  /* max size may be j-1 */
                    if(qh_setsize(qh, ints2)!=j-1){
                        qh_fprintf(qh, stderr, 6342, "testqset_r (qh_setzero): Expecting %d elements, got %d\n", j, qh_setsize(qh, ints2));
                        error_count++;
                    }
                    qh_setcompact(qh, ints2);
                    checkSetContents(qh, "qh_setzero", ints2, j/2, 0, -1, -1);
                }
            }
            qh_setfree(qh, &ints2);
        }
    }
    qh_setfreelong(qh, &ints);
    if(ints){
        qh_setfree(qh, &ints); /* Was quick memory */
    }
}/*testSetlastEtc*/

void testSettemp(qhT *qh, int numInts, int *intarray, int checkEvery)
{
    setT *ints= NULL;
    setT *ints2= NULL;
    setT *ints3= NULL;
    int i,j;

    qh_fprintf(qh, stderr, 8153, "\n\nTesting qh_settemp* 0..%d. Test", numInts-1);
    for(j=0; j0){
                qh_settemppush(qh, ints);
                ints3= qh_settemppop(qh);
                if(ints!=ints3){
                    qh_fprintf(qh, stderr, 6343, "testqset_r (qh_settemppop): didn't pop the push\n");
                    error_count++;
                }
            }
            qh_settempfree(qh, &ints2);
        }
    }
    qh_setfreelong(qh, &ints);
    if(ints){
        qh_setfree(qh, &ints); /* Was quick memory */
    }
}/*testSettemp*/

/* Check that a set contains count elements
   Ranges are consecutive (e.g., 1,2,3,...) starting with first, mid, and last
   Use -1 for missing ranges
   Returns -1 if should check results
*/
int log_i(qhT *qh, setT *set, const char *s, int i, int numInts, int checkEvery)
{
    int j= i;
    int scale= 1;
    int e= 0;
    int *i2, **i2p;

    if(*s || checkEvery==1){
        if(i<10){
            qh_fprintf(qh, stderr, 8154, " %s%d", s, i);
        }else{
            if(i==11 && checkEvery==1){
                qh_fprintf(qh, stderr, 8155, "\nResults after 10: ");
                FOREACHint_(set){
                    qh_fprintf(qh, stderr, 8156, " %d", *i2);
                }
                qh_fprintf(qh, stderr, 8157, " Continue");
            }
            while((j= j/10)>=1){
                scale *= 10;
                e++;
            }
            if(i==numInts-1){
                qh_fprintf(qh, stderr, 8158, " %s%d", s, i);
            }else if(i==scale){
                if(i<=1000){
                    qh_fprintf(qh, stderr, 8159, " %s%d", s, i);
                }else{
                    qh_fprintf(qh, stderr, 8160, " %s1e%d", s, e);
                }
            }
        }
    }
    if(i<1000 || i%checkEvery==0 || i== scale || i==numInts-1){
        return 1;
    }
    return 0;
}/*log_i*/

/* Check that a set contains count elements
   Ranges are consecutive (e.g., 1,2,3,...) starting with first, mid, and last
   Use -1 for missing ranges
*/
void checkSetContents(qhT *qh, const char *name, setT *set, int count, int rangeA, int rangeB, int rangeC)
{

    i2T *i2, **i2p;
    int i2_i, i2_n;
    int prev= -1; /* avoid warning */
    int i;
    int first= -3;
    int second= -3;
    int rangeCount=1;
    int actualSize= 0;

    qh_setcheck(qh, set, name, 0);
    if(set){
        SETreturnsize_(set, actualSize);  /* normally used only when speed is critical */
        if(*qh_setendpointer(set)!=NULL){
            qh_fprintf(qh, stderr, 6344, "testqset_r (%s): qh_setendpointer(set), 0x%x, is not NULL terminator of set 0x%x\n", name, qh_setendpointer(set), set);
            error_count++;
        }
    }
    if(actualSize!=qh_setsize(qh, set)){
        qh_fprintf(qh, stderr, 6305, "testqset_r (%s): SETreturnsize_(qh) returned %d while qh_setsize(qh) returns %d\n", name, actualSize, qh_setsize(qh, set));
        error_count++;
    }else if(actualSize!=count){
        qh_fprintf(qh, stderr, 6306, "testqset_r (%s): Expecting %d elements for set.  Got %d elements\n", name, count, actualSize);
        error_count++;
    }
    if(SETempty_(set)){
        if(count!=0){
            qh_fprintf(qh, stderr, 6307, "testqset_r (%s): Got empty set instead of count %d, rangeA %d, rangeB %d, rangeC %d\n", name, count, rangeA, rangeB, rangeC);
            error_count++;
        }
    }else{
        /* Must be first, otherwise trips msvc 8 */
        i2T **p= SETaddr_(set, i2T);
        if(*p!=SETfirstt_(set, i2T)){
            qh_fprintf(qh, stderr, 6309, "testqset_r (%s): SETaddr_(set, i2t) [%p] is not the same as SETfirst_(set) [%p]\n", name, SETaddr_(set, i2T), SETfirst_(set));
            error_count++;
        }
        first= *(int *)SETfirst_(set);
        if(SETfirst_(set)!=SETfirstt_(set, i2T)){
            qh_fprintf(qh, stderr, 6308, "testqset_r (%s): SETfirst_(set) [%p] is not the same as SETfirstt_(set, i2T [%p]\n", name, SETfirst_(set), SETfirstt_(set, i2T));
            error_count++;
        }
        if(qh_setsize(qh, set)>1){
            second= *(int *)SETsecond_(set);
            if(SETsecond_(set)!=SETsecondt_(set, i2T)){
                qh_fprintf(qh, stderr, 6310, "testqset_r (%s): SETsecond_(set) [%p] is not the same as SETsecondt_(set, i2T) [%p]\n", name, SETsecond_(set), SETsecondt_(set, i2T));
                error_count++;
            }
        }
    }
    /* Test first run of ints in set*/
    i= 0;
    FOREACHint_(set){
        if(i2!=SETfirst_(set) && *i2!=prev+1){
            break;
        }
        prev= *i2;
        if(SETindex_(set, i2)!=i){
            qh_fprintf(qh, stderr, 6311, "testqset_r (%s): Expecting SETindex_(set, pointer-to-%d) to be %d.  Got %d\n", name, *i2, i, SETindex_(set, i2));
            error_count++;;
        }
        if(i2!=SETref_(i2)){
            qh_fprintf(qh, stderr, 6312, "testqset_r (%s): SETref_(i2) [%p] does not point to i2 (the %d'th element)\n", name, SETref_(i2), i);
            error_count++;;
        }
        i++;
    }
    FOREACHint_i_(qh, set){
        /* Must be first conditional, otherwise it trips up msvc 8 */
        i2T **p= SETelemaddr_(set, i2_i, i2T);
        if(i2!=*p){
            qh_fprintf(qh, stderr, 6320, "testqset_r (%s): SETelemaddr_(set, %d, i2T) [%p] does not point to i2\n", name, i2_i, SETelemaddr_(set, i2_i, int));
            error_count++;;
        }
        if(i2_i==0){
            if(first!=*i2){
                qh_fprintf(qh, stderr, 6314, "testqset_r (%s): First element is %d instead of SETfirst %d\n", name, *i2, first);
                error_count++;;
            }
            if(rangeA!=*i2){
                qh_fprintf(qh, stderr, 6315, "testqset_r (%s): starts with %d instead of rangeA %d\n", name, *i2, rangeA);
                error_count++;;
            }
            prev= rangeA;
        }else{
            if(i2_i==1 && second!=*i2){
                qh_fprintf(qh, stderr, 6316, "testqset_r (%s): Second element is %d instead of SETsecond %d\n", name, *i2, second);
                error_count++;;
            }
            if(prev+1==*i2){
                prev++;
            }else{
                if(*i2==rangeB){
                    prev= rangeB;
                    rangeB= -1;
                    rangeCount++;
                }else if(rangeB==-1 && *i2==rangeC){
                    prev= rangeC;
                    rangeC= -1;
                    rangeCount++;
                }else{
                    prev++;
                    qh_fprintf(qh, stderr, 6317, "testqset_r (%s): Expecting %d'th element to be %d.  Got %d\n", name, i2_i, prev, *i2);
                    error_count++;
                }
            }
        }
        if(i2!=SETelem_(set, i2_i)){
            qh_fprintf(qh, stderr, 6318, "testqset_r (%s): SETelem_(set, %d) [%p] is not i2 [%p] (the %d'th element)\n", name, i2_i, SETelem_(set, i2_i), i2, i2_i);
            error_count++;;
        }
        if(SETelemt_(set, i2_i, i2T)!=SETelem_(set, i2_i)){   /* Normally SETelemt_ is used for generic sets */
            qh_fprintf(qh, stderr, 6319, "testqset_r (%s): SETelemt_(set, %d, i2T) [%p] is not SETelem_(set, %d) [%p] (the %d'th element)\n", name, i2_i, SETelemt_(set, i2_i, int), i2_i, SETelem_(set, i2_i), i2_i);
            error_count++;;
        }
    }
    if(error_count>=MAXerrorCount){
        qh_fprintf(qh, stderr, 8161, "testqset_r (checkSetContents): Stop testing after %d errors\n", error_count);
        exit(1);
    }
}/*checkSetContents*/

qhull-2020.2/src/testqset_r/testqset_r.pro0000644060175106010010000000124112611572114017067 0ustar  bbarber# -------------------------------------------------
# testqset_r.pro -- Qt project file for testqset_r.exe
# -------------------------------------------------

include(../qhull-warn.pri)

TARGET = testqset_r

DESTDIR = ../../bin
TEMPLATE = app
CONFIG += console warn_on
CONFIG -= qt
CONFIG += qhull_warn_conversion

build_pass:CONFIG(debug, debug|release){
   OBJECTS_DIR = Debug
}else:build_pass:CONFIG(release, debug|release){
   OBJECTS_DIR = Release
}

INCLUDEPATH += ..

SOURCES += testqset_r.c
SOURCES += ../libqhull_r/qset_r.c
SOURCES += ../libqhull_r/mem_r.c
SOURCES += ../libqhull_r/usermem_r.c

HEADERS += ../libqhull_r/mem_r.h
HEADERS += ../libqhull_r/qset_r.h

qhull-2020.2/src/user_eg/0000755060175106010010000000000013724321434013411 5ustar  bbarberqhull-2020.2/src/user_eg/user_eg.c0000644060175106010010000002721013504701456015212 0ustar  bbarber/*
  ---------------------------------

  user_eg.c
  sample code for calling qhull() from an application.  Uses non-reentrant libqhull

  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 C++ example, see user_eg3/user_eg3_r.cpp

   Summaries are sent to stderr if other output formats are used

   compiled by 'make bin/user_eg'

   see libqhull.h for data structures, macros, and user-callable functions.
*/

#include "libqhull/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; jlocate a facet with qh_findbestfacet()
  calls qh_setdelaunay() to project the point to a parabaloid
warning:
  Errors if it finds a tricoplanar facet ('Qt').  The corresponding Delaunay triangle
  is in the set of tricoplanar facets or one of their neighbors.  This search
  is not implemented here.
*/
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);
  if (facet->tricoplanar) {
    fprintf(stderr, "findDelaunay: search not implemented for triangulated, non-simplicial Delaunay regions (tricoplanar facet, f%d).\n",
       facet->id);
    qh_errexit(qh_ERRqhull, facet, NULL);
  }
  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= 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);
  fflush(NULL);
  exitcode= qh_new_qhull(dim, numpoints, points, ismalloc,
                      flags, outfile, errfile);
  fflush(NULL);
  if (!exitcode) {                  /* if no error */
    /* 'qh facet_list' contains the convex hull */
    print_summary();
    FORALLfacets {
       /* ... your code ... */
    }
  }
#ifdef qh_NOmem
  qh_freeqhull(qh_ALL);
#else
  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);
#endif

  /*
    Run 2: Delaunay triangulation, reusing the previous qh/qh_qh
  */

  printf( "\n========\ncompute %d-d Delaunay triangulation\n", dim);
  sprintf(flags, "qhull s d Tcv %s", argc >= 3 ? argv[2] : "");
  numpoints= SIZEcube;
  makeDelaunay(points, numpoints, dim, (int)time(NULL));
  for (i=numpoints; i--; )
    rows[i]= points+dim*i;
  qh_printmatrix(outfile, "input", rows, numpoints, dim);
  fflush(NULL);
  exitcode= qh_new_qhull(dim, numpoints, points, ismalloc,
                      flags, outfile, errfile);
  fflush(NULL);
  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 %d-d Delaunay triangle or adjacent triangle closest to [0.5, 0.5, ...]\n", dim);
    exitcode= setjmp(qh errexit);
    if (!exitcode) {
      /* Trap Qhull errors from 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( "\n========\nCompute a new triangulation as a separate instance of Qhull\n");
    oldqhA= qh_save_qhull();
    sprintf(flags, "qhull s d Tcv %s", argc >= 3 ? argv[2] : "");
    numpoints= SIZEcube;
    makeDelaunay(pointsB, numpoints, dim, (int)time(NULL)+1);
    for (i=numpoints; i--; )
      rows[i]= pointsB+dim*i;
    qh_printmatrix(outfile, "input", rows, numpoints, dim);
    fflush(NULL);
    exitcode= qh_new_qhull(dim, numpoints, pointsB, ismalloc,
                      flags, outfile, errfile);
    fflush(NULL);
    if (!exitcode)
      print_summary();
    printf( "\n========\nFree memory allocated by the new instance of Qhull, and redisplay the old results.\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);
    printf( "\n\n");
    print_summary();
  }
#endif

#ifdef qh_NOmem
  qh_freeqhull(qh_ALL);
#else
  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);
#endif

  /*
    Run 3: halfspace intersection about the origin
  */
  printf( "\n========\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);
  fflush(NULL);
  /* 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);
  fflush(NULL);
  if (!exitcode)
    print_summary();
#ifdef qh_NOmem
  qh_freeqhull(qh_ALL);
#else
  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);
#endif
  return exitcode;
} /* main */

qhull-2020.2/src/user_eg/user_eg.pro0000644060175106010010000000044112541571400015557 0ustar  bbarber# -------------------------------------------------
# user_eg.pro -- Qt project for Qhull demonstration using shared Qhull library
#
# It uses reentrant Qhull
# -------------------------------------------------

include(../qhull-app-shared_r.pri)

TARGET = user_eg

SOURCES += user_eg_r.c
qhull-2020.2/src/user_eg/user_eg_r.c0000644060175106010010000002737013504671272015544 0ustar  bbarber/*
  ---------------------------------

  user_eg_r.c
  sample code for calling qhull() from an application.  Uses reentrant libqhull_r

  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_r.c and user_eg2_r.c.
   These examples, call qh_qhull() directly.  They allow
   tighter control on the code loaded with Qhull.

   For a C++ example, see user_eg3/user_eg3_r.cpp

   Summaries are sent to stderr if other output formats are used

   compiled by 'make bin/user_eg'

   see libqhull_r.h for data structures, macros, and user-callable functions.
*/

#include "libqhull_r/qhull_ra.h"

/*-------------------------------------------------
-internal function prototypes
*/
void print_summary(qhT *qh);
void makecube(coordT *points, int numpoints, int dim);
void makeDelaunay(qhT *qh, coordT *points, int numpoints, int dim, int seed);
void findDelaunay(qhT *qh, int dim);
void makehalf(coordT *points, int numpoints, int dim);

/*-------------------------------------------------
-print_summary(qh)
*/
void print_summary(qhT *qh) {
  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; jlocate a facet with qh_findbestfacet()
  calls qh_setdelaunay() to project the point to a parabaloid
warning:
  Errors if it finds a tricoplanar facet ('Qt').  The corresponding Delaunay triangle
  is in the set of tricoplanar facets or one of their neighbors.  This search
  is not implemented here.
*/
void findDelaunay(qhT *qh, 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(qh, dim+1, 1, point);
  facet= qh_findbestfacet(qh, point, qh_ALL, &bestdist, &isoutside);
  if (facet->tricoplanar) {
    fprintf(stderr, "findDelaunay: search not implemented for triangulated, non-simplicial Delaunay regions (tricoplanar facet, f%d).\n",
       facet->id);
    qh_errexit(qh, qh_ERRqhull, facet, NULL);
  }
  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= 2 ? argv[1] : "");
  numpoints= SIZEcube;
  makecube(points, numpoints, DIM);
  for (i=numpoints; i--; )
    rows[i]= points+dim*i;
  qh_printmatrix(qh, outfile, "input", rows, numpoints, dim);
  fflush(NULL);
  exitcode= qh_new_qhull(qh, dim, numpoints, points, ismalloc,
                      flags, outfile, errfile);
  fflush(NULL);
  if (!exitcode) {                  /* if no error */
    /* 'qh->facet_list' contains the convex hull */
    print_summary(qh);
    FORALLfacets {
       /* ... your code ... */
    }
  }
#ifdef qh_NOmem
  qh_freeqhull(qh, qh_ALL);
#else
  qh_freeqhull(qh, !qh_ALL);                   /* free long memory  */
  qh_memfreeshort(qh, &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);
#endif

  /*
    Run 2: Delaunay triangulation, reusing the previous qh/qh_qh
  */

  printf( "\n========\ncompute %d-d Delaunay triangulation\n", dim);
  sprintf(flags, "qhull s d Tcv %s", argc >= 3 ? argv[2] : "");
  numpoints= SIZEcube;
  makeDelaunay(qh, points, numpoints, dim, (int)time(NULL));
  for (i=numpoints; i--; )
    rows[i]= points+dim*i;
  qh_printmatrix(qh, outfile, "input", rows, numpoints, dim);
  fflush(NULL);
  exitcode= qh_new_qhull(qh, dim, numpoints, points, ismalloc,
                      flags, outfile, errfile);
  fflush(NULL);
  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(qh);
    FORALLfacets {
       /* ... your code ... */
    }
    printf( "\nfind %d-d Delaunay triangle or adjacent triangle closest to [0.5, 0.5, ...]\n", dim);
    exitcode= setjmp(qh->errexit);
    if (!exitcode) {
      /* Trap Qhull errors from findDelaunay().  Without the setjmp(), Qhull
         will exit() after reporting an error */
      qh->NOerrexit= False;
      findDelaunay(qh, DIM);
    }
    qh->NOerrexit= True;
  }
  {
    coordT pointsB[DIM*TOTpoints]; /* array of coordinates for each point */

    qhT qh_qhB;    /* Create a new instance of Qhull (qhB) */
    qhT *qhB= &qh_qhB;
    qh_zero(qhB, errfile);

    printf( "\n========\nCompute a new triangulation as a separate instance of Qhull\n");
    sprintf(flags, "qhull s d Tcv %s", argc >= 3 ? argv[2] : "");
    numpoints= SIZEcube;
    makeDelaunay(qhB, pointsB, numpoints, dim, (int)time(NULL)+1);
    for (i=numpoints; i--; )
      rows[i]= pointsB+dim*i;
    qh_printmatrix(qhB, outfile, "input", rows, numpoints, dim);
    fflush(NULL);
    exitcode= qh_new_qhull(qhB, dim, numpoints, pointsB, ismalloc,
                      flags, outfile, errfile);
    fflush(NULL);
    if (!exitcode)
      print_summary(qhB);
    printf( "\n========\nFree memory allocated by the new instance of Qhull, and redisplay the old results.\n");
#ifdef qh_NOmem
    qh_freeqhull(qh, qh_ALL);
#else
    qh_freeqhull(qhB, !qh_ALL);                 /* free long memory */
    qh_memfreeshort(qhB, &curlong, &totlong);  /* free short memory and memory allocator */
    if (curlong || totlong)
        fprintf(errfile, "qhull internal warning (user_eg, #4): did not free %d bytes of long memory (%d pieces)\n", totlong, curlong);
#endif
    printf( "\n\n");
    print_summary(qh);  /* The other instance is unchanged */
    /* Exiting the block frees qh_qhB */
  }
#ifdef qh_NOmem
  qh_freeqhull(qh, qh_ALL);
#else
  qh_freeqhull(qh, !qh_ALL);                 /* free long memory */
  qh_memfreeshort(qh, &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);
#endif

  /*
    Run 3: halfspace intersection about the origin
  */
  printf( "\n========\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(qh, outfile, "input as halfspace coefficients + offsets", rows, numpoints, dim+1);
  fflush(NULL);
  /* 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(qh, dim+1, numpoints, points, ismalloc,
                      flags, outfile, errfile);
  fflush(NULL);
  if (!exitcode)
    print_summary(qh);
#ifdef qh_NOmem
  qh_freeqhull(qh, qh_ALL);
#else
  qh_freeqhull(qh, !qh_ALL);
  qh_memfreeshort(qh, &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);
#endif
  return exitcode;
} /* main */

qhull-2020.2/src/user_eg2/0000755060175106010010000000000013724321435013474 5ustar  bbarberqhull-2020.2/src/user_eg2/user_eg2.c0000644060175106010010000006756213505436313015372 0ustar  bbarber/*
  ---------------------------------

  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.

   For a C++ example, see user_eg3/user_eg3_r.cpp


  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 bin/user_eg2'

   see libqhull.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 "libqhull/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; jlocate a facet with qh_findbestfacet()
  calls qh_setdelaunay() to project the point to a parabaloid
warning:
  Errors if it finds a tricoplanar facet ('Qt').  The corresponding Delaunay triangle
  is in the set of tricoplanar facets or one of their neighbors.  This search
  is not implemented here.
*/
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);
  if (facet->tricoplanar) {
    fprintf(stderr, "findDelaunay: search not implemented for triangulated, non-simplicial Delaunay regions (tricoplanar facet, f%d).\n",
       facet->id);
    qh_errexit(qh_ERRqhull, facet, NULL);
  }
  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= 2 ? argv[1] : "");
    qh_initflags(options);
    printf( "\n========\ncompute triangulated convex hull of cube after rotating input\n");
    makecube(array[0], SIZEcube, DIM);
    fflush(NULL);
    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 FORCEoutput && !qh STOPadd && !qh STOPcone && !qh STOPpoint)
      qh_check_points();
    fflush(NULL);
    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 FORCEoutput && !qh STOPadd && !qh STOPcone && !qh STOPpoint)
      qh_check_points();
    fflush(NULL);
  }
  qh NOerrexit= True;
#ifdef qh_NOmem
  qh_freeqhull(qh_ALL);
#else
  qh_freeqhull(!qh_ALL);
  qh_memfreeshort(&curlong, &totlong);
  if (curlong || totlong)
    fprintf(stderr, "qhull warning (user_eg2, run 1): did not free %d bytes of long memory (%d pieces)\n",
          totlong, curlong);
#endif

  /*
    Run 2: Delaunay triangulation
  */
  qh_init_A(stdin, stdout, stderr, 0, NULL);
  exitcode= setjmp(qh errexit);
  if (!exitcode) {
    coordT array[TOTpoints][DIM];

    qh NOerrexit= False;
    strcat(qh rbox_command, "user_eg2 Delaunay example");
    sprintf(options, "qhull s d Tcv %s", argc >= 3 ? argv[2] : "");
    qh_initflags(options);
    printf( "\n========\ncompute %d-d Delaunay triangulation\n", DIM-1);
    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 FORCEoutput && !qh STOPadd && !qh STOPcone && !qh STOPpoint)
      qh_check_points();
    fflush(NULL);
    printf( "\n========\nadd points to triangulation\n");
    addDelaunay(array[0], SIZEcube, SIZEdiamond, DIM);
    qh_check_output();
    printf("\nfind Delaunay triangle or adjacent triangle closest to [0.5, 0.5, ...]\n");
    findDelaunay(DIM);
    qh_produce_output();  /* delete this line to help avoid io.c */
    if (qh VERIFYoutput && !qh FORCEoutput && !qh STOPadd && !qh STOPcone && !qh STOPpoint)
      qh_check_points();
    fflush(NULL);
  }
  qh NOerrexit= True;
#ifdef qh_NOmem
  qh_freeqhull(qh_ALL);
#else
  qh_freeqhull(!qh_ALL);
  qh_memfreeshort(&curlong, &totlong);
  if (curlong || totlong)
    fprintf(stderr, "qhull warning (user_eg2, run 2): did not free %d bytes of long memory (%d pieces)\n",
         totlong, curlong);
#endif

  /*
    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;

    qh NOerrexit= False;
    strcat(qh rbox_command, "user_eg2 halfspace example");
    sprintf(options, "qhull H0 s Tcv %s", argc >= 4 ? argv[3] : "");
    qh_initflags(options);
    printf( "\n========\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();
    fflush(NULL);
    qh_check_output();
    qh_produce_output();  /* delete this line to help avoid io.c */
    if (qh VERIFYoutput && !qh FORCEoutput && !qh STOPadd && !qh STOPcone && !qh STOPpoint)
      qh_check_points();
    fflush(NULL);
    printf( "\n========\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 FORCEoutput && !qh STOPadd && !qh STOPcone && !qh STOPpoint)
      qh_check_points();
    fflush(NULL);
  }
  qh NOerrexit= True;
  qh NOerrexit= True;
#ifdef qh_NOmem
  qh_freeqhull(qh_ALL);
#else
  qh_freeqhull(!qh_ALL);
  qh_memfreeshort(&curlong, &totlong);
  if (curlong || totlong)
    fprintf(stderr, "qhull warning (user_eg2, run 3): did not free %d bytes of long memory (%d pieces)\n",
          totlong, curlong);
#endif
  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 libqhull.c for 2 facets
*/
void qh_errexit(int exitcode, facetT *facet, ridgeT *ridge) {
  QHULL_UNUSED(facet);
  QHULL_UNUSED(ridge);

  if (qh ERREXITcalled) {
    fprintf(qh ferr, "qhull error while handling previous error in qh_errexit.  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(const 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 */

/* 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)
    qh_fprintf(fp, 9368, "\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@qhull.org\n");
  else if (!qh_QUICKhelp) {
    qh_fprintf(fp, 9369, "\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
    qh_fprintf(fp, 9370, "\
\n\
Qhull is currently using single precision arithmetic.  The following\n\
will probably remove the precision problems:\n\
  - recompile qhull for realT precision(#define REALfloat 0 in user.h).\n");
#endif
    if (qh DELAUNAY && !qh SCALElast && qh MAXabs_coord > 1e4)
      qh_fprintf(fp, 9371, "\
\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)
      qh_fprintf(fp, 9372, "\
When computing the Delaunay triangulation:\n\
  - use 'Qz' to add a point at-infinity.  This reduces precision problems.\n");

    qh_fprintf(fp, 9373, "\
\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);
    qh_fprintf(fp, 9374, "\
\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 */


/* qh_printhelp_narrowhull( minangle )
     Warn about a narrow hull

  notes:
    Alternatively, reduce qh_WARNnarrow in user.h

*/
void qh_printhelp_narrowhull(FILE *fp, realT minangle) {

    qh_fprintf(fp, 9375, "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 */
} /* printhelp_narrowhull */

/* qh_printhelp_singular
      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;

  qh_fprintf(fp, 9376, "\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)
    qh_fprintf(fp, 9377, "\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);
  qh_fprintf(fp, 9378, "\n");
  FORALLfacets {
    qh_fprintf(fp, 9379, "facet");
    FOREACHvertex_(facet->vertices)
      qh_fprintf(fp, 9380, " p%d", qh_pointid(vertex->point));
    zinc_(Zdistio);
    qh_distplane(qh interior_point, facet, &dist);
    qh_fprintf(fp, 9381, " distance= %4.2g\n", dist);
  }
  if (!qh_QUICKhelp) {
    if (qh HALFspace)
      qh_fprintf(fp, 9382, "\n\
These points are the dual of the given halfspaces.  They indicate that\n\
the intersection is degenerate.\n");
    qh_fprintf(fp, 9383,"\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)
      qh_fprintf(fp, 9384, "\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");
  }
  qh_fprintf(fp, 9385, "\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);
    }
    qh_fprintf(fp, 9386, "  %d:  %8.4g  %8.4g  difference= %4.4g\n", k, min, max, max-min);
  }
  if (!qh_QUICKhelp) {
    qh_fprintf(fp, 9387, "\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
    qh_fprintf(fp, 9388, "\
  - recompile qhull for realT precision(#define REALfloat 0 in libqhull.h).\n");
#endif
    qh_fprintf(fp, 9389, "\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)
      qh_fprintf(fp, 9390, "\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 */


/*-----------------------------------------
-user_memsizes- allocate up to 10 additional, quick allocation sizes
*/
void qh_user_memsizes(void) {

  /* qh_memsize(size); */
} /* user_memsizes */

#endif
qhull-2020.2/src/user_eg2/user_eg2.pro0000644060175106010010000000044312541571400015725 0ustar  bbarber# -------------------------------------------------
# user_eg2.pro -- Qt project for Qhull demonstration using the static Qhull library
#
# It uses reentrant Qhull
# -------------------------------------------------

include(../qhull-app-c_r.pri)

TARGET = user_eg2

SOURCES += user_eg2_r.c
qhull-2020.2/src/user_eg2/user_eg2_r.c0000644060175106010010000007054113505430506015700 0ustar  bbarber/*
  ---------------------------------

  user_eg2_r.c

  sample code for calling qhull() from an application.

  See user_eg_r.c for a simpler method using qh_new_qhull().
  The method used here and in unix_r.c gives you additional
  control over Qhull.

  For a C++ example, see user_eg3/user_eg3_r.cpp

  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_r.c and compiled by 'make bin/user_eg2'

   see libqhull_r.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_r.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 "libqhull_r/qhull_ra.h"

/*-------------------------------------------------
-internal function prototypes
*/
void print_summary(qhT *qh);
void makecube(coordT *points, int numpoints, int dim);
void adddiamond(qhT *qh, coordT *points, int numpoints, int numnew, int dim);
void makeDelaunay(qhT *qh, coordT *points, int numpoints, int dim);
void addDelaunay(qhT *qh, coordT *points, int numpoints, int numnew, int dim);
void findDelaunay(qhT *qh, int dim);
void makehalf(coordT *points, int numpoints, int dim);
void addhalf(qhT *qh, coordT *points, int numpoints, int numnew, int dim, coordT *feasible);

/*-------------------------------------------------
-print_summary(qh)
*/
void print_summary(qhT *qh) {
  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; jJOGGLEmax < REALmax/2 && !qh->PREmerge)
    qh_fprintf(qh, qh->ferr, 7096, "qhull warning (user_eg2/adddiamond): joggle 'QJ' is enabled.  Output is simplicial (i.e., triangles in 2-D)\n");

  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(qh, point, !qh_ALL, &bestdist, &isoutside);
    if (isoutside) {
      if (!qh_addpoint(qh, 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(qh);
  else if (qh->KEEPnearinside)
    qh_nearcoplanar(qh);
} /*.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(qhT *qh, coordT *points, int numpoints, int dim) {
  int j,k, seed;
  coordT *point, realr;

  seed= (int)time(NULL); /* time_t to int */
  printf("seed: %d\n", seed);
  qh_RANDOMseed_(qh, seed);
  for (j=0; jJOGGLEmax < REALmax/2 && !qh->PREmerge)
    qh_fprintf(qh, qh->ferr, 7097, "qhull warning (user_eg2/addDelaunay): joggle 'QJ' is enabled.  Output is simplicial (i.e., triangles in 2-D)\n");

  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(qh, dim, 1, point);
    facet= qh_findbestfacet(qh, point, !qh_ALL, &bestdist, &isoutside);
    if (isoutside) {
      if (!qh_addpoint(qh, point, facet, False))
        break;  /* user requested an early exit with 'TVn' or 'TCn' */
    }
    qh_printpoint(qh, stdout, "added point", point);
    printf("%d points, %d extra points, %d vertices, and %d facets in total\n",
                  qh->num_points, qh_setsize(qh, qh->other_points),
                  qh->num_vertices, qh->num_facets);

    /* qh_produce_output(qh); */
  }
  if (qh->DOcheckmax)
    qh_check_maxout(qh);
  else if (qh->KEEPnearinside)
    qh_nearcoplanar(qh);
} /*.addDelaunay.*/

/*--------------------------------------------------
-findDelaunay- find Delaunay triangle or adjacent triangle for [0.5,0.5,...]
  assumes dim < 100
notes:
  See locate a facet with qh_findbestfacet()
  calls qh_setdelaunay() to project the point to a parabaloid
warning:
  Errors if it finds a tricoplanar facet ('Qt').  The corresponding Delaunay triangle
  is in the set of tricoplanar facets or one of their neighbors.  This search
  is not implemented here.
*/
void findDelaunay(qhT *qh, 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(qh, dim, 1, point);
  facet= qh_findbestfacet(qh, point, qh_ALL, &bestdist, &isoutside);
  if (facet->tricoplanar) {
    fprintf(stderr, "findDelaunay: search not implemented for triangulated, non-simplicial Delaunay regions (tricoplanar facet, f%d).\n",
       facet->id);
    qh_errexit(qh, qh_ERRqhull, facet, NULL);
  }
  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; jJOGGLEmax < REALmax/2 && !qh->PREmerge)
    qh_fprintf(qh, qh->ferr, 7098, "qhull warning (user_eg2/addhalf): joggle 'QJ' is enabled.  Output is simplicial (i.e., triangles in 2-D)\n");

  for (j=0; j < numnew ; j++) {
    offset= -1.0;
    for (k=dim; k--; ) {
      if (j/2 == k) {
        normal[k]= sqrt((coordT)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(qh, dim, point, &next, normal, &offset, feasible);
    facet= qh_findbestfacet(qh, point, !qh_ALL, &bestdist, &isoutside);
    if (isoutside) {
      if (!qh_addpoint(qh, point, facet, False))
        break;  /* user requested an early exit with 'TVn' or 'TCn' */
    }
    qh_printpoint(qh, 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, qh->other_points),
                  qh->num_vertices, qh->num_facets);
    /* qh_produce_output(qh); */
  }
  if (qh->DOcheckmax)
    qh_check_maxout(qh);
  else if (qh->KEEPnearinside)
    qh_nearcoplanar(qh);
} /*.addhalf.*/

#define DIM 3     /* dimension of points, must be < 31 for SIZEcube */
#define SIZEcube (1<errexit);
  if (!exitcode) {
    coordT array[TOTpoints][DIM];

    qh->NOerrexit= False;
    strcat(qh->rbox_command, "user_eg2 cube example");
    sprintf(options, "qhull s Tcv Q11 %s ", argc >= 2 ? argv[1] : "");
    qh_initflags(qh, options);
    printf( "\n========\ncompute triangulated convex hull of cube after rotating input\n");
    makecube(array[0], SIZEcube, DIM);
    fflush(NULL);
    qh_init_B(qh, array[0], SIZEcube, DIM, ismalloc);
    qh_qhull(qh);
    qh_check_output(qh);
    qh_triangulate(qh);  /* requires option 'Q11' if want to add points */
    print_summary(qh);
    if (qh->VERIFYoutput && !qh->FORCEoutput && !qh->STOPadd && !qh->STOPcone && !qh->STOPpoint)
      qh_check_points(qh);
    fflush(NULL);
    printf( "\nadd points in a diamond\n");
    adddiamond(qh, array[0], SIZEcube, SIZEdiamond, DIM);
    qh_check_output(qh);
    print_summary(qh);
    qh_produce_output(qh);  /* delete this line to help avoid io_r.c */
    if (qh->VERIFYoutput && !qh->FORCEoutput && !qh->STOPadd && !qh->STOPcone && !qh->STOPpoint)
      qh_check_points(qh);
    fflush(NULL);
  }
  qh->NOerrexit= True;
#ifdef qh_NOmem
  qh_freeqhull(qh, qh_ALL);
#else
  qh_freeqhull(qh, !qh_ALL);
  qh_memfreeshort(qh, &curlong, &totlong);
  if (curlong || totlong)
    fprintf(stderr, "qhull warning (user_eg2, run 1): did not free %d bytes of long memory (%d pieces)\n",
          totlong, curlong);
#endif

  /*
    Run 2: Delaunay triangulation
  */
  qh_init_A(qh, stdin, stdout, stderr, 0, NULL);
  exitcode= setjmp(qh->errexit);
  if (!exitcode) {
    coordT array[TOTpoints][DIM];

    qh->NOerrexit= False;
    strcat(qh->rbox_command, "user_eg2 Delaunay example");
    sprintf(options, "qhull s d Tcv %s", argc >= 3 ? argv[2] : "");
    qh_initflags(qh, options);
    printf( "\n========\ncompute %d-d Delaunay triangulation\n", DIM-1);
    makeDelaunay(qh, 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(qh, array[0], SIZEcube, DIM, ismalloc);
    qh_qhull(qh);
    /* If you want Voronoi ('v') without qh_produce_output(), call
       qh_setvoronoi_all() after qh_qhull() */
    qh_check_output(qh);
    print_summary(qh);
    qh_produce_output(qh);  /* delete this line to help avoid io_r.c */
    if (qh->VERIFYoutput && !qh->FORCEoutput && !qh->STOPadd && !qh->STOPcone && !qh->STOPpoint)
      qh_check_points(qh);
    fflush(NULL);
    printf( "\n========\nadd points to triangulation\n");
    addDelaunay(qh, array[0], SIZEcube, SIZEdiamond, DIM);
    qh_check_output(qh);
    printf("\nfind Delaunay triangle or adjacent triangle closest to [0.5, 0.5, ...]\n");
    findDelaunay(qh, DIM);
    qh_produce_output(qh);  /* delete this line to help avoid io_r.c */
    if (qh->VERIFYoutput && !qh->FORCEoutput && !qh->STOPadd && !qh->STOPcone && !qh->STOPpoint)
      qh_check_points(qh);
    fflush(NULL);
  }
  qh->NOerrexit= True;
#ifdef qh_NOmem
  qh_freeqhull(qh, qh_ALL);
#else
  qh_freeqhull(qh, !qh_ALL);
  qh_memfreeshort(qh, &curlong, &totlong);
  if (curlong || totlong)
    fprintf(stderr, "qhull warning (user_eg2, run 2): did not free %d bytes of long memory (%d pieces)\n",
         totlong, curlong);
#endif

  /*
    Run 3: halfspace intersection
  */
  qh_init_A(qh, stdin, stdout, stderr, 0, NULL);
  exitcode= setjmp(qh->errexit);
  if (!exitcode) {
    coordT array[TOTpoints][DIM+1];  /* +1 for halfspace offset */
    pointT *points;

    qh->NOerrexit= False;
    strcat(qh->rbox_command, "user_eg2 halfspace example");
    sprintf(options, "qhull H0 s Tcv %s", argc >= 4 ? argv[3] : "");
    qh_initflags(qh, options);
    printf( "\n========\ncompute halfspace intersection about the origin for a diamond\n");
    makehalf(array[0], SIZEcube, DIM);
    qh_setfeasible(qh, DIM); /* from io_r.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(qh, DIM+1, SIZEcube, array[0], qh->feasible_point);
    qh_init_B(qh, points, SIZEcube, DIM, True); /* qh_freeqhull frees points */
    qh_qhull(qh);
    fflush(NULL);
    qh_check_output(qh);
    qh_produce_output(qh);  /* delete this line to help avoid io_r.c */
    if (qh->VERIFYoutput && !qh->FORCEoutput && !qh->STOPadd && !qh->STOPcone && !qh->STOPpoint)
      qh_check_points(qh);
    fflush(NULL);
    printf( "\n========\nadd halfspaces for cube to intersection\n");
    addhalf(qh, array[0], SIZEcube, SIZEdiamond, DIM, qh->feasible_point);
    qh_check_output(qh);
    qh_produce_output(qh);  /* delete this line to help avoid io_r.c */
    if (qh->VERIFYoutput && !qh->FORCEoutput && !qh->STOPadd && !qh->STOPcone && !qh->STOPpoint)
      qh_check_points(qh);
    fflush(NULL);
  }
  qh->NOerrexit= True;
  qh->NOerrexit= True;
#ifdef qh_NOmem
  qh_freeqhull(qh, qh_ALL);
#else
  qh_freeqhull(qh, !qh_ALL);
  qh_memfreeshort(qh, &curlong, &totlong);
  if (curlong || totlong)
    fprintf(stderr, "qhull warning (user_eg2, run 3): did not free %d bytes of long memory (%d pieces)\n",
          totlong, curlong);
#endif
  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 libqhull_r.c for 2 facets
*/
void qh_errexit(qhT *qh, int exitcode, facetT *facet, ridgeT *ridge) {
  QHULL_UNUSED(facet);
  QHULL_UNUSED(ridge);

  if (qh->ERREXITcalled) {
    fprintf(qh->ferr, "qhull error while handling previous error in qh_errexit.  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(qhT *qh, const 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(qhT *qh, facetT *facetlist, setT *facets, boolT printall) {
  facetT *facet, **facetp;

  /* remove these calls to help avoid io_r.c */
  qh_printbegin(qh, qh->ferr, qh_PRINTfacets, facetlist, facets, printall);/*io_r.c*/
  FORALLfacet_(facetlist)                                                  /*io_r.c*/
    qh_printafacet(qh, qh->ferr, qh_PRINTfacets, facet, printall);         /*io_r.c*/
  FOREACHfacet_(facets)                                                    /*io_r.c*/
    qh_printafacet(qh, qh->ferr, qh_PRINTfacets, facet, printall);         /*io_r.c*/
  qh_printend(qh, qh->ferr, qh_PRINTfacets, facetlist, facets, printall);  /*io_r.c*/

  FORALLfacet_(facetlist)
    fprintf( qh->ferr, "facet f%d\n", facet->id);
} /* printfacetlist */

/* qh_printhelp_degenerate( fp )
    prints descriptive message for precision error

  notes:
    no message if qh_QUICKhelp
*/
void qh_printhelp_degenerate(qhT *qh, FILE *fp) {

  if (qh->MERGEexact || qh->PREmerge || qh->JOGGLEmax < REALmax/2)
    qh_fprintf(qh, fp, 9368, "\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@qhull.org\n");
  else if (!qh_QUICKhelp) {
    qh_fprintf(qh, fp, 9369, "\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
    qh_fprintf(qh, fp, 9370, "\
\n\
Qhull is currently using single precision arithmetic.  The following\n\
will probably remove the precision problems:\n\
  - recompile qhull for realT precision(#define REALfloat 0 in user_r.h).\n");
#endif
    if (qh->DELAUNAY && !qh->SCALElast && qh->MAXabs_coord > 1e4)
      qh_fprintf(qh, fp, 9371, "\
\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)
      qh_fprintf(qh, fp, 9372, "\
When computing the Delaunay triangulation:\n\
  - use 'Qz' to add a point at-infinity.  This reduces precision problems.\n");

    qh_fprintf(qh, fp, 9373, "\
\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);
    qh_fprintf(qh, fp, 9374, "\
\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 */


/* qh_printhelp_narrowhull( minangle )
     Warn about a narrow hull

  notes:
    Alternatively, reduce qh_WARNnarrow in user_r.h

*/
void qh_printhelp_narrowhull(qhT *qh, FILE *fp, realT minangle) {

    qh_fprintf(qh, fp, 9375, "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 */
} /* printhelp_narrowhull */

/* qh_printhelp_singular
      prints descriptive message for singular input
*/
void qh_printhelp_singular(qhT *qh, FILE *fp) {
  facetT *facet;
  vertexT *vertex, **vertexp;
  realT min, max, *coord, dist;
  int i,k;

  qh_fprintf(qh, fp, 9376, "\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(qh, fp, "", qh->facet_list, NULL, qh_ALL);
  if (!qh_QUICKhelp)
    qh_fprintf(qh, fp, 9377, "\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(qh, fp, "center point", qh->hull_dim, qh->interior_point, -1);
  qh_fprintf(qh, fp, 9378, "\n");
  FORALLfacets {
    qh_fprintf(qh, fp, 9379, "facet");
    FOREACHvertex_(facet->vertices)
      qh_fprintf(qh, fp, 9380, " p%d", qh_pointid(qh, vertex->point));
    zinc_(Zdistio);
    qh_distplane(qh, qh->interior_point, facet, &dist);
    qh_fprintf(qh, fp, 9381, " distance= %4.2g\n", dist);
  }
  if (!qh_QUICKhelp) {
    if (qh->HALFspace)
      qh_fprintf(qh, fp, 9382, "\n\
These points are the dual of the given halfspaces.  They indicate that\n\
the intersection is degenerate.\n");
    qh_fprintf(qh, fp, 9383,"\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)
      qh_fprintf(qh, fp, 9384, "\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");
  }
  qh_fprintf(qh, fp, 9385, "\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);
    }
    qh_fprintf(qh, fp, 9386, "  %d:  %8.4g  %8.4g  difference= %4.4g\n", k, min, max, max-min);
  }
  if (!qh_QUICKhelp) {
    qh_fprintf(qh, fp, 9387, "\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
    qh_fprintf(qh, fp, 9388, "\
  - recompile qhull for realT precision(#define REALfloat 0 in libqhull_r.h).\n");
#endif
    qh_fprintf(qh, fp, 9389, "\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)
      qh_fprintf(qh, fp, 9390, "\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 */


/*-----------------------------------------
-user_memsizes- allocate up to 10 additional, quick allocation sizes
*/
void qh_user_memsizes(qhT *qh) {

  QHULL_UNUSED(qh);
  /* qh_memsize(qh, size); */
} /* user_memsizes */

#endif
qhull-2020.2/src/user_eg3/0000755060175106010010000000000013724321436013476 5ustar  bbarberqhull-2020.2/src/user_eg3/user_eg3.pro0000644060175106010010000000046212550314704015732 0ustar  bbarber# -------------------------------------------------
# user_eg3.pro -- Qt project for cpp demonstration user_eg3.exe
#
# The C++ interface requires reentrant Qhull.
# -------------------------------------------------

include(../qhull-app-cpp.pri)

TARGET = user_eg3
CONFIG -= qt

SOURCES += user_eg3_r.cpp
qhull-2020.2/src/user_eg3/user_eg3_r.cpp0000644060175106010010000006477013710657653016265 0ustar  bbarber#//! user_eg3_r.cpp -- Invoke rbox and qhull from C++

#include "libqhullcpp/RboxPoints.h"
#include "libqhullcpp/QhullError.h"
#include "libqhullcpp/QhullQh.h"
#include "libqhullcpp/QhullFacet.h"
#include "libqhullcpp/QhullFacetList.h"
#include "libqhullcpp/QhullFacetSet.h"
#include "libqhullcpp/QhullLinkedList.h"
#include "libqhullcpp/QhullPoint.h"
#include "libqhullcpp/QhullUser.h"
#include "libqhullcpp/QhullVertex.h"
#include "libqhullcpp/QhullVertexSet.h"
#include "libqhullcpp/Qhull.h"

#include    /* for printf() of help message */
#include  // setw
#include 
#include 

using std::cerr;
using std::cin;
using std::cout;
using std::endl;

using orgQhull::Qhull;
using orgQhull::QhullError;
using orgQhull::QhullFacet;
using orgQhull::QhullFacetList;
using orgQhull::QhullFacetListIterator;
using orgQhull::QhullFacetSet;
using orgQhull::QhullFacetSetIterator;
using orgQhull::QhullPoint;
using orgQhull::QhullPoints;
using orgQhull::QhullPointsIterator;
using orgQhull::QhullQh;
using orgQhull::QhullUser;
using orgQhull::QhullVertex;
using orgQhull::QhullVertexList;
using orgQhull::QhullVertexListIterator;
using orgQhull::QhullVertexSet;
using orgQhull::QhullVertexSetIterator;
using orgQhull::RboxPoints;

int main(int argc, char **argv);
int user_eg3(int argc, char **argv);

char prompt[]= "\n========\n\
user_eg3 commands... -- demonstrate calling rbox and qhull from C++.\n\
\n\
user_eg3 is statically linked to qhullcpp and reentrant qhull.  If user_eg3\n\
fails immediately, it is probably linked to the non-reentrant qhull library.\n\
\n\
Commands:\n\
  eg-100               Run the example in qh-code.htm\n\
  eg-convex            'rbox d | qconvex o' with std::vector and C++ classes\n\
  eg-delaunay          'rbox y c | qdelaunay o' with std::vector and C++ classes\n\
  eg-voronoi           'rbox y c | qvoronoi o' with std::vector and C++ classes\n\
  eg-fifo              'rbox y c | qvoronoi FN Fi Fo' with QhullUser and qh_fprintf\n\
\n\
Rbox and Qhull commands:\n\
  rbox \"200 D4\" ...    Generate points from rbox\n\
  qhull \"d p\" ...      Run qhull with options and produce output\n\
  qhull-cout \"o\" ...   Run qhull with options and produce output to cout\n\
  qhull \"T1\" ...       Run qhull with level-1 trace to cerr\n\
  qhull-cout \"T1z\" ... Run qhull with level-1 trace to cout\n\
  facets               Print qhull's facets when done\n\
\n\
For example\n\
  user_eg3 rbox qhull\n\
  user_eg3 rbox qhull T1\n\
  user_eg3 rbox qhull d\n\
  user_eg3 rbox D2 10 2 \"s r 5\" qhull \"s p\" facets\n\
  user_eg3 eg-convex\n\
  user_eg3 rbox 10 eg-delaunay qhull \"d o\"\n\
  user_eg3 rbox D5 c P2 qhull d eg-delaunay\n\
  user_eg3 rbox \"D5 c P2\" qhull v eg-voronoi o\n\
  user_eg3 rbox D2 10 qhull \"v\" eg-fifo p Fi Fo\n\
";
// single quotes OK in Unix but not OK in Windows cmd.exe

/*--------------------------------------------
-user_eg3-  main procedure of user_eg3 application
*/
int main(int argc, char **argv){

    QHULL_LIB_CHECK

    if(argc==1){
        cout << prompt;
        return 0;
    }
    try{
        return user_eg3(argc, argv);
    }catch(QhullError &e){
        cerr << e.what() << std::endl;
        return e.errorCode();
    }
}//main

void printDoubles(const std::vector &doubles)
{
    for(size_t i= 0; i < doubles.size(); i++){
        cout << std::setw(6) << doubles[i] << " ";
    }
}//printDoubles

void printInts(const std::vector &ints)
{
    for(size_t i= 0; i < ints.size(); i++){
        cout << ints[i] << " ";
    }
}//printInts

void qconvex_o(const Qhull &qhull)
{
    int dim= qhull.hullDimension();
    int numfacets= qhull.facetList().count();
    int totneighbors= numfacets * dim;  /* incorrect for non-simplicial facets, see qh_countfacets */
    cout << dim << "\n" << qhull.points().size() << " " << numfacets << " " << totneighbors/2 << "\n";
    std::vector > points;
    // for(QhullPoint point : qhull.points())
    for(QhullPoints::ConstIterator i= qhull.points().begin(); i != qhull.points().end(); ++i){
        QhullPoint point= *i;
        points.push_back(point.toStdVector());
    }
    // for(std::vector point : points){
    for(size_t j= 0; j < points.size(); ++j){
        std::vector point= points[j];
        size_t n= point.size();
        for(size_t i= 0; i < n; ++i){
            if(i < n-1){
                cout << std::setw(6) << point[i] << " ";
            }else{
                cout << std::setw(6) << point[i] << "\n";
            }
        }
    }
    QhullFacetList facets= qhull.facetList();
    std::vector > facetVertices;
    // for(QhullFacet f : facets)
    QhullFacetListIterator j(facets);
    while(j.hasNext()){
        QhullFacet f= j.next();
        std::vector vertices;
        if(!f.isGood()){
            // ignore facet
        }else if(!f.isTopOrient() && f.isSimplicial()){ /* orient the vertices like option 'o' */
            QhullVertexSet vs= f.vertices();
            vertices.push_back(vs[1].point().id());
            vertices.push_back(vs[0].point().id());
            for(int i= 2; i<(int)vs.size(); ++i){
                vertices.push_back(vs[i].point().id());
            }
            facetVertices.push_back(vertices);
        }else{  /* note: for non-simplicial facets, this code does not duplicate option 'o', see qh_facet3vertex and qh_printfacetNvertex_nonsimplicial */
            // for(QhullVertex vertex : f.vertices()){
            QhullVertexSetIterator k(f.vertices());
            while(k.hasNext()){
                QhullVertex vertex= k.next();
                QhullPoint p= vertex.point();
                vertices.push_back(p.id());
            }
            facetVertices.push_back(vertices);
        }
    }
    // for(std::vector vertices : facetVertices)
    for(size_t k= 0; k vertices= facetVertices[k];
        size_t n= vertices.size();
        cout << n << " ";
        for(size_t i= 0; i > inputSites;
    QhullPoints points= qhull.points();
    // for(QhullPoint point : points)
    QhullPointsIterator j(points);
    while(j.hasNext()){
        QhullPoint point= j.next();
        inputSites.push_back(point.toStdVector());
    }

    // Printer header and Voronoi vertices
    QhullFacetList facets= qhull.facetList();
    int numFacets= facets.count();
    size_t numRidges= numFacets*hullDimension/2;  // only for simplicial facets
    cout << hullDimension << "\n" << inputSites.size() << " " << numFacets << " " << numRidges << "\n";
    // for(std::vector site : inputSites)
    for(size_t k= 0; k < inputSites.size(); ++k){
        std::vector site= inputSites[k];
        size_t n= site.size();
        for(size_t i= 0; i > regions;
    // for(QhullFacet f : facets)
    QhullFacetListIterator k(facets);
    while(k.hasNext()){
        QhullFacet f= k.next();
        std::vector vertices;
        if(!f.isUpperDelaunay()){
            if(!f.isTopOrient() && f.isSimplicial()){ /* orient the vertices like option 'o' */
                QhullVertexSet vs= f.vertices();
                vertices.push_back(vs[1].point().id());
                vertices.push_back(vs[0].point().id());
                for(int i= 2; i<(int)vs.size(); ++i){
                    vertices.push_back(vs[i].point().id());
                }
            }else{  /* note: for non-simplicial facets, this code does not duplicate option 'o', see qh_facet3vertex and qh_printfacetNvertex_nonsimplicial */
                // for(QhullVertex vertex : f.vertices()){
                QhullVertexSetIterator i(f.vertices());
                while(i.hasNext()){
                    QhullVertex vertex= i.next();
                    QhullPoint p= vertex.point();
                    vertices.push_back(p.id());
                }
            }
            regions.push_back(vertices);
        }
    }
    // for(std::vector vertices : regions)
    for(size_t k2= 0; k2 < regions.size(); ++k2){
        std::vector vertices= regions[k2];
        size_t n= vertices.size();
        cout << n << " ";
        for(size_t i= 0; iqh());
    qhull->outputQhull(printOption); // qh_fprintf writes its results into 'results'
    int n= results.numResults();
    if(results.firstCode()!=9231){
        cout << "user_eg3 error (qvoronoi_fifo): 'qhull " << printOption << "' did not produce output for 'Fi' or 'Fo'\nqh_fprintf codes: ";
        printInts(results.codes());
        cout << "\n";
        return;
    }else if(n != results.numDoubles() || n != results.numInts()){
        cout << "user_eg3 error (qvoronoi_fifo): Expecting doubles and ints for " << n << " results.  Got " << results.numDoubles() << " doubles and " << results.numInts() << " ints.  Did an error occur?\nqh_fprintf codes: ";
        printInts(results.codes());
        cout << "\n";
        return;
    }
    cout << n << "\n";
    for(int i= 0; i > voronoiVertices;
    std::vector vertexAtInfinity;
    for(int i= 0; i voronoiVertex : voronoiVertices)
    for(size_t k= 0; k < voronoiVertices.size(); ++k){
        std::vector voronoiVertex= voronoiVertices[k];
        size_t n= voronoiVertex.size();
        for(size_t i= 0; i > voronoiRegions(numpoints); // qh_printvoronoi calls qh_pointvertex via qh_markvoronoi
    // for(QhullVertex vertex : qhull.vertexList())
    QhullVertexListIterator j2(qhull.vertexList());
    while(j2.hasNext()){
        QhullVertex vertex= j2.next();
        size_t numinf= 0;
        std::vector voronoiRegion;
        //for(QhullFacet neighbor : vertex.neighborFacets())
        QhullFacetSetIterator k2(vertex.neighborFacets());
        while(k2.hasNext()){
            QhullFacet neighbor= k2.next();
            if(neighbor.visitId()==0){
                if(!numinf){
                    numinf= 1;
                    voronoiRegion.push_back(0); // the voronoiVertex at infinity indicates an unbounded region
                }
            }else if(neighbor.visitId() numinf){
            int siteId= vertex.point().id();
            if(siteId>=0 && siteId voronoiRegion : voronoiRegions)
    for(size_t k3= 0; k3 < voronoiRegions.size(); ++k3){
        std::vector voronoiRegion= voronoiRegions[k3];
        size_t n= voronoiRegion.size();
        cout << n;
        for(size_t i= 0; i > voronoiVertices;
    // for(QhullFacet facet : qhull.facetList())
    QhullFacetListIterator j(qhull.facetList());
    while(j.hasNext()){
        QhullFacet facet= j.next();
        if(facet.visitId() && facet.visitId() voronoiVertex : voronoiVertices)
    for(size_t k= 0; k < voronoiVertices.size(); ++k){
        std::vector voronoiVertex= voronoiVertices[k];
        size_t n= voronoiVertex.size();
        for(size_t i= 0; i > voronoiRegions(numpoints); // qh_printvoronoi calls qh_pointvertex via qh_markvoronoi
    //for(QhullVertex vertex : qhull.vertexList()){
    QhullVertexListIterator j2(qhull.vertexList());
    while(j2.hasNext()){
        QhullVertex vertex= j2.next();
        size_t numinf= 0;
        std::vector voronoiRegion;
        // for(QhullFacet neighbor : vertex.neighborFacets())
        QhullFacetSetIterator k(vertex.neighborFacets());
        while(k.hasNext()){
            QhullFacet neighbor= k.next();
            if(neighbor.visitId()==0){
                if(!numinf){
                    numinf= 1;
                    voronoiRegion.push_back(-1); // -1 indicates the Voronoi vertex at infinity
                }
            }else if(neighbor.visitId() numinf){
            int siteId= vertex.point().id();
            if(siteId>=0 && siteId voronoiRegion : voronoiRegions)
    for(size_t j3= 0; j3 < voronoiRegions.size(); ++j3){
        std::vector voronoiRegion= voronoiRegions[j3];
        size_t n= voronoiRegion.size();
        cout << n;
        for(size_t i= 0; i1){
            cout << "\nInput points and facetlist for '" << qhull.qhullCommand() << "' via C++ classes\n";
            qconvex_o(qhull);
        }else if(strcmp(argv[i], "eg-convex")==0 && !rbox.isEmpty()){
            Qhull q(rbox, "");
            cout << "\nInput points and facetlist for convex hull of " << q.rboxCommand() << " via C++ classes\n";
            qconvex_o(q);
            noRboxOutput= true;
        }else if(strcmp(argv[i], "eg-convex")==0){
            cout << "\nA 3-d diamond (rbox d)\n";
            RboxPoints diamond("d");
            cout << diamond;
            cout << "\nInput points and facetlist of its convex hull (qhull o)\n";
            Qhull q(diamond, "o");
            q.setOutputStream(&cout);
            q.outputQhull();
            // q.outputQhull("o") produces the same output
            cout << "\nInput points and facetlist using std::vector and C++ classes\n";
            qconvex_o(q);
            cout << "\nIts outward pointing normals as vector plus offset (qhull n)\n";
            q.outputQhull("n");
        }else if(strcmp(argv[i], "eg-delaunay")==0 && readingQhull>1 && qhull.isDelaunay()){
            cout << "\nVertices and Delaunay regions of paraboloid from '" << qhull.qhullCommand() << "' via C++ classes\n";
            qdelaunay_o(qhull);
        }else if(strcmp(argv[i], "eg-delaunay")==0 && !rbox.isEmpty()){
            cout << "\nDelaunay triangulation of " << rbox.count() << " points as " << rbox.dimension()+1 << "-d paraboloid via C++ classes\n";
            Qhull q(rbox, "d");
            qdelaunay_o(q);
            noRboxOutput= true;
        }else if(strcmp(argv[i], "eg-delaunay")==0){
            cout << "\nA 2-d triangle in a square (rbox y c D2)\n";
            RboxPoints triangleSquare("y c D2");
            cout << triangleSquare;
            cout << "\nThe 2-d input sites are lifted to a 3-d paraboloid.\n";
            cout << "A Delaunay region is a facet of the paraboloid's convex hull.\n";
            cout << "\nThe Delaunay triangulation as input sites and Delaunay regions (qhull d o)\n";
            Qhull q(triangleSquare, "d o");
            q.setOutputStream(&cout);
            q.outputQhull();
            // q.outputQhull("o") produces the same output
            cout << "\nThe same results using std::vector and C++ classes\n";
            qdelaunay_o(q);
        }else if(strcmp(argv[i], "eg-voronoi")==0 && readingQhull>1 && qhull.isDelaunay()){
            cout << "\nVoronoi vertices and regions for '" << qhull.qhullCommand() << "' via C++ classes\n";
            bool isLower;            //not used
            int voronoiVertexCount;  //not used
            qhull.prepareVoronoi(&isLower, &voronoiVertexCount); // not needed if previous output from Qhull
            qvoronoi_o(qhull);
        }else if(strcmp(argv[i], "eg-voronoi")==0 && !rbox.isEmpty()){
            Qhull q(rbox, "v");
            cout << "\nVoronoi vertices and regions for " << q.rboxCommand() << " via C++ classes\n";
            bool isLower;
            int voronoiVertexCount;
            q.prepareVoronoi(&isLower, &voronoiVertexCount);
            qvoronoi_o(q);
            noRboxOutput= true;
        }else if(strcmp(argv[i], "eg-voronoi")==0){
            cout << "\nA 2-d triangle in a square (rbox y c D2)\n";
            RboxPoints triangleSquare("y c D2");
            cout << triangleSquare;
            cout << "\nIts Voronoi diagram as vertices and regions (qhull v o)\n";
            cout << "The Voronoi diagram is the dual of the Delaunay triangulation\n";
            cout << "Voronoi vertices are Delaunay regions, and Voronoi regions are Delaunay input sites\n";
            cout << "The Voronoi vertex at infinity is represented as '-10.101 -10.101'\n";
            Qhull q(triangleSquare, "v o");
            q.setOutputStream(&cout);
            q.outputQhull();
            // q.outputQhull("o") produces the same output
            cout << "\nThe same results using std::vector and C++ classes\n";
            cout << "Qhull::prepareVoronoi assigns facetT.visit_id and vertexT.neighbors\n";
            cout << "The Voronoi regions are rotated by one Voronoi vertex (prepareVoronoi occurs twice)\n";
            bool isLower;
            int voronoiVertexCount;
            q.prepareVoronoi(&isLower, &voronoiVertexCount); // Also called by q.outputQhull("o"), hence the rotated vertices
            qvoronoi_o(q);
        }else if(strcmp(argv[i], "eg-fifo")==0 && readingQhull>1 && qhull.isDelaunay()){
            cout << "\nVoronoi vertices for '" << qhull.qhullCommand() << "' via C++ classes\n";
            bool isLower;
            int voronoiVertexCount;
            qhull.prepareVoronoi(&isLower, &voronoiVertexCount);
            qvoronoi_pfn(qhull);
            cout << "\nHyperplanes for bounded facets between Voronoi regions via QhullUser and qh_fprintf\n";
            qvoronoi_fifo(&qhull, "Fi");
            cout << "\nHyperplanes for unbounded facets between Voronoi regions via QhullUser and qh_fprintf\n";
            qvoronoi_fifo(&qhull, "Fo");
        }else if(strcmp(argv[i], "eg-fifo")==0 && !rbox.isEmpty()){
            Qhull q(rbox, "v");
            cout << "\nVoronoi vertices for " << q.rboxCommand() << " via QhullUser and qh_fprintf\n";
            bool isLower;
            int voronoiVertexCount;
            q.prepareVoronoi(&isLower, &voronoiVertexCount);
            qvoronoi_pfn(q);
            cout << "\nHyperplanes for bounded facets between Voronoi regions via QhullUser and qh_fprintf\n";
            qvoronoi_fifo(&q, "Fi");
            cout << "\nHyperplanes for unbounded facets between Voronoi regions via QhullUser and qh_fprintf\n";
            qvoronoi_fifo(&q, "Fo");
            noRboxOutput= true;
        }else if(strcmp(argv[i], "eg-fifo")==0){
            cout << "\nA 2-d triangle in a square (rbox y c D2)\n";
            RboxPoints triangleSquare("y c D2");
            cout << triangleSquare;
            cout << "\nIts Voronoi vertices (qhull v p)\n";
            cout << "This is the first part of eg-voronoi, but without infinity\n";
            Qhull q(triangleSquare, "v p");
            q.setOutputStream(&cout);
            q.outputQhull();
            cout << "\nIts Voronoi regions (qhull v FN)\n";
            cout << "This is the second part of eg-voronoi, with ids one less\n";
            cout << "Regions are ordered by the corresponding input site.\n";
            q.outputQhull("FN");
            // q.outputQhull("p FN") produces the same outputs
            cout << "\nThe same results as 'qhull v p FN' using std::vector and C++ classes\n";
            cout << "Qhull::prepareVoronoi assigns facet.visit_id and vertex.neighbors\n";
            cout << "prepareVoronoi is also called by q.outputQhull(\"FN\"), hence the rotated vertices\n";
            bool isLower;
            int voronoiVertexCount;
            q.prepareVoronoi(&isLower, &voronoiVertexCount); // Also called by q.outputQhull("o"), hence the rotated vertices
            qvoronoi_pfn(q);
            cout << "\nHyperplanes for bounded facets between Voronoi regions (qhull v Fi)\n";
            cout << "Each hyperplane is the perpendicular bisector of 2 input sites.\n";
            q.outputQhull("Fi");
            cout << "\nHyperplanes for unbounded rays of unbounded facets (qhull v Fo)\n";
            cout << "Each ray goes through the midpoint of 2 input sites, oriented outwards\n";
            q.outputQhull("Fo");
            cout << "\nThe same result as 'qhull v Fi' using QhullUser and its custom qh_fprintf\n";
            cout << "qh_fprintf captures the output from qh_eachvoronoi in io_r.c (qhull v Fi Fo Ta)\n";
            qvoronoi_fifo(&q, "Fi");
            cout << "\nThe same result as 'qhull v Fo' using QhullUser and its custom qh_fprintf\n";
            qvoronoi_fifo(&q, "Fo");
        }else if(strcmp(argv[i], "rbox")==0){
            if(readingRbox!=0 || readingQhull!=0){
                cerr << "user_eg3 -- \"rbox\" must be first" << endl;
                return 1;
            }
            readingRbox++;
        }else if(strcmp(argv[i], "qhull")==0
        || strcmp(argv[i], "qhull-cout")==0){
            if(readingQhull){
                cerr << "user_eg3 -- only one \"qhull\" or \"qhull-cout\" allowed." << endl;
                return 1;
            }
            if(strcmp(argv[i], "qhull-cout")==0){
                qhull.setOutputStream(&cout);
            }
            if(rbox.isEmpty()){
                if(readingRbox){
                    if(rbox.dimension()==0){
                        rbox.setDimension(2);
                    }
                    rbox.appendPoints("10");
                }else{
                    cerr << "Enter dimension followed by count followed by coordinates.  End with ^Z (Windows) or ^D (Unix).\n";
                    rbox.appendPoints(cin);
                }
            }
            readingQhull++;
            readingRbox= 0;
        }else if(strcmp(argv[i], "facets")==0){
            printFacets= true;
        }else if(readingRbox){
            readingRbox++;
            cerr << "rbox " << argv[i] << endl;
            rbox.appendPoints(argv[i]);
            if(rbox.hasRboxMessage()){
                cerr << "user_eg3 " << argv[i] << " -- " << rbox.rboxMessage();
                return rbox.rboxStatus();
            }
        }else if(readingQhull){
            if(readingQhull==1){
                qhull.runQhull(rbox, argv[i]);
                qhull.outputQhull();
            }else{
                qhull.outputQhull(argv[i]);
            }
            readingQhull++;
            if(qhull.hasQhullMessage()){
                cerr << "\nResults of " << argv[i] << "\n" << qhull.qhullMessage();
                qhull.clearQhullMessage();
            }
        }else{
            cerr << "user_eg3 error: Expecting eg-100, eg-convex, eg-delaunay, eg-voronoi, eg-fifo, qhull, qhull-cout, or rbox.  Got " << argv[i] << endl;
            return 1;
        }
    }//foreach argv
    if(readingRbox && !noRboxOutput){
        cout << rbox;
        return 0;
    }
    if(readingQhull==1){ // e.g., rbox 10 qhull
        qhull.runQhull(rbox, "");
        qhull.outputQhull();
        if(qhull.hasQhullMessage()){
            cerr << "\nResults of qhull\n" << qhull.qhullMessage();
            qhull.clearQhullMessage();
        }
    }
    if(qhull.hasOutputStream()){
        return 0;
    }
    if(printFacets){
        QhullFacetList facets= qhull.facetList();
        cout << "\nFacets created by Qhull::runQhull()\n" << facets;
    }
    return 0;
}//user_eg3