Revision: 77315
          http://sourceforge.net/p/brlcad/code/77315
Author:   starseeker
Date:     2020-10-01 21:41:50 +0000 (Thu, 01 Oct 2020)
Log Message:
-----------
gdiam is another easy one, without any particular upstream activity.

Modified Paths:
--------------
    brlcad/trunk/INSTALL
    brlcad/trunk/configure
    brlcad/trunk/doc/legal/embedded/CMakeLists.txt
    brlcad/trunk/doc/legal/other/CMakeLists.txt
    brlcad/trunk/misc/win32-msvc/Dll/CMakeLists.txt
    brlcad/trunk/src/external/Creo/CMakeLists.txt
    brlcad/trunk/src/external/Cubit/CMakeLists.txt
    brlcad/trunk/src/external/Unigraphics/CMakeLists.txt
    brlcad/trunk/src/librt/CMakeLists.txt
    brlcad/trunk/src/other/CMakeLists.txt

Added Paths:
-----------
    brlcad/trunk/doc/legal/embedded/gdiam.txt
    brlcad/trunk/src/librt/gdiam/
    brlcad/trunk/src/librt/gdiam/LICENSE.MIT
    brlcad/trunk/src/librt/gdiam/README
    brlcad/trunk/src/librt/gdiam/gdiam.cpp
    brlcad/trunk/src/librt/gdiam/gdiam.hpp
    brlcad/trunk/src/librt/gdiam/gdiam_test.cpp

Removed Paths:
-------------
    brlcad/trunk/doc/legal/other/libgdiam.txt
    brlcad/trunk/src/other/libgdiam/
    brlcad/trunk/src/other/libgdiam.dist

Modified: brlcad/trunk/INSTALL
===================================================================
--- brlcad/trunk/INSTALL        2020-10-01 21:19:02 UTC (rev 77314)
+++ brlcad/trunk/INSTALL        2020-10-01 21:41:50 UTC (rev 77315)
@@ -681,17 +681,6 @@
 Aliases:  ENABLE_OPENSCENEGRAPH
 
 
---- BRLCAD_GDIAM ---
-
-Option for enabling and disabling compilation of the libgdiam approximate
-tight bounding box library provided with BRL-CAD's source code.  Default
-is AUTO, responsive to the toplevel BRLCAD_BUNDLED_LIBS option and
-testing first for a system version if BRLCAD_BUNDLED_LIBS is also
-AUTO.
-
-Aliases:  ENABLE_GDIAM
-
-
 --- BRLCAD_PROJ4 ---
 
 Option for enabling and disabling compilation of the PROJ.4 geographic

Modified: brlcad/trunk/configure
===================================================================
--- brlcad/trunk/configure      2020-10-01 21:19:02 UTC (rev 77314)
+++ brlcad/trunk/configure      2020-10-01 21:41:50 UTC (rev 77315)
@@ -178,10 +178,6 @@
                                   shift;;
      --disable-openscenegraph)                options="$options 
-DBRLCAD_OSG=SYSTEM";
                                   shift;;
-     --enable-gdiam)                options="$options -DBRLCAD_GDIAM=BUNDLED";
-                                  shift;;
-     --disable-gdiam)                options="$options -DBRLCAD_GDIAM=SYSTEM";
-                                  shift;;
      --enable-proj4)                options="$options -DBRLCAD_PROJ4=BUNDLED";
                                   shift;;
      --disable-proj4)                options="$options -DBRLCAD_PROJ4=SYSTEM";

Modified: brlcad/trunk/doc/legal/embedded/CMakeLists.txt
===================================================================
--- brlcad/trunk/doc/legal/embedded/CMakeLists.txt      2020-10-01 21:19:02 UTC 
(rev 77314)
+++ brlcad/trunk/doc/legal/embedded/CMakeLists.txt      2020-10-01 21:41:50 UTC 
(rev 77315)
@@ -23,6 +23,7 @@
   gecode.txt
   gdal_gcv_plugin1.txt
   gdal_gcv_plugin2.txt
+  gdiam.txt
   halfedge.txt
   humanize.txt
   hv3.txt

Copied: brlcad/trunk/doc/legal/embedded/gdiam.txt (from rev 77314, 
brlcad/trunk/doc/legal/other/libgdiam.txt)
===================================================================
--- brlcad/trunk/doc/legal/embedded/gdiam.txt                           (rev 0)
+++ brlcad/trunk/doc/legal/embedded/gdiam.txt   2020-10-01 21:41:50 UTC (rev 
77315)
@@ -0,0 +1,23 @@
+Copyright 2001 Sariel Har-Peled ([email protected])
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+file:/src/librt/gdiam/gdiam.cpp
+file:/src/librt/gdiam/gdiam.hpp
+

Modified: brlcad/trunk/doc/legal/other/CMakeLists.txt
===================================================================
--- brlcad/trunk/doc/legal/other/CMakeLists.txt 2020-10-01 21:19:02 UTC (rev 
77314)
+++ brlcad/trunk/doc/legal/other/CMakeLists.txt 2020-10-01 21:41:50 UTC (rev 
77315)
@@ -4,7 +4,6 @@
   incrTcl.txt
   libbson.txt
   libbson_yajl.txt
-  libgdiam.txt
   libnetpbm.txt
   libpng.txt
   libregex.txt

Deleted: brlcad/trunk/doc/legal/other/libgdiam.txt
===================================================================
--- brlcad/trunk/doc/legal/other/libgdiam.txt   2020-10-01 21:19:02 UTC (rev 
77314)
+++ brlcad/trunk/doc/legal/other/libgdiam.txt   2020-10-01 21:41:50 UTC (rev 
77315)
@@ -1,20 +0,0 @@
-Copyright 2001 Sariel Har-Peled ([email protected])
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-

Modified: brlcad/trunk/misc/win32-msvc/Dll/CMakeLists.txt
===================================================================
--- brlcad/trunk/misc/win32-msvc/Dll/CMakeLists.txt     2020-10-01 21:19:02 UTC 
(rev 77314)
+++ brlcad/trunk/misc/win32-msvc/Dll/CMakeLists.txt     2020-10-01 21:41:50 UTC 
(rev 77315)
@@ -38,7 +38,6 @@
   libbn-static
   libbrep-static
   libbu-static
-  gdiam-static
   libged-static
   regex-static
   librt-static
@@ -118,7 +117,6 @@
   libbn-static
   libbrep-static
   libbu-static
-  gdiam-static
   libged-static
   regex-static
   librt-static

Modified: brlcad/trunk/src/external/Creo/CMakeLists.txt
===================================================================
--- brlcad/trunk/src/external/Creo/CMakeLists.txt       2020-10-01 21:19:02 UTC 
(rev 77314)
+++ brlcad/trunk/src/external/Creo/CMakeLists.txt       2020-10-01 21:41:50 UTC 
(rev 77315)
@@ -38,7 +38,7 @@
   set(CREO_DEFS "-DPRO_MACHINE=36 -DPRO_OS=4 -DPRO_USE_VAR_ARGS 
-D_USING_V100_SDK71_")
 
   # BRL-CAD definitions
-  set(BRLCAD_DEFS "-DHAVE_CONFIG_H -DBRLCAD_DLL -DBRLCADBUILD -DBU_DLL_IMPORTS 
-DBN_DLL_IMPORTS -DNMG_DLL_IMPORTS -DBG_DLL_IMPORTS -DBREP_DLL_IMPORTS 
-DRT_DLL_IMPORTS -DWDB_DLL_IMPORTS -DTIE_DLL_IMPORTS -DDB5_DLL_IMPORTS 
-DGDIAM_DLL_IMPORTS -DON_DLL_IMPORTS")
+  set(BRLCAD_DEFS "-DHAVE_CONFIG_H -DBRLCAD_DLL -DBRLCADBUILD -DBU_DLL_IMPORTS 
-DBN_DLL_IMPORTS -DNMG_DLL_IMPORTS -DBG_DLL_IMPORTS -DBREP_DLL_IMPORTS 
-DRT_DLL_IMPORTS -DWDB_DLL_IMPORTS -DTIE_DLL_IMPORTS -DDB5_DLL_IMPORTS 
-DON_DLL_IMPORTS")
 
   # These settings are global to all the configs.
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CREO_DEFS} ${BRLCAD_DEFS}" CACHE 
STRING "" FORCE)
@@ -207,7 +207,6 @@
     libnmg
     librt
     libwdb
-    gdiam
     openNURBS
     poly2tri
     regex_brl
@@ -369,7 +368,6 @@
     set_property(TARGET creo-brl APPEND PROPERTY COMPILE_DEFINITIONS 
"DB5_DLL_IMPORTS")
     set_property(TARGET creo-brl APPEND PROPERTY COMPILE_DEFINITIONS 
"WDB_DLL_IMPORTS")
     set_property(TARGET creo-brl APPEND PROPERTY COMPILE_DEFINITIONS 
"TIE_DLL_IMPORTS")
-    set_property(TARGET creo-brl APPEND PROPERTY COMPILE_DEFINITIONS 
"GDIAM_DLL_IMPORTS")
     set_property(TARGET creo-brl APPEND PROPERTY COMPILE_DEFINITIONS 
"ON_DLL_IMPORTS")
   endif(HIDE_INTERNAL_SYMBOLS)
 

Modified: brlcad/trunk/src/external/Cubit/CMakeLists.txt
===================================================================
--- brlcad/trunk/src/external/Cubit/CMakeLists.txt      2020-10-01 21:19:02 UTC 
(rev 77314)
+++ brlcad/trunk/src/external/Cubit/CMakeLists.txt      2020-10-01 21:41:50 UTC 
(rev 77315)
@@ -35,7 +35,6 @@
     set_property(TARGET g-sat APPEND PROPERTY COMPILE_DEFINITIONS 
"DB5_DLL_IMPORTS")
     set_property(TARGET g-sat APPEND PROPERTY COMPILE_DEFINITIONS 
"WDB_DLL_IMPORTS")
     set_property(TARGET g-sat APPEND PROPERTY COMPILE_DEFINITIONS 
"TIE_DLL_IMPORTS")
-    set_property(TARGET g-sat APPEND PROPERTY COMPILE_DEFINITIONS 
"GDIAM_DLL_IMPORTS")
     set_property(TARGET g-sat APPEND PROPERTY COMPILE_DEFINITIONS 
"ON_DLL_IMPORTS")
     set_property(TARGET g-sat APPEND PROPERTY COMPILE_DEFINITIONS 
"TINYCTHREAD_DLL_IMPORTS")
   endif(HIDE_INTERNAL_SYMBOLS)

Modified: brlcad/trunk/src/external/Unigraphics/CMakeLists.txt
===================================================================
--- brlcad/trunk/src/external/Unigraphics/CMakeLists.txt        2020-10-01 
21:19:02 UTC (rev 77314)
+++ brlcad/trunk/src/external/Unigraphics/CMakeLists.txt        2020-10-01 
21:41:50 UTC (rev 77315)
@@ -40,10 +40,8 @@
       set_property(TARGET ug-g APPEND PROPERTY COMPILE_DEFINITIONS 
"DB5_DLL_IMPORTS")
       set_property(TARGET ug-g APPEND PROPERTY COMPILE_DEFINITIONS 
"WDB_DLL_IMPORTS")
       set_property(TARGET ug-g APPEND PROPERTY COMPILE_DEFINITIONS 
"TIE_DLL_IMPORTS")
-      set_property(TARGET ug-g APPEND PROPERTY COMPILE_DEFINITIONS 
"GDIAM_DLL_IMPORTS")
       set_property(TARGET ug-g APPEND PROPERTY COMPILE_DEFINITIONS 
"ON_DLL_IMPORTS")
       set_property(TARGET ug-g APPEND PROPERTY COMPILE_DEFINITIONS 
"TINYCTHREAD_DLL_IMPORTS")
-      set_property(TARGET ug-g APPEND PROPERTY COMPILE_DEFINITIONS 
"LZ4_DLL_IMPORT=1")
     endif(HIDE_INTERNAL_SYMBOLS)
 
   endif (BRLCAD_ENABLE_TCL)

Modified: brlcad/trunk/src/librt/CMakeLists.txt
===================================================================
--- brlcad/trunk/src/librt/CMakeLists.txt       2020-10-01 21:19:02 UTC (rev 
77314)
+++ brlcad/trunk/src/librt/CMakeLists.txt       2020-10-01 21:41:50 UTC (rev 
77315)
@@ -20,8 +20,8 @@
 set(RT_LOCAL_INCLUDE_DIRS
   ${CMAKE_CURRENT_SOURCE_DIR}
   ${CMAKE_CURRENT_SOURCE_DIR}/vds
+  ${CMAKE_CURRENT_SOURCE_DIR}/gdiam
   ${REGEX_INCLUDE_DIRS}
-  ${GDIAM_INCLUDE_DIRS}
   )
 
 BRLCAD_LIB_INCLUDE_DIRS(rt RT_INCLUDE_DIRS RT_LOCAL_INCLUDE_DIRS)
@@ -68,6 +68,7 @@
   dir.c
   dspline.c
   fortray.c
+  gdiam/gdiam.cpp
   globals.c
   htbl.c
   ls.c
@@ -363,21 +364,15 @@
   set(SPR_LIB libSPR)
 endif(BRLCAD_ENABLE_SPR)
 
-BRLCAD_ADDLIB(librt "${LIBRT_SOURCES}" 
"${OPENCL_LIBS};${GDIAM_LIBRARY};libbrep;libnmg;libbg;libbn;libbu;${OPENNURBS_LIBRARIES};${REGEX_LIBRARIES};${WINSOCK_LIB};${RPCRT_LIB};${STDCXX_LIBRARIES}")
+BRLCAD_ADDLIB(librt "${LIBRT_SOURCES}" 
"${OPENCL_LIBS};libbrep;libnmg;libbg;libbn;libbu;${OPENNURBS_LIBRARIES};${REGEX_LIBRARIES};${WINSOCK_LIB};${RPCRT_LIB};${STDCXX_LIBRARIES}")
 
 set_target_properties(librt PROPERTIES VERSION 20.0.1 SOVERSION 20)
 if(HIDE_INTERNAL_SYMBOLS)
   set_property(TARGET librt APPEND PROPERTY COMPILE_DEFINITIONS 
"TIE_DLL_EXPORTS")
   set_property(TARGET librt APPEND PROPERTY COMPILE_DEFINITIONS 
"DB5_DLL_EXPORTS")
-  if(TARGET gdiam OR HIDE_INTERNAL_SYMBOLS_EXT)
-    set_property(TARGET librt APPEND PROPERTY COMPILE_DEFINITIONS 
"GDIAM_DLL_IMPORTS")
-  endif(TARGET gdiam OR HIDE_INTERNAL_SYMBOLS_EXT)
   if (TARGET librt-obj)
     set_property(TARGET librt-obj APPEND PROPERTY COMPILE_DEFINITIONS 
"TIE_DLL_EXPORTS")
     set_property(TARGET librt-obj APPEND PROPERTY COMPILE_DEFINITIONS 
"DB5_DLL_EXPORTS")
-    if(TARGET gdiam OR HIDE_INTERNAL_SYMBOLS_EXT)
-      set_property(TARGET librt-obj APPEND PROPERTY COMPILE_DEFINITIONS 
"GDIAM_DLL_IMPORTS")
-    endif(TARGET gdiam OR HIDE_INTERNAL_SYMBOLS_EXT)
   endif (TARGET librt-obj)
 endif(HIDE_INTERNAL_SYMBOLS)
 
@@ -403,6 +398,10 @@
   vds/README
   vds/COPYING
   vds/vds.h
+  gdiam/gdiam.hpp
+  gdiam/gdiam_test.cpp
+  gdiam/LICENSE.MIT
+  gdiam/README
   )
 
 # Local Variables:

Copied: brlcad/trunk/src/librt/gdiam/LICENSE.MIT (from rev 77314, 
brlcad/trunk/src/other/libgdiam/LICENSE.MIT)
===================================================================
--- brlcad/trunk/src/librt/gdiam/LICENSE.MIT                            (rev 0)
+++ brlcad/trunk/src/librt/gdiam/LICENSE.MIT    2020-10-01 21:41:50 UTC (rev 
77315)
@@ -0,0 +1,20 @@
+Copyright 2001 Sariel Har-Peled ([email protected])
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+

Copied: brlcad/trunk/src/librt/gdiam/README (from rev 77314, 
brlcad/trunk/src/other/libgdiam/README)
===================================================================
--- brlcad/trunk/src/librt/gdiam/README                         (rev 0)
+++ brlcad/trunk/src/librt/gdiam/README 2020-10-01 21:41:50 UTC (rev 77315)
@@ -0,0 +1,61 @@
+Source code implementing the algorithms described in:
+
+A Practical Approach for Computing the Diameter of a Point-Set
+Sariel Har-Peled
+
+Copyright 2001 Sariel Har-Peled ([email protected])
+http://valis.cs.uiuc.edu/~sariel/research/papers/00/diameter/diam_prog.html
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+ * the GNU General Public License as published by the Free Software
+   Foundation; either version 2, or (at your option) any later version.
+
+or
+
+ * the GNU Lesser General Public License as published by the Free
+   Software Foundation; either version 2.1, or (at your option)
+   any later version.
+
+or
+
+ * MIT License https://opensource.org/licenses/MIT
+ 
+If you need the source code under a different open-source license, let
+me know. 
+
+Program is provdied without any guarantee. Use at your own risk.
+
+*--------------------------------------------------------------
+ * History
+ *
+ *  3/6/18 
+ *        - Tobias Stohr reported & fixed a bug wis missing
+ *          constructor for 
+ *
+ * 8/18/16 -
+ *
+ *     Apply various code tweaks from BRL-CAD (C. Yapp)
+ *
+ * 12/22/14 -
+ *
+ *     Apply GSoC patch switching the convex hull algorithm to
+ *     monotone chain (P. Amidon)
+ *
+ * 8/7/13 -
+ *
+ *     Add DLL import/export logic for Windows (C. Yapp)
+ *
+ * 8/4/13 -
+ *     Add get_vertex method for low-level data translation. (C. Yapp)
+ *
+ * 8/3/13 -
+ *     Update licensing - can now use either GPLv2 or LGPLv2.1.
+ *     Added CMake build.
+ *
+ * 3/28/01 -
+ *     Original code updated to be more robust. It should now
+ *     handle really abnoxious inputs well (i.e., points with equal
+ *     coordinates, etc.
+

Copied: brlcad/trunk/src/librt/gdiam/gdiam.cpp (from rev 77314, 
brlcad/trunk/src/other/libgdiam/gdiam.cpp)
===================================================================
--- brlcad/trunk/src/librt/gdiam/gdiam.cpp                              (rev 0)
+++ brlcad/trunk/src/librt/gdiam/gdiam.cpp      2020-10-01 21:41:50 UTC (rev 
77315)
@@ -0,0 +1,2402 @@
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
+ * gdiam.cpp -
+ *   Computes diameter, and a tight-fitting bounding box of a
+ *   point-set in 3d.
+ *
+ * Copyright 2001 Sariel Har-Peled ([email protected])
+ * https://sarielhp.org/research/papers/00/diameter/diam_prog.html
+ *
+ * Note:  gdiam is available under multiple licenses - we make
+ * use of it under the MIT license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a 
copy of
+ * this software and associated documentation files (the "Software"), to deal 
in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
copies
+ * of the Software, and to permit persons to whom the Software is furnished to 
do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in 
all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
THE
+ * SOFTWARE.
+ *
+ * Code is based on the paper:
+ *   A Practical Approach for Computing the Diameter of a
+ *   Point-Set (in ACM Sym. on Computation Geometry SoCG 2001)
+ *   Sariel Har-Peled (http://www.uiuc.edu/~sariel)
+ *--------------------------------------------------------------
+ * History
+ *  3/6/18
+ *        - Tobias Stohr reported & fixed a bug was missing
+ *          constructor for
+ * 8/19/16 - Clifford Yapp updated the source
+ * 3/28/01 -
+ *     This is a more robust version of the code. It should
+ *     handlereally abnoxious inputs well (i.e., points with equal
+ *     coordinates, etc.
+\*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+
+#include "common.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <memory.h>
+#include <math.h>
+
+#include  <iostream>
+#include  <vector>
+#include  <algorithm>
+
+#include  "gdiam.hpp"
+
+/* for g++ to quell warnings */
+#if defined(__GNUC__) && !defined(__clang__)
+#  pragma GCC diagnostic push /* start new diagnostic pragma */
+#  pragma GCC diagnostic ignored "-Wfloat-equal"
+#elif defined(__clang__)
+#  pragma clang diagnostic push /* start new diagnostic pragma */
+#  pragma clang diagnostic ignored "-Wfloat-equal"
+#endif
+
+/*--- Constants ---*/
+
+#define  HEAP_LIMIT  10000
+#define  HEAP_DELTA  10000
+#define  PI 3.14159265958979323846
+
+/*--- Start of Code ---*/
+
+typedef long double  ldouble;
+
+class GFSPPair;
+
+class   GFSPTreeNode {
+private:
+    GBBox    bbox;
+    gdiam_point   * p_pnt_left, * p_pnt_right;
+    gdiam_real  bbox_diam, bbox_diam_proj;
+    GFSPTreeNode  * left, * right;
+    gdiam_point_t  center;
+
+public:
+    void  dump() const {
+        printf( "dump...\n" );
+    }
+    int  size() const {
+        return  (int)( p_pnt_right - p_pnt_left );
+    }
+    gdiam_point  getCenter() const {
+        return   (gdiam_point)center;
+    }
+    int  nodes_number() const {
+        int  sum;
+
+        if  ( ( left == NULL )  &&  ( right == NULL ) )
+            return  1;
+        sum = 1;
+
+        if  ( left != NULL )
+            sum += left->nodes_number();
+        if  ( right != NULL )
+            sum += right->nodes_number();
+
+        return  sum;
+    }
+
+    GFSPTreeNode( gdiam_point   * _p_pnt_left,
+                  gdiam_point   * _p_pnt_right ) {
+        bbox.init();
+        left = right = NULL;
+        p_pnt_left = _p_pnt_left;
+        p_pnt_right = _p_pnt_right;
+        bbox_diam = bbox_diam_proj = -1;
+    }
+
+    gdiam_real  maxDiam() const {
+        return  bbox_diam;
+    }
+    gdiam_real  maxDiamProj() const {
+        return  bbox_diam_proj;
+    }
+
+    GFSPTreeNode  * get_left() {
+        return  left;
+    }
+    GFSPTreeNode  * get_right() {
+        return   right;
+    }
+
+    bool  isSplitable() const {
+        return  (size() > 1);
+    }
+
+    const gdiam_point   * ptr_pnt_left() {
+        return  p_pnt_left;
+    }
+    const gdiam_point   * ptr_pnt_rand() {
+        return  p_pnt_left + ( rand() % ( p_pnt_right - p_pnt_left + 1 ) );
+    }
+    const gdiam_point   * ptr_pnt_right() {
+        return  p_pnt_right;
+    }
+
+
+    friend class  GFSPTree;
+
+    const GBBox  & getBBox() const {
+        return  bbox;
+    }
+};
+
+
+class  GFSPTree {
+private:
+    gdiam_point  * arr;
+    GFSPTreeNode  * root;
+
+public:
+    void  init( const gdiam_point  * _arr,
+                int  size ) {
+        arr = (gdiam_point *)malloc( sizeof( gdiam_point ) * size );
+        assert( arr != NULL );
+
+        for  ( int  ind = 0; ind < size; ind++ ) {
+            arr[ ind ] = _arr[ ind ];
+        }
+
+        root = build_node( arr, arr + size - 1 );
+    }
+
+    static void  terminate( GFSPTreeNode  * node ) {
+        if  ( node == NULL )
+            return;
+        terminate( node->left );
+        terminate( node->right );
+
+        node->left = node->right = NULL;
+
+        delete node;
+    }
+    void  term() {
+        free( arr );
+        arr = NULL;
+
+        GFSPTree::terminate( root );
+        root = NULL;
+    }
+
+    const gdiam_point   * getPoints() const {
+        return  arr;
+    }
+
+    int  nodes_number() const {
+        return  root->nodes_number();
+    }
+
+    gdiam_real   brute_diameter( int  a_lo, int  a_hi,
+                                 int  b_lo, int  b_hi,
+                                 GPointPair  & diam ) const {
+        for  ( int  ind = a_lo; ind <= a_hi; ind++ )
+            for  ( int  jnd = b_lo; jnd <= b_hi; jnd++ )
+                diam.update_diam( arr[ ind ], arr[ jnd ] );
+
+        return  diam.distance;
+    }
+    gdiam_real   brute_diameter( int  a_lo, int  a_hi,
+                                 int  b_lo, int  b_hi,
+                                 GPointPair  & diam,
+                                 const gdiam_point  dir ) const {
+        for  ( int  ind = a_lo; ind <= a_hi; ind++ )
+            for  ( int  jnd = b_lo; jnd <= b_hi; jnd++ )
+                diam.update_diam( arr[ ind ], arr[ jnd ], dir );
+
+        return  diam.distance;
+    }
+    gdiam_real   brute_diameter( const gdiam_point  * a_lo,
+                           const gdiam_point  * a_hi,
+                           const gdiam_point  * b_lo,
+                           const gdiam_point  * b_hi,
+                           GPointPair  & diam ) const {
+        for  ( const gdiam_point  * ind = a_lo; ind <= a_hi; ind++ )
+            for  ( const gdiam_point   * jnd = b_lo; jnd <= b_hi; jnd++ )
+                diam.update_diam( *ind, *jnd );
+
+        return  diam.distance;
+    }
+    gdiam_real   brute_diameter( const gdiam_point  * a_lo,
+                                 const gdiam_point  * a_hi,
+                                 const gdiam_point  * b_lo,
+                                 const gdiam_point  * b_hi,
+                                 GPointPair  & diam,
+                                 const gdiam_point  dir ) const {
+        for  ( const gdiam_point  * ind = a_lo; ind <= a_hi; ind++ )
+            for  ( const gdiam_point   * jnd = b_lo; jnd <= b_hi; jnd++ )
+                diam.update_diam( *ind, *jnd, dir );
+
+        return  diam.distance;
+    }
+
+    gdiam_point  getPoint( int  ind ) const {
+        return  arr[ ind ];
+    }
+
+    GFSPTreeNode  * getRoot() {
+        return  root;
+    }
+
+    GFSPTreeNode  * build_node( gdiam_point  * left,
+                                gdiam_point  * right ) {
+        if  ( left > right ) {
+            printf( "what!?\n" );
+            fflush( stdout );
+            assert( left <= right );
+        }
+        while  ( ( right > left )
+                 &&  ( pnt_isEqual( *right, *left ) ) )
+            right--;
+        GFSPTreeNode  * node = new  GFSPTreeNode( left, right );
+
+        node->bbox.init();
+        for  ( const gdiam_point  * ind = left; ind <= right; ind++ )
+            node->bbox.bound( *ind );
+        node->bbox_diam = node->bbox.get_diam();
+
+        node->bbox.center( node->center );
+
+        return  node;
+    }
+
+    // return how many elements on left side.
+    int    split_array( gdiam_point   * left,
+                        gdiam_point   * right,
+                        int  dim, const gdiam_real  & val ) {
+        const gdiam_point   * start_left = left;
+
+        while  ( left < right ) {
+            if  ( (*left)[ dim ] < val )
+                left++;
+            else
+                if  ( (*right)[ dim ] >= val )
+                    right--;
+                else {
+                    gdiam_exchange( *right, *left );
+                }
+        }
+
+        return  left - start_left;
+    }
+
+
+    void   split_node( GFSPTreeNode  * node )
+    {
+        int  dim, left_size;
+        gdiam_real  split_val;
+
+        if  ( node->left != NULL )
+            return;
+
+        GBBox  & bb( node->bbox );
+
+        dim = bb.getLongestDim();
+        split_val = ( bb.min_coord( dim ) + bb.max_coord( dim ) ) / 2.0;
+
+        left_size = split_array( node->p_pnt_left, node->p_pnt_right,
+                              dim, split_val );
+        if  ( left_size <= 0.0 ) {
+            printf( "bb: %g   %g\n",
+                    bb.min_coord( dim ), bb.max_coord( dim ) );
+            assert( left_size > 0 );
+        }
+        if  ( left_size >= (node->p_pnt_right - node->p_pnt_left + 1 ) ) {
+            printf( "left size too large?\n" );
+            fflush( stdout );
+            assert( left_size < (node->p_pnt_right - node->p_pnt_left + 1 ) );
+        }
+
+        node->left = build_node( node->p_pnt_left,
+                                 node->p_pnt_left + left_size - 1 );
+        node->right = build_node( node->p_pnt_left + left_size,
+                                  node->p_pnt_right );
+    }
+
+    void  findExtremeInProjection( GFSPPair  & pair,
+                                   GPointPair  & max_pair_diam );
+};
+
+void  bbox_vertex( const GBBox  & bb, gdiam_point_t  & ver,
+                   int  vert ) {
+    ver[ 0 ] = ((vert & 0x1) != 0)?
+        bb.min_coord( 0 ) : bb.max_coord( 0 );
+    ver[ 1 ] = ((vert & 0x2) != 0)?
+        bb.min_coord( 1 ) : bb.max_coord( 1 );
+    ver[ 2 ] = ((vert & 0x4) != 0)?
+        bb.min_coord( 2 ) : bb.max_coord( 2 );
+}
+
+
+gdiam_real  bbox_proj_dist( const GBBox  & bb1,
+                            const GBBox  & bb2,
+                            gdiam_point_cnt  proj )
+{
+    gdiam_point_t  a, b;
+    gdiam_real  rl;
+
+    rl = 0;
+    for  ( int  ind = 0; ind < 8; ind++ ) {
+        bbox_vertex( bb1, a, ind );
+
+        for  ( int  jnd = 0; jnd < 8; jnd++ ) {
+            bbox_vertex( bb2, b, jnd );
+            rl = max( rl, pnt_distance( a, b, proj ) );
+        }
+    }
+
+    return  rl;
+}
+
+
+
+class  GFSPPair
+{
+private:
+    GFSPTreeNode  * left, * right;
+    double  max_diam;
+
+public:
+    void  init( GFSPTreeNode  * _left, GFSPTreeNode  * _right )
+    {
+        left = _left;
+        right = _right;
+
+        GBBox  bb;
+
+        bb.init( left->getBBox(), right->getBBox() );
+        max_diam = bb.get_diam();
+    }
+
+    void  init( GFSPTreeNode  * _left, GFSPTreeNode  * _right,
+                gdiam_point  proj_dir, gdiam_real UNUSED(dist) )
+    {
+        left = _left;
+        right = _right;
+
+        GBBox  bb;
+
+        bb.init( left->getBBox(), right->getBBox() );
+        max_diam = max( max( bbox_proj_dist( _left->getBBox(),
+                                        _right->getBBox(),
+                                        proj_dir ),
+                             bbox_proj_dist( _left->getBBox(),
+                                             _left->getBBox(),
+                                             proj_dir ) ),
+                        bbox_proj_dist( _right->getBBox(),
+                                        _right->getBBox(),
+                                        proj_dir ) );
+
+    }
+
+    // error 2r/l - approximate cos of the max possible angle in the pair
+    double  getProjectionError() const
+    {
+        double  l, two_r;
+
+        l = pnt_distance( left->getCenter(), right->getCenter() );
+        two_r = max( left->maxDiam(), right->maxDiam() );
+
+        if  ( l == 0.0 )
+            return  10;
+
+        return  two_r / l;
+    }
+
+    GFSPTreeNode  * get_left() {
+        return  left;
+        }
+    GFSPTreeNode  * get_right() {
+        return   right;
+    }
+
+    void  dump() const {
+        printf( "[\n" );
+        left->dump();
+        right->dump();
+        printf( "\tmax_diam; %g\n", max_diam );
+    }
+
+    bool  isBelowThreshold( int  threshold ) const {
+        if  ( left->size() > threshold )
+            return  false;
+        if  ( right->size() > threshold )
+            return  false;
+
+        return  true;
+    }
+
+    double   directDiameter( const GFSPTree  & tree,
+                             GPointPair  & diam ) const {
+        return  tree.brute_diameter( left->ptr_pnt_left(),
+                                     left->ptr_pnt_right(),
+                                     right->ptr_pnt_left(),
+                                     right->ptr_pnt_right(),
+                                     diam );
+    }
+
+    double   directDiameter( const GFSPTree  & tree,
+                             GPointPair  & diam,
+                             const gdiam_point  dir ) const {
+        return  tree.brute_diameter( left->ptr_pnt_left(),
+                                     left->ptr_pnt_right(),
+                                     right->ptr_pnt_left(),
+                                     right->ptr_pnt_right(),
+                                     diam, dir );
+    }
+
+    double  maxDiam()  const {
+        return  max_diam;
+    }
+    double  minAprxDiam()  const {
+        double   sub_diam;
+
+        sub_diam = left->maxDiam() + right->maxDiam();
+        if  ( sub_diam > (max_diam / 10.0) )
+            return  max_diam;
+
+        return  max_diam - sub_diam / 2.0;
+    }
+};
+
+
+class g_heap_pairs_p;
+
+#define  UDM_SIMPLE      1
+#define  UDM_BIG_SAMPLE  2
+
+class  GTreeDiamAlg
+{
+private:
+    GFSPTree  tree;
+    //double  diam;
+    GPointPair   pair_diam;
+    int  points_num;
+    int  threshold_brute;
+    int  update_diam_mode;
+public:
+    GTreeDiamAlg( gdiam_point  * arr, int  size, int  mode ) {
+        tree.init( arr, size );
+        //diam = 0;
+        pair_diam.init( arr[ 0 ] );
+        points_num = size;
+        threshold_brute = 40;
+        update_diam_mode = mode;
+    }
+
+    void  term() {
+        tree.term();
+    }
+
+    int  size() const {
+        return  points_num;
+    }
+    const GPointPair  & getDiameter() const {
+        return  pair_diam;
+    }
+
+    int  nodes_number() const {
+        return  tree.nodes_number();
+    }
+
+    void  addPairHeap( g_heap_pairs_p  & heap,
+                       GFSPTreeNode  * left,
+                       GFSPTreeNode  * right );
+    void  addPairHeap( g_heap_pairs_p  & heap,
+                       GFSPTreeNode  * left,
+                       GFSPTreeNode  * right,
+                       gdiam_point  proj,
+                       GFSPPair  & father );
+    void  split_pair( GFSPPair  & pair,
+                      g_heap_pairs_p  & heap, double  eps );
+    void  split_pair_proj( GFSPPair  & pair,
+                           g_heap_pairs_p  & heap, double  eps,
+                           gdiam_point  proj );
+    void  compute_by_heap( double  eps );
+    void  compute_by_heap_proj( double  eps, gdiam_point  proj );
+
+    double  diameter() {
+        return  pair_diam.distance;
+    }
+};
+
+
+/*--- Heap implementation ---*/
+
+typedef  int   ( *ptrCompareFunc )( void  * aPtr, void  * bPtr );
+typedef  void  * voidPtr_t;
+
+struct  heap_t
+{
+    voidPtr_t  * pArr;
+    int  curr_size, max_size;
+    ptrCompareFunc  pCompFunc;
+};
+
+void  heap_init( heap_t  * pHeap, ptrCompareFunc  _pCompFunc )
+{
+    assert( pHeap != NULL );
+    assert( _pCompFunc != NULL );
+
+    memset( pHeap, 0, sizeof( heap_t ) );
+
+    pHeap->pCompFunc = _pCompFunc;
+    pHeap->max_size = 100;
+    pHeap->pArr = (voidPtr_t *)malloc( sizeof( void * )
+                                       * pHeap->max_size );
+    assert( pHeap->pArr != NULL );
+    pHeap->curr_size = 0;
+}
+
+
+static void  resize( heap_t  * pHeap, int  size )
+{
+    int  max_sz;
+    voidPtr_t  * pTmp;
+
+    if   ( size <= pHeap->max_size )
+        return;
+
+    max_sz = size * 2;
+    pTmp = (voidPtr_t *)malloc( max_sz * sizeof( void * ) );
+    assert( pTmp != NULL );
+    memset( pTmp, 0, max_sz * sizeof( void * ) );
+    memcpy( pTmp, pHeap->pArr, pHeap->curr_size * sizeof( void * ) );
+    free( pHeap->pArr );
+    pHeap->pArr = pTmp;
+}
+
+
+void  heap_term( heap_t  * pHeap )
+{
+    assert( pHeap != NULL );
+
+    if  ( pHeap->pArr != NULL )
+        free( pHeap->pArr );
+    memset( pHeap, 0, sizeof( heap_t ) );
+}
+
+
+void  heap_insert( heap_t  * pHeap, void  * pData )
+{
+    int  ind, father;
+    voidPtr_t  pTmp;
+
+    resize( pHeap, pHeap->curr_size + 1 );
+
+    ind = pHeap->curr_size;
+    pHeap->curr_size++;
+
+    pHeap->pArr[ ind ] = pData;
+
+    while  ( ind > 0 ) {
+        father = ( ind - 1 ) / 2;
+
+        if  ( (*pHeap->pCompFunc)( pHeap->pArr[ ind ],
+                                   pHeap->pArr[ father ] ) <= 0 )
+            break;
+
+        pTmp = pHeap->pArr[ ind ];
+        pHeap->pArr[ ind ] = pHeap->pArr[ father ];
+        pHeap->pArr[ father ] = pTmp;
+
+        ind = father;
+    }
+}
+
+
+void  * heap_top( heap_t  * pHeap )
+{
+    return  pHeap->pArr[ 0 ];
+}
+
+
+void  * heap_delete_max( heap_t  * pHeap )
+{
+    void  * res;
+    void  * pTmp;
+    int  ind, left, right, max_ind;
+
+    if  ( pHeap->curr_size <= 0 )
+        return  NULL;
+
+    res = pHeap->pArr[ 0 ];
+
+    pHeap->curr_size--;
+    pHeap->pArr[ 0 ] = pHeap->pArr[ pHeap->curr_size ];
+    pHeap->pArr[ pHeap->curr_size ] = NULL;
+    ind = 0;
+
+    while  ( ind < pHeap->curr_size ) {
+        left = 2 * ind + 1;
+        right = 2 * ind + 2;
+        if  ( left >= pHeap->curr_size )
+            break;
+        if  ( right >= pHeap->curr_size )
+            right = left;
+
+        if  ( (*pHeap->pCompFunc)( pHeap->pArr[ left ],
+                                   pHeap->pArr[ right ] ) <= 0 )
+            max_ind = right;
+        else
+            max_ind = left;
+        if  ( (*pHeap->pCompFunc)( pHeap->pArr[ ind  ],
+                                   pHeap->pArr[ max_ind ] ) >= 0 )
+            break;
+
+        pTmp = pHeap->pArr[ ind ];
+        pHeap->pArr[ ind ] = pHeap->pArr[ max_ind ];
+        pHeap->pArr[ max_ind ] = pTmp;
+
+        ind = max_ind;
+    }
+
+    return  res;
+}
+
+
+bool  heap_is_empty( heap_t  * pHeap )
+{
+    assert( pHeap != NULL );
+
+    return( pHeap->curr_size <= 0 );
+}
+
+
+int   compare_pairs( void  * _a, void  * _b )
+{
+    const GFSPPair  & a( *(GFSPPair *)_a );
+    const GFSPPair  & b( *(GFSPPair *)_b );
+
+    if  ( a.maxDiam() < b.maxDiam() )
+        return  -1;
+    if  ( a.maxDiam() > b.maxDiam() )
+        return  1;
+
+    return  0;
+}
+
+
+
+class  g_heap_pairs_p
+{
+private:
+    heap_t  heap;
+
+public:
+    g_heap_pairs_p() {
+        heap_init( &heap, compare_pairs );
+    }
+
+    ~g_heap_pairs_p() {
+        while  ( size() > 0 ) {
+            pop();
+        }
+        heap_term( &heap );
+    }
+
+    void  push( GFSPPair  & pair )
+    {
+        GFSPPair  * p_pair = new GFSPPair( pair );
+        heap_insert( &heap, (void *)p_pair );
+    }
+
+    int  size() const {
+        return  heap.curr_size;
+    }
+    GFSPPair  top() {
+        return  *(GFSPPair *)heap_top( &heap );
+    }
+    void  pop() {
+        GFSPPair  * ptr = (GFSPPair *)heap_delete_max( &heap );
+
+        delete  ptr;
+    }
+};
+
+
+/* heap.implementation end */
+
+
+void  computeExtremePair( const gdiam_point  * arr, int  size,
+                          int  dim, GPointPair  & pp )
+{
+    pp.init( arr[ 0 ] );
+
+    for  ( int  ind = 1; ind < size; ind++ ) {
+        const gdiam_point  pnt( arr[ ind ] );
+
+        if  ( pnt[ dim ] < pp.p[ dim ] )
+            pp.p = pnt;
+        if  ( pnt[ dim ] > pp.q[ dim ] )
+            pp.q = pnt;
+    }
+
+    pp.distance = pnt_distance( pp.p, pp.q );
+}
+
+
+
+void  GTreeDiamAlg::compute_by_heap( double  eps )
+{
+    g_heap_pairs_p  heap;
+    int  heap_limit, heap_delta;
+
+    heap_limit = HEAP_LIMIT;
+    heap_delta = HEAP_DELTA;
+
+    GFSPTreeNode  * root = tree.getRoot();
+
+    computeExtremePair( tree.getPoints(), points_num,
+                        root->getBBox().getLongestDim(),
+                        pair_diam );
+
+    GFSPPair  root_pair;
+
+    root_pair.init( root, root );
+
+    heap.push( root_pair );
+
+    int  count =0;
+    while  ( heap.size() > 0 ) {
+        GFSPPair  pair = heap.top();
+        heap.pop();
+        split_pair( pair, heap, eps );
+        if  ( ( count & 0x3ff ) == 0 ) {
+            if  ( ((int)heap.size()) > heap_limit ) {
+                threshold_brute *= 2;
+                printf( "threshold_brute: %d\n", threshold_brute );
+                heap_limit += heap_delta;
+            }
+        }
+        count++;
+    }
+}
+
+
+void  GTreeDiamAlg::compute_by_heap_proj( double  eps,
+                                          gdiam_point  proj )
+{
+    g_heap_pairs_p  heap;
+    int  heap_limit, heap_delta;
+    GPointPair   pair_diam_x;
+
+    heap_limit = HEAP_LIMIT;
+    heap_delta = HEAP_DELTA;
+
+    GFSPTreeNode  * root = tree.getRoot();
+
+    computeExtremePair( tree.getPoints(), points_num,
+                        root->getBBox().getLongestDim(),
+                        pair_diam_x );
+    pair_diam.init( pair_diam_x.p, pair_diam_x.q, proj );
+
+    GFSPPair  root_pair;
+
+    root_pair.init( root, root, proj, 0 );
+
+    heap.push( root_pair );
+
+    int  count =0;
+    while  ( heap.size() > 0 ) {
+        GFSPPair  pair = heap.top();
+        heap.pop();
+        split_pair_proj( pair, heap, eps, proj );
+        if  ( ( count & 0x3ff ) == 0 ) {
+            if  ( ((int)heap.size()) > heap_limit ) {
+                threshold_brute *= 2;
+                printf( "threshold_brute: %d\n", threshold_brute );
+                heap_limit += heap_delta;
+            }
+        }
+        count++;
+    }
+}
+
+
+void  GTreeDiamAlg::addPairHeap( g_heap_pairs_p  & heap,
+                                 GFSPTreeNode  * left,
+                                 GFSPTreeNode  * right )
+{
+    if  ( update_diam_mode == UDM_SIMPLE ) {
+        const gdiam_point  p( *(left->ptr_pnt_left()) );
+        const gdiam_point  q( *(right->ptr_pnt_left()) );
+
+        pair_diam.update_diam( p, q );
+    } else
+        if  ( update_diam_mode == UDM_BIG_SAMPLE ) {
+            if  ( ( left->size() < 100 )  ||  ( right->size() < 100 ) ) {
+                const gdiam_point  p( *(left->ptr_pnt_left()) );
+                const gdiam_point  q( *(right->ptr_pnt_left()) );
+
+                pair_diam.update_diam( p, q );
+                } else
+            {
+#define  UMD_SIZE        5
+                gdiam_point  arr_left[ UMD_SIZE ],
+                    arr_right[ UMD_SIZE ];
+                for  ( int  ind = 0; ind < UMD_SIZE; ind++ ) {
+                    const gdiam_point  p( *(left->ptr_pnt_rand()) );
+                    const gdiam_point  q( *(right->ptr_pnt_rand()) );
+                    arr_left[ ind ] = p;
+                    arr_right[ ind ] = q;
+                }
+                for  ( int  ind = 0; ind < UMD_SIZE; ind++ )
+                    for  ( int  jnd = 0; jnd < UMD_SIZE; jnd++ )
+                        pair_diam.update_diam( arr_left[ ind ],
+                                               arr_right[ jnd ] );
+            }
+        } else {
+            assert( false );
+        }
+
+    GFSPPair  pair;
+
+    pair.init( left, right );
+    if  ( pair.maxDiam() <= pair_diam.distance )
+        return;
+    heap.push( pair );
+}
+
+
+void  GTreeDiamAlg::addPairHeap( g_heap_pairs_p  & heap,
+                                 GFSPTreeNode  * left,
+                                 GFSPTreeNode  * right,
+                                 gdiam_point  proj,
+                                 GFSPPair  &UNUSED(father) )
+{
+    const gdiam_point  p( *(left->ptr_pnt_left()) );
+    const gdiam_point  q( *(right->ptr_pnt_left()) );
+
+    pair_diam.update_diam( p, q, proj );
+
+    GFSPPair  pair;
+
+    pair.init( left, right, proj,
+               pnt_distance( p, q, proj ) );
+    if  ( pair.maxDiam() <= pair_diam.distance )
+        return;
+    heap.push( pair );
+}
+
+
+void  GTreeDiamAlg::split_pair_proj( GFSPPair  & pair,
+                                     g_heap_pairs_p  & heap, double  eps,
+                                     gdiam_point  proj )
+{
+    bool  f_is_left_splitable, f_is_right_splitable;
+
+    if  ( pair.maxDiam() <= ((1.0 + eps) * pair_diam.distance ))
+        return;
+
+    if  ( pair.isBelowThreshold( threshold_brute ) ) {
+        pair.directDiameter( tree, pair_diam, proj );
+        return;
+    }
+
+    f_is_left_splitable = pair.get_left()->isSplitable();
+    f_is_right_splitable = pair.get_right()->isSplitable();
+    assert( f_is_left_splitable  ||  f_is_right_splitable );
+    if ( f_is_left_splitable )
+        tree.split_node( pair.get_left() );
+    if ( f_is_right_splitable )
+        tree.split_node( pair.get_right() );
+
+    if  ( f_is_left_splitable
+          &&  f_is_right_splitable ) {
+        addPairHeap( heap,
+                     pair.get_left()->get_left(),
+                     pair.get_right()->get_left(),
+                     proj, pair );
+        addPairHeap( heap,
+                     pair.get_left()->get_left(),
+                     pair.get_right()->get_right(),
+                     proj, pair );
+        // to avoid exponential blowup
+        if  ( pair.get_left() != pair.get_right() )
+            addPairHeap( heap,
+                         pair.get_left()->get_right(),
+                         pair.get_right()->get_left(),
+                         proj, pair );
+        addPairHeap( heap,
+                     pair.get_left()->get_right(),
+                     pair.get_right()->get_right(),
+                     proj, pair );
+        return;
+    }
+    if  ( f_is_left_splitable ) {
+        addPairHeap( heap,
+                     pair.get_left()->get_left(),
+                     pair.get_right(), proj, pair );
+        addPairHeap( heap,
+                     pair.get_left()->get_right(),
+                     pair.get_right(), proj, pair );
+        return;
+    }
+    if  ( f_is_right_splitable ) {
+        addPairHeap( heap,
+                     pair.get_left(),
+                     pair.get_right()->get_left(), proj, pair );
+        addPairHeap( heap,
+                     pair.get_left(),
+                     pair.get_right()->get_right(), proj, pair );
+        return;
+    }
+}
+
+
+void  GTreeDiamAlg::split_pair( GFSPPair  & pair,
+                                g_heap_pairs_p  & heap,
+                                double  eps )
+{
+    bool  f_is_left_splitable, f_is_right_splitable;
+
+    if  ( pair.maxDiam() <= ((1.0 + eps) * pair_diam.distance ))
+        return;
+
+    if  ( pair.isBelowThreshold( threshold_brute ) ) {
+        pair.directDiameter( tree, pair_diam );
+        return;
+    }
+
+    f_is_left_splitable = pair.get_left()->isSplitable();
+    f_is_right_splitable = pair.get_right()->isSplitable();
+    assert( f_is_left_splitable  ||  f_is_right_splitable );
+    if ( f_is_left_splitable )
+        tree.split_node( pair.get_left() );
+    if ( f_is_right_splitable )
+        tree.split_node( pair.get_right() );
+
+    if  ( f_is_left_splitable
+          &&  f_is_right_splitable ) {
+        addPairHeap( heap,
+                     pair.get_left()->get_left(),
+                     pair.get_right()->get_left() );
+        addPairHeap( heap,
+                     pair.get_left()->get_left(),
+                     pair.get_right()->get_right() );
+        // to avoid exponential blowup
+        if  ( pair.get_left() != pair.get_right() )
+            addPairHeap( heap,
+                         pair.get_left()->get_right(),
+                         pair.get_right()->get_left() );
+        addPairHeap( heap,
+                     pair.get_left()->get_right(),
+                     pair.get_right()->get_right() );
+        return;
+    }
+    if  ( f_is_left_splitable ) {
+        addPairHeap( heap,
+                     pair.get_left()->get_left(),
+                     pair.get_right() );
+        addPairHeap( heap,
+                     pair.get_left()->get_right(),
+                     pair.get_right() );
+        return;
+    }
+    if  ( f_is_right_splitable ) {
+        addPairHeap( heap,
+                     pair.get_left(),
+                     pair.get_right()->get_left() );
+        addPairHeap( heap,
+                     pair.get_left(),
+                     pair.get_right()->get_right() );
+        return;
+    }
+}
+
+
+GPointPair   gdiam_approx_diam( gdiam_point  * start, int  size,
+                                gdiam_real  eps )
+{
+    GPointPair  pair;
+
+    GTreeDiamAlg  * pAlg = new  GTreeDiamAlg( start, size, UDM_SIMPLE );
+    pAlg->compute_by_heap( eps );
+
+    pair = pAlg->getDiameter();
+
+    delete  pAlg;
+
+    return  pair;
+}
+
+
+GPointPair   gdiam_approx_diam_UDM( gdiam_point  * start, int  size,
+                                    gdiam_real  eps )
+{
+    GPointPair  pair;
+
+    GTreeDiamAlg  * pAlg = new  GTreeDiamAlg( start, size, UDM_BIG_SAMPLE );
+    pAlg->compute_by_heap( eps );
+
+    pair = pAlg->getDiameter();
+
+    delete  pAlg;
+
+    return  pair;
+}
+
+
+gdiam_point  * gdiam_convert( gdiam_real  * start, int  size )
+{
+    gdiam_point  * p_arr;
+
+    assert( start != NULL );
+    assert( size > 0 );
+
+    p_arr = (gdiam_point *)malloc( sizeof( gdiam_point ) * size );
+    assert( p_arr != NULL );
+
+    for  ( int  ind = 0; ind < size; ind++ )
+        p_arr[ ind ] = (gdiam_point)&(start[ ind * 3 ]);
+
+    return  p_arr;
+}
+
+
+GPointPair   gdiam_approx_diam_pair( gdiam_real  * start, int  size,
+                                     gdiam_real  eps )
+{
+    gdiam_point  * p_arr;
+    GPointPair  pair;
+
+    p_arr = gdiam_convert( start, size );
+    pair = gdiam_approx_diam( p_arr, size, eps );
+    free( p_arr );
+
+    return  pair;
+}
+
+
+GPointPair   gdiam_approx_diam_pair_UDM( gdiam_real  * start, int  size,
+                                         gdiam_real  eps )
+{
+    gdiam_point  * p_arr;
+    GPointPair  pair;
+
+    p_arr = gdiam_convert( start, size );
+    pair = gdiam_approx_diam_UDM( p_arr, size, eps );
+    free( p_arr );
+
+    return  pair;
+}
+
+
+gdiam_bbox   gdiam_approx_const_mvbb( gdiam_point  * start, int  size,
+                                      gdiam_real  eps,
+                                      GBBox  * p_ap_bbox )
+{
+    GPointPair  pair, pair_2;
+
+    GTreeDiamAlg  * pAlg = new  GTreeDiamAlg( start, size, UDM_SIMPLE );
+    pAlg->compute_by_heap( eps );
+
+    pair = pAlg->getDiameter();
+
+    /* Compute the resulting diameter */
+    gdiam_point_t  dir, dir_2, dir_3;
+
+    dir[ 0 ] = pair.p[ 0 ] - pair.q[ 0 ];
+    dir[ 1 ] = pair.p[ 1 ] - pair.q[ 1 ];
+    dir[ 2 ] = pair.p[ 2 ] - pair.q[ 2 ];
+    pnt_normalize( dir );
+
+    pAlg->compute_by_heap_proj( eps, dir );
+
+    pair_2 = pAlg->getDiameter();
+    dir_2[ 0 ] = pair_2.p[ 0 ] - pair_2.q[ 0 ];
+    dir_2[ 1 ] = pair_2.p[ 1 ] - pair_2.q[ 1 ];
+    dir_2[ 2 ] = pair_2.p[ 2 ] - pair_2.q[ 2 ];
+
+    gdiam_real prd;
+
+    prd = pnt_dot_prod( dir, dir_2 );
+    dir_2[ 0 ] = dir_2[ 0 ] - prd * dir[ 0 ];
+    dir_2[ 1 ] = dir_2[ 1 ] - prd * dir[ 1 ];
+    dir_2[ 2 ] = dir_2[ 2 ] - prd * dir[ 2 ];
+
+    pnt_normalize( dir );
+    pnt_normalize( dir_2 );
+
+    pnt_cross_prod( dir, dir_2, dir_3 );
+    pnt_normalize( dir_3 );
+
+    gdiam_bbox  bbox;
+    GBBox  ap_bbox;
+
+    if  ( ( pnt_length( dir_2 ) < 1e-6 )
+          &&  ( pnt_length( dir_3 ) < 1e-6 ) )
+        gdiam_generate_orthonormal_base( dir, dir_2, dir_3 );
+
+    if  ( ( pnt_length( dir ) == 0.0 )
+          ||  ( pnt_length( dir_2 ) < 1e-6 )
+          ||  ( pnt_length( dir_3 ) < 1e-6 ) ) {
+        gdiam_generate_orthonormal_base( dir, dir_2, dir_3 );
+        pnt_dump( dir );
+        pnt_dump( dir_2 );
+        pnt_dump( dir_3 );
+
+        fflush( stdout );
+        fflush( stderr );
+        assert( false );
+    }
+
+    bbox.init( dir, dir_2, dir_3 );
+    ap_bbox.init();
+    for  ( int  ind = 0; ind < size; ind++ ) {
+        bbox.bound( start[ ind ] );
+        ap_bbox.bound( start[ ind ] );
+    }
+
+    delete  pAlg;
+    if  ( ap_bbox.volume() < bbox.volume() )
+        bbox.init( ap_bbox );
+
+    if  ( p_ap_bbox != NULL )
+        *p_ap_bbox = ap_bbox;
+
+    return  bbox;
+}
+
+
+gdiam_bbox   gdiam_approx_const_mvbb( gdiam_real  * start, int  size,
+                                      gdiam_real  eps )
+{
+    gdiam_point  * p_arr;
+    gdiam_bbox  gbbox;
+
+    p_arr = gdiam_convert( start, size );
+    gbbox = gdiam_approx_const_mvbb( p_arr, size, eps, NULL );
+    free( p_arr );
+
+    return   gbbox;
+}
+
+/*-----------------------------------------------------------------------
+ * Code for computing best bounding box in a given drection
+\*-----------------------------------------------------------------------*/
+
+void  gdiam_generate_orthonormal_base( gdiam_point  in,
+                                       gdiam_point  out1,
+                                       gdiam_point  out2 )
+{
+    assert( pnt_length( in ) > 0.0 );
+
+    pnt_normalize( in );
+
+    // stupid cases..
+    if  ( in[ 0 ] == 0.0 ) {
+        if  ( in[ 1 ] == 0.0 ) {
+            pnt_init_normalize( out1, 1, 0, 0 );
+            pnt_init_normalize( out2, 0, 1, 0 );
+            return;
+        }
+        if  ( in[ 2 ] == 0.0 ) {
+            pnt_init_normalize( out1, 1, 0, 0 );
+            pnt_init_normalize( out2, 0, 0, 1 );
+            return;
+        }
+        pnt_init_normalize( out1, 0, -in[ 2 ], in[ 1 ] );
+        pnt_init_normalize( out2, 1, 0, 0 );
+        return;
+    }
+    if  ( ( in[ 1 ] == 0.0 )  &&  ( in[ 2 ] == 0.0 ) )  {
+        pnt_init_normalize( out1, 0, 1, 0 );
+        pnt_init_normalize( out2, 0, 0, 1 );
+        return;
+    }
+    if  ( in[ 1 ] == 0.0 ) {
+        pnt_init_normalize( out1, -in[ 2 ], 0, in[ 0 ] );
+        pnt_init_normalize( out2, 0, 1, 0 );
+        return;
+    }
+    if  ( in[ 2 ] == 0.0 ) {
+        pnt_init_normalize( out1, -in[ 1 ], in[ 0 ], 0 );
+        pnt_init_normalize( out2, 0, 0, 1 );
+        return;
+    }
+
+    // all entries in the vector are not zero.
+    pnt_init_normalize( out1, -in[ 1 ], in[ 0 ], 0 );
+    pnt_cross_prod( in, out1, out2 );
+    pnt_normalize( out2 );
+}
+
+
+class  point2d
+{
+public:
+    gdiam_real  x, y;
+    gdiam_point  src;
+
+    void  init( gdiam_point  pnt,
+                gdiam_point  base_x,
+                gdiam_point  base_y ) {
+        src = pnt;
+        x = pnt_dot_prod( pnt, base_x );
+        y = pnt_dot_prod( pnt, base_y );
+    }
+
+    gdiam_real  dist( const point2d  & pnt ) {
+        return  sqrt( ( x - pnt.x ) * ( x - pnt.x )
+                      + ( y - pnt.y ) * ( y - pnt.y ) );
+    }
+
+    void  dump() const {
+        printf( "(%g, %g)\n", x, y );
+    }
+    bool  equal( const point2d  & pnt ) const {
+        return  ( ( x == pnt.x )  &&  ( y == pnt.y ) );
+    }
+    bool  equal_real( const point2d  & pnt ) const {
+        return  ( ( fabs( x - pnt.x ) < 1e-8 )
+                  && ( fabs( y - pnt.y ) < 1e-8 ) );
+    }
+};
+
+typedef  point2d  * point2d_ptr;
+class  vec_point_2d : public std::vector<point2d_ptr> {};
+
+
+
+inline ldouble     Area( const point2d  & a,
+                        const point2d  & b,
+                        const point2d  & c )
+{
+    double  x1, y1, x2, y2, len;
+
+    x1 = b.x - a.x;
+    y1 = b.y - a.y;
+
+    x2 = c.x - a.x;
+    y2 = c.y - a.y;
+
+    if  ( ( x1 != 0.0 )  ||  ( y1 != 0.0 ) ) {
+        len = sqrt( x1 * x1 + y1 * y1 );
+        x1 /= len;
+        y1 /= len;
+    }
+
+    if  ( ( x2 != 0.0 )  ||  ( y2 != 0.0 ) ) {
+        len = sqrt( x2 * x2 + y2 * y2 );
+        x2 /= len;
+        y2 /= len;
+    }
+
+    ldouble  area;
+
+    area = x1 * y2 - x2 * y1;
+    return  area;
+}
+
+
+inline int     AreaSign( const point2d  & a,
+                         const point2d  & b,
+                         const point2d  & c )
+{
+    ldouble  area;//, area1, area2;
+
+    area = a.x * b.y - a.y * b.x +
+        a.y * c.x - a.x * c.y +
+        b.x * c.y - c.x * b.y;
+
+    return  ( ( area < (ldouble)0.0 )? -1:
+              ( (area > (ldouble)0.0)? 1 : 0 ) );
+}
+
+inline  bool    Left(  const point2d  & a,
+                         const point2d  & b,
+                         const point2d  & c )
+{
+    return  AreaSign( a, b, c ) > 0;
+}
+
+inline  bool    Left_colinear(  const point2d  & a,
+                                const point2d  & b,
+                                const point2d  & c )
+{
+    return  AreaSign( a, b, c ) >= 0;
+}
+
+
+struct CompareByAngle {
+public:
+    point2d  base;
+
+    bool operator()(const point2d_ptr  & a, const point2d_ptr   & b ) {
+       int  sgn;
+       gdiam_real  len1, len2;
+
+        if  ( a->equal( *b ) )
+            return  false;
+        assert( a != NULL );
+        assert( b != NULL );
+        if  ( a->equal( base ) ) {
+            assert( false );
+            return  true;
+        }
+        if  ( b->equal( base ) ) {
+            assert( false );
+            return  false;
+        }
+
+       sgn = AreaSign( base, *a, *b );
+        if  ( sgn != 0 )
+            return  (sgn > 0);
+        len1 = base.dist( *a );
+        len2 = base.dist( *b );
+
+        return (len1 > len2);
+    }
+};
+
+
+point2d_ptr  get_min_point( vec_point_2d  & in,
+                            int  & index )
+{
+    point2d_ptr  min_pnt = in[ 0 ];
+
+    index = 0;
+
+    for  ( int  ind = 0; ind < (int)in.size(); ind++ ) {
+        if  ( in[ ind ]->y < min_pnt->y ) {
+            min_pnt = in[ ind ];
+            index = ind;
+        } else
+            if  ( ( in[ ind ]->y == min_pnt->y )
+                  &&  ( in[ ind ]->x < min_pnt->x ) ) {
+                min_pnt = in[ ind ];
+                index = ind;
+            }
+    }
+
+    return  min_pnt;
+}
+
+
+void  dump( vec_point_2d   & vec )
+{
+    for  ( int  ind = 0; ind < (int)vec.size(); ind++ ) {
+        printf( "-- %11d (%-11g, %-11g)\n",
+                ind, vec[ ind ]->x,
+                vec[ ind ]->y );
+    }
+    printf( "\n\n" );
+}
+
+
+static void  print_pnt( point2d_ptr  pnt )
+{
+    printf( "(%g, %g)\n", pnt->x, pnt->y );
+}
+
+
+void   verify_convex_hull( vec_point_2d  & in, vec_point_2d  & ch )
+{
+    ldouble  area;
+
+    for  ( int  ind = 0; ind < (int)( ch.size() - 2 ); ind++ )
+        assert( Left( *( ch[ ind ] ), *( ch[ ind + 1 ] ),
+                      *( ch[ ind + 2 ] ) ) );
+    assert( Left( *( ch[ ch.size() - 2 ] ), *( ch[ ch.size() - 1 ] ),
+                  *( ch[ 0 ] ) ) );
+    assert( Left( *( ch[ ch.size() - 1 ] ), *( ch[ 0 ] ),
+                  *( ch[ 1 ] ) ) );
+
+    for  ( int  ind = 0; ind < (int)( in.size() - 2 ); ind++ ) {
+         for  ( int  jnd = 0; jnd < (int)( ch.size() - 1 ); jnd++ ) {
+             if  ( ch[ jnd ]->equal_real( *( in[ ind ] ) ) )
+                 continue;
+             if  ( ch[ jnd + 1 ]->equal( *( in[ ind ] ) ) )
+                 continue;
+
+             if  ( ! Left_colinear( *( ch[ jnd ] ), *( ch[ jnd + 1 ] ),
+                                    *( in[ ind ] ) ) ) {
+                 area = Area( *( ch[ jnd ] ), *( ch[ jnd + 1 ] ),
+                              *( in[ ind ] ) );
+                 if  ( fabs( area ) < 1e-12 )
+                     continue;
+                 printf( "Failure in progress!\n\n" );
+                 print_pnt( ch[ jnd ] );
+                 print_pnt( ch[ jnd + 1 ] );
+                 print_pnt( in[ ind ] );
+
+                 printf( "ch[ jnd ]: (%g, %g)\n",
+                         ch[ jnd ]->x, ch[ jnd ]->y );
+                 printf( "ch[ jnd + 1 ]: (%g, %g)\n",
+                         ch[ jnd + 1 ]->x, ch[ jnd + 1 ]->y );
+                 printf( "ch[ ind ]: (%g, %g)\n",
+                         in[ ind ]->x, in[ ind ]->y );
+                 printf( "Area: %g\n", (double)Area( *( ch[ jnd ] ),
+                                             *( ch[ jnd + 1 ] ),
+                                             *( in[ ind ] ) ) );
+                 printf( "jnd: %d, jnd + 1: %d, ind: %d\n",
+                         jnd, jnd+1, ind );
+                 fflush( stdout );
+                 fflush( stderr );
+
+                 assert( Left( *( ch[ jnd ] ), *( ch[ jnd + 1 ] ),
+                               *( in[ ind ] ) ) );
+             }
+         }
+         if  ( ch[ 0 ]->equal( *( in[ ind ] ) ) )
+             continue;
+         if  ( ch[ ch.size() - 1 ]->equal( *( in[ ind ] ) ) )
+             continue;
+         assert( Left( *( ch[ ch.size() - 1 ] ),
+                       *( ch[ 0 ] ),
+                       *( in[ ind ] ) ) );
+    }
+    printf( "Convex hull seems to be ok!\n" );
+}
+
+
+
+static  void   remove_duplicate( vec_point_2d  & in,
+                                 point2d_ptr  ptr,
+                                 int  start )
+{
+    int  dest;
+
+    dest = start;
+    while  ( start < (int)in.size() ) {
+        if  ( in[ start ]->equal_real( *ptr ) ) {
+            start++;
+            continue;
+        }
+        in[ dest++ ] = in[ start++ ];
+    }
+    while  ( (int)in.size() > dest )
+        in.pop_back();
+}
+
+
+static  void   remove_consecutive_dup( vec_point_2d  & in )
+{
+    int  dest, pos;
+
+    if  ( in.size() < 1 )
+        return;
+
+    dest = pos = 0;
+
+    // copy first entry
+    in[ dest++ ] = in[ pos++ ];
+    while  ( pos < ( (int)in.size() - 1 ) ) {
+        if  ( in[ pos - 1 ]->equal_real( *(in[ pos ]) ) ) {
+            pos++;
+            continue;
+        }
+        in[ dest++ ] = in[ pos++ ];
+    }
+    in[ dest++ ] = in[ pos++ ];
+
+    while  ( (int)in.size() > dest )
+        in.pop_back();
+}
+
+
+// Copyright 2001 softSurfer, 2012 Dan Sunday
+// This code may be freely used and modified for any purpose
+// providing that this copyright notice is included with it.
+// SoftSurfer makes no warranty for this code, and cannot be held
+// liable for any real or imagined damage resulting from its use.
+// Users of this code must verify correctness for their application.
+// isLeft(): tests if a point is Left|On|Right of an infinite line.
+//    Input:  three points P0, P1, and P2
+//    Return: >0 for P2 left of the line through P0 and P1
+//            =0 for P2 on the line
+//            <0 for P2 right of the line
+//    See: Algorithm 1 on Area of Triangles
+inline float
+isLeft( const point2d &P0, const point2d &P1, const point2d &P2 )
+{
+    return (P1.x - P0.x)*(P2.y - P0.y) - (P2.x - P0.x)*(P1.y - P0.y);
+}
+
+
+
+
+// Switched to Monotone Chain Algorithm to avoid the area computation, which
+// is problematic for strict weak ordering when doing sorting.  Useful links:
+// 
http://stackoverflow.com/questions/1041620/most-efficient-way-to-erase-duplicates-and-sort-a-c-vector
+// http://geomalgorithms.com/a10-_hull-1.html
+void  convex_hull( vec_point_2d  & in, vec_point_2d  & out )
+{
+
+    CompareByAngle  comp;
+    int  position;
+
+    assert( in.size() > 1 );
+
+    comp.base = *( get_min_point( in, position ));
+    std::swap( in[ 0 ], in[ position ] );
+
+    remove_duplicate( in, in[ 0 ], 1 );
+
+    for  ( int  ind = 0; ind < (int)in.size(); ind++ ) {
+        assert( in[ ind ] != NULL );
+    }
+
+    // Copyright 2001 softSurfer, 2012 Dan Sunday
+    // This code may be freely used and modified for any purpose
+    // providing that this copyright notice is included with it.
+    // SoftSurfer makes no warranty for this code, and cannot be held
+    // liable for any real or imagined damage resulting from its use.
+    // Users of this code must verify correctness for their application.
+
+    int n = in.size();
+    sort( in.begin() + 1, in.end(), comp );
+    remove_consecutive_dup( in );
+    out.reserve(n);
+
+    // the output array out[] will be used as the stack
+    int    bot=0, top=(-1);   // indices for bottom and top of the stack
+    int    i;                 // array scan index
+
+
+    // Get the indices of points with min x-coord and min|max y-coord
+    int minmin = 0, minmax;
+    float xmin = in[0]->x;
+    for (i=1; i<n; i++)
+        if (in[i]->x != xmin) break;
+    minmax = i-1;
+    if (minmax == n-1) {       // degenerate case: all x-coords == xmin
+        out.push_back(in[minmin]);
+        if (in[minmax]->y != in[minmin]->y) // a  nontrivial segment
+            out.push_back(in[minmax]);
+        out.push_back(in[minmin]);
+        return;
+    }
+
+    // Get the indices of points with max x-coord and min|max y-coord
+    int maxmin, maxmax = n-1;
+    float xmax = in[n-1]->x;
+    for (i=n-2; i>=0; i--)
+        if (in[i]->x != xmax) break;
+    maxmin = i+1;
+
+    // Compute the lower hull on the stack H
+    out.push_back(in[minmin]); ++top; // push  minmin point onto stack
+    i = minmax;
+    while (++i <= maxmin)
+    {
+        // the lower line joins in[minmin]  with in[maxmin]
+        if (isLeft( *in[minmin], *in[maxmin], *in[i])  >= 0 && i < maxmin)
+            continue;           // ignore in[i] above or on the lower line
+
+        while (top > 0)         // there are at least 2 points on the stack
+        {
+            // test if  in[i] is left of the line at the stack top
+            if (isLeft(  *out[top-1], *out[top], *in[i]) > 0)
+                 break;         // in[i] is a new hull  vertex
+            else {
+                 --top;
+                 out.pop_back();         // pop top point off  stack
+            }
+        }
+        ++top;
+        out.push_back(in[i]);        // push in[i] onto stack
+    }
+    // Next, compute the upper hull on the stack out above  the bottom hull
+    if (maxmax != maxmin)      // if  distinct xmax points
+        out.push_back(in[maxmax]);  // push maxmax point onto stack
+    bot = top;               // the bottom point of the upper hull stack
+    i = maxmin;
+    while (--i > minmax)
+    {
+        // the upper line joins in[maxmax]  with in[minmax]
+        if (isLeft( *in[maxmax], *in[minmax], *in[i])  >= 0 && i > minmax)
+            continue;           // ignore in[i] below or on the upper line
+
+
+        while (top > bot)     // at least 2 points on the upper stack
+        {
+             // test if  in[i] is left of the line at the stack top
+             if (isLeft( *out[top-1], *out[top], *in[i]) > 0) {
+                  break;         // in[i] is a new hull  vertex
+             } else {
+                  --top;
+                  out.pop_back();         // pop top point off  stack
+             }
+        }
+        ++top;
+        out.push_back(in[i]);        // push in[i] onto stack
+    }
+    if (minmax != minmin)
+        out.push_back(in[minmin]);  // push  joining endpoint onto stack
+#ifndef GDIAM_QUIET
+    std::vector<point2d_ptr>::iterator it;
+    for(it = out.begin(); it != out.end(); it++){
+           std::cout << "point: " << (*it)->x << "," << (*it)->y << "\n";
+    }
+#endif
+
+}
+
+
+struct bbox_2d_info
+{
+    gdiam_point_2d_t  vertices[ 4 ];
+    gdiam_real  area;
+
+    void  get_dir( int  ind, gdiam_point_2d  out ) {
+        out[ 0 ] = vertices[ ind ][ 0 ]
+            - vertices[ (ind + 1) % 4 ][ 0 ];
+        out[ 1 ] = vertices[ ind ][ 1 ]
+            - vertices[ (ind + 1) % 4 ][ 1 ];
+    }
+
+    void  dump() {
+        printf( "--- bbox 2d ----------------------------\n" );
+        for  ( int  ind = 0; ind < 4; ind++ )
+            printf( "%d: (%g, %g)\n", ind, vertices[ ind ][0],
+                    vertices[ ind ][1] );
+        for  ( int  ind = 0; ind < 4; ind++ ) {
+            gdiam_point_2d_t  dir;
+
+            get_dir( ind, dir );
+
+            printf( "dir %d: (%g, %g)\n", ind, dir[0],
+                    dir[1] );
+        }
+        printf( "\\----------------------------------\n" );
+    }
+
+};
+
+#define  EPS  1e-6
+inline  bool   eq_real( gdiam_real  a, gdiam_real  b ) {
+    return  ( ( ( b - EPS ) < a )
+              &&  ( a < (b + EPS) ) );
+}
+
+class  MinAreaRectangle
+{
+private:
+    vec_point_2d   ch;
+    gdiam_real  * angles;
+
+public:
+    void  dump_ch() {
+        for  ( int  ind = 0; ind < (int)ch.size(); ind++ ) {
+            printf( "%d: (%g, %g)\n", ind, ch[ ind ]->x,
+                    ch[ ind ]->y );
+        }
+    }
+
+    void  compute_edge_dir( int  u ) {
+        int  u2;
+        double  ang;
+        double  x1, y1, x2, y2;
+
+        u2 = (u + 1) % ch.size();
+
+        x1 = ch[ u ]->x;
+        y1 = ch[ u ]->y;
+        x2 = ch[ u2 ]->x;
+        y2 = ch[ u2 ]->y;
+
+        ang = atan2( y2 - y1, x2 - x1 );
+        if  ( ang < 0 )
+            ang += 2.0 * PI;
+        angles[ u ] = ang;
+
+        // floating point nonsence. A huck to solve this...
+        if  ( ( u > 0 )
+              &&  ( angles[ u ] < angles[ u - 1 ] )
+              &&   eq_real( angles[ u ], angles[ u - 1 ] ) )
+            angles[ u ] = angles[ u - 1 ];
+    }
+
+    /* Finding the first vertex whose edge is over a given angle */
+    int  find_vertex( int  start_vertex,
+                      double  trg_angle ) {
+        double  prev_angle, curr_angle;
+        bool  f_found;
+        int  ver, prev_vertex;
+
+        f_found = false;
+
+        prev_vertex = start_vertex - 1;
+        if  ( prev_vertex < 0 )
+            prev_vertex = ch.size() - 1;
+
+        prev_angle = angles[ prev_vertex ];
+        ver = start_vertex;
+        while  ( ! f_found ) {
+            curr_angle = angles[ ver ];
+            if ( prev_angle <= curr_angle )
+                f_found = ( ( prev_angle < trg_angle)
+                            &&  ( trg_angle <= curr_angle ) );
+            else
+                f_found = ( ( prev_angle < trg_angle )
+                            ||  ( trg_angle <= curr_angle ));
+
+            if ( f_found)
+                break;
+            else
+                prev_angle = curr_angle;
+
+            ver = ( ver + 1 ) % ch.size();
+        }
+
+        return  ver;
+    }
+
+
+    /* Computing the intersection point of two lines, each given by a
+   point and slope */
+    void  compute_crossing( int  a_ind, double  a_angle,
+                            int  b_ind, double  b_angle,
+                            gdiam_real  & x,
+                            gdiam_real  & y ) {
+        double  a_slope, b_slope, x_a, x_b, y_a, y_b;
+
+        if ( eq_real( a_angle, 0.0 )  ||  eq_real( a_angle, PI ) ) {
+            x = ch[ b_ind ]->x;
+            y = ch[ a_ind ]->y;
+            return;
+        }
+        if ( eq_real( a_angle, PI/2.0 )  ||  eq_real( a_angle, PI * 1.5 ) ) {
+            x = ch[ a_ind ]->x;
+            y = ch[ b_ind ]->y;
+            return;
+        }
+
+        a_slope = tan( a_angle );
+        b_slope = tan( b_angle );
+        x_a = ch[ a_ind ]->x;
+        y_a = ch[ a_ind ]->y;
+        x_b = ch[ b_ind ]->x;
+        y_b = ch[ b_ind ]->y;
+
+        double  a_const, b_const, x_out, y_out;
+        a_const = y_a - a_slope * x_a;
+        b_const = y_b - b_slope * x_b;
+        x_out = - ( a_const - b_const ) / (a_slope - b_slope);
+        y_out = a_slope * x_out + a_const;
+        x = x_out;
+        y = y_out;
+    }
+
+
+    void  get_bbox( int   a_ind, gdiam_real   a_angle,
+                    int   b_ind, gdiam_real   b_angle,
+                    int   c_ind, gdiam_real   c_angle,
+                    int   d_ind, gdiam_real   d_angle,
+                    bbox_2d_info   & bbox,
+                    gdiam_real  & area ) {
+        compute_crossing( a_ind, a_angle, b_ind, b_angle,
+                          bbox.vertices[ 0 ][ 0 ],
+                          bbox.vertices[ 0 ][ 1 ] );
+        compute_crossing( b_ind, b_angle, c_ind, c_angle,
+                          bbox.vertices[ 1 ][ 0 ],
+                          bbox.vertices[ 1 ][ 1 ] );
+        compute_crossing( c_ind, c_angle, d_ind, d_angle,
+                          bbox.vertices[ 2 ][ 0 ],
+                          bbox.vertices[ 2 ][ 1 ] );
+        compute_crossing( d_ind, d_angle, a_ind, a_angle,
+                          bbox.vertices[ 3 ][ 0 ],
+                          bbox.vertices[ 3 ][ 1 ] );
+
+        area = pnt_distance_2d( bbox.vertices[ 0 ],
+                              bbox.vertices[ 1 ] )
+            * pnt_distance_2d( bbox.vertices[ 0 ],
+                               bbox.vertices[ 3 ] );
+    }
+
+    /* Given one angle (bbx direction), find the other three */
+    void  get_angles( int  ind,
+                      gdiam_real   & angle_1,
+                      gdiam_real   & angle_2,
+                      gdiam_real   & angle_3 ) {
+        double   angle;
+
+        angle = angles[ ind ];
+        angle_1 = angle + PI * 0.5;
+
+        if   ( angle_1 >= (2.0 * PI) )
+            angle_1 -= 2.0 * PI;
+
+        angle_2 = angle + PI;
+        if ( angle_2 >= (2.0 * PI) )
+            angle_2 -= 2.0 * PI;
+
+        angle_3 = angle + 1.5 * PI;
+        if ( angle_3 >= (2.0 * PI) )
+            angle_3 -= 2.0 * PI;
+    }
+
+    void  compute_min_bbox_inner( bbox_2d_info   & min_bbox,
+                                  gdiam_real  & min_area ) {
+        int        u, v, s, t;
+        gdiam_real     ang1, ang2, ang3, tmp_area;
+        bbox_2d_info  tmp_bbox;
+
+        angles = (gdiam_real *)malloc( sizeof( gdiam_real )
+                                           * (int)ch.size() );
+        assert( angles != NULL );
+
+        /* Pre-computing all edge directions */
+        for (u = 0; u < (int)ch.size(); u ++)
+            compute_edge_dir( u );
+
+        /* Initializing the search */
+        get_angles( 0, ang1, ang2, ang3 );
+
+        s = find_vertex( 0, ang1 );
+        v = find_vertex( s, ang2 );
+        t = find_vertex( v, ang3 );
+
+        get_bbox( 0, angles[ 0 ],
+                  s, ang1,
+                  v, ang2,
+                  t, ang3,
+                  min_bbox, min_area );
+
+        /* Performing a double rotating calipers */
+        for  ( u = 1; u < (int)ch.size(); u ++ ) {
+            get_angles( u, ang1, ang2, ang3 );
+            s = find_vertex( s, ang1 );
+            v = find_vertex( v, ang2 );
+            t = find_vertex( t, ang3 );
+            get_bbox( u, angles[ u ],
+                      s, ang1,
+                      v, ang2,
+                      t, ang3,
+                      tmp_bbox, tmp_area );
+            if  ( min_area > tmp_area ) {
+                min_area = tmp_area;
+                min_bbox = tmp_bbox;
+            }
+        }
+        free( angles );
+        angles = NULL;
+    }
+
+    void  compute_min_bbox( vec_point_2d   & points,
+                            bbox_2d_info   & min_bbox,
+                            gdiam_real  & min_area ) {
+        convex_hull( points, ch );
+        compute_min_bbox_inner( min_bbox, min_area );
+    }
+
+};
+
+void   dump_points( gdiam_point  * in_arr,
+                    int  size )
+{
+    for  ( int  ind = 0; ind < size; ind++ ) {
+        printf( "%d: (%g, %g, %g)\n", ind,
+                in_arr[ ind ][ 0 ],
+                in_arr[ ind ][ 1 ],
+                in_arr[ ind ][ 2 ] );
+    }
+}
+
+#define  ZERO_EPS  (1e-6)
+
+static void   construct_base_inner( gdiam_point  pnt1,
+                             gdiam_point  pnt2,
+                             gdiam_point  pnt3 )
+{
+    pnt_normalize( pnt1 );
+    pnt_normalize( pnt2 );
+    pnt_normalize( pnt3 );
+
+    if  ( ( pnt_length( pnt1 ) < ZERO_EPS )
+          &&  ( pnt_length( pnt2 ) < ZERO_EPS )
+          &&  ( pnt_length( pnt3 ) < ZERO_EPS ) ){
+        assert( false );
+    }
+
+    if  ( ( pnt_length( pnt1 ) < ZERO_EPS )
+          &&  ( pnt_length( pnt2 ) < ZERO_EPS ) ) {
+        gdiam_generate_orthonormal_base( pnt3, pnt1, pnt2 );
+        return;
+    }
+    if  ( ( pnt_length( pnt1 ) < ZERO_EPS )
+          &&  ( pnt_length( pnt3 ) < ZERO_EPS ) ) {
+        gdiam_generate_orthonormal_base( pnt2, pnt1, pnt3 );
+        return;
+    }
+    if  ( ( pnt_length( pnt2 ) < ZERO_EPS )
+          &&  ( pnt_length( pnt3 ) < ZERO_EPS ) ) {
+        gdiam_generate_orthonormal_base( pnt1, pnt2, pnt3 );
+        return;
+    }
+    if  ( pnt_length( pnt1 ) < ZERO_EPS ) {
+        pnt_cross_prod( pnt2, pnt3, pnt1 );
+        return;
+    }
+    if  ( pnt_length( pnt2 ) < ZERO_EPS ) {
+        pnt_cross_prod( pnt1, pnt3, pnt2 );
+        return;
+    }
+    if  ( pnt_length( pnt3 ) < ZERO_EPS ) {
+        pnt_cross_prod( pnt1, pnt2, pnt3 );
+        return;
+    }
+}
+
+void   construct_base( gdiam_point  pnt1,
+                       gdiam_point  pnt2,
+                       gdiam_point  pnt3 )
+{
+    construct_base_inner( pnt1, pnt2, pnt3 );
+    pnt_scale_and_add( pnt2, -pnt_dot_prod( pnt1, pnt2 ),
+                       pnt1 );
+    pnt_normalize( pnt2 );
+
+    pnt_scale_and_add( pnt3, -pnt_dot_prod( pnt1, pnt3 ),
+                       pnt1 );
+    pnt_scale_and_add( pnt3, -pnt_dot_prod( pnt2, pnt3 ),
+                       pnt2 );
+    pnt_normalize( pnt3 );
+}
+
+
+class  ProjPointSet
+{
+private:
+    gdiam_point_t  base_x, base_y, base_proj;
+    point2d  * arr;
+    vec_point_2d   points, ch;
+    gdiam_bbox   bbox;
+    gdiam_point  * in_arr;
+    int  size;
+
+public:
+    ProjPointSet() : arr(NULL), in_arr(NULL), size( 0 ) {}
+
+    ~ProjPointSet() {
+        term();
+    }
+    void  init( gdiam_point  dir,
+                gdiam_point  * _in_arr,
+                int  _size ) {
+        arr = NULL;
+
+        if  ( pnt_length( dir ) == 0.0 ) {
+            dump_points( _in_arr, _size );
+            pnt_dump( dir );
+            fflush( stdout );
+            fflush( stderr );
+            assert( pnt_length( dir ) > 0.0 );
+        }
+        size = _size;
+        in_arr = _in_arr;
+        assert( size > 0 );
+
+        pnt_copy( base_proj, dir );
+        gdiam_generate_orthonormal_base( base_proj, base_x, base_y );
+
+        arr = (point2d *)malloc( sizeof( point2d ) * size );
+        assert( arr != 0 );
+
+        for  ( int  ind = 0; ind < size; ind++ ) {
+            arr[ ind ].init( in_arr[ ind ], base_x, base_y );
+            points.push_back( &( arr[ ind ] ) );
+        }
+    }
+
+    void  compute() {
+        MinAreaRectangle  mar;
+        bbox_2d_info   min_bbox;
+        gdiam_real   min_area;
+        double  x1, y1, x2, y2;
+        gdiam_point_t  out_1, out_2;
+
+        mar.compute_min_bbox( points, min_bbox, min_area );
+
+        // We take the resulting min_area rectangle and lift it back to 3d...
+        x1 = min_bbox.vertices[ 0 ][ 0 ] -
+            min_bbox.vertices[ 1 ][ 0 ];
+        y1 = min_bbox.vertices[ 0 ][ 1 ] -
+            min_bbox.vertices[ 1 ][ 1 ];
+        x2 = min_bbox.vertices[ 0 ][ 0 ] -
+            min_bbox.vertices[ 3 ][ 0 ];
+        y2 = min_bbox.vertices[ 0 ][ 1 ] -
+            min_bbox.vertices[ 3 ][ 1 ];
+
+        double  len;
+
+        len = sqrt( x1 * x1 + y1 * y1 );
+        if  ( len > 0.0 ) {
+            x1 /= len;
+            y1 /= len;
+        }
+
+        len = sqrt( x2 * x2 + y2 * y2 );
+        if  ( len > 0.0 ) {
+            x2 /= len;
+            y2 /= len;
+        }
+
+        pnt_zero( out_1 );
+        pnt_scale_and_add( out_1, x1, base_x );
+        pnt_scale_and_add( out_1, y1, base_y );
+        pnt_normalize( out_1 );
+
+        pnt_zero( out_2 );
+        pnt_scale_and_add( out_2, x2, base_x );
+        pnt_scale_and_add( out_2, y2, base_y );
+        pnt_normalize( out_2 );
+
+        construct_base( base_proj, out_1, out_2 );
+        if  ( ( ! (fabs( pnt_dot_prod( base_proj, out_1 ) ) < 1e-6 ) )
+              ||  ( ! (fabs( pnt_dot_prod( base_proj, out_2 ) ) < 1e-6 ) )
+              ||  ( ! (fabs( pnt_dot_prod( out_1, out_2 ) ) < 1e-6 ) ) ) {
+            printf( "should be all close to zero: %g, %g, %g\n",
+                    pnt_dot_prod( base_proj, out_1 ),
+                    pnt_dot_prod( base_proj, out_2 ),
+                    pnt_dot_prod( out_1, out_2 ) );
+            pnt_dump( base_proj );
+            pnt_dump( out_1 );
+            pnt_dump( out_2 );
+
+
+            printf( "real points:\n" );
+            dump_points( in_arr, size );
+
+            printf( "points on CH:\n" );
+            dump( points );
+
+            printf( "BBox:\n" );
+            min_bbox.dump();
+
+            fflush( stdout );
+            fflush( stderr );
+            assert( fabs( pnt_dot_prod( base_proj, out_1 ) ) < 1e-6 );
+            assert( fabs( pnt_dot_prod( base_proj, out_2 ) ) < 1e-6 );
+            assert( fabs( pnt_dot_prod( out_1, out_2 ) ) < 1e-6 );
+        }
+
+        bbox.init( base_proj, out_1, out_2 );
+        for  ( int  ind = 0; ind < size; ind++ )
+            bbox.bound( in_arr[ ind ] );
+    }
+
+    gdiam_bbox   & get_bbox() {
+        return  bbox;
+    }
+
+    void  term() {
+        if  ( arr != NULL ) {
+            free( arr );
+            arr = NULL;
+        }
+    }
+    void  init() {
+    }
+};
+
+
+gdiam_bbox   gdiam_mvbb_optimize( gdiam_point  * start, int  size,
+                                  gdiam_bbox  bb_out, int  times  )
+{
+    gdiam_bbox  bb_tmp;
+
+    for  ( int  ind = 0; ind < times; ind++ ) {
+        ProjPointSet  pps;
+
+        if  ( pnt_length( bb_out.get_dir( ind % 3 ) ) == 0.0 ) {
+            printf( "Dumping!\n" );
+            bb_out.dump();
+            fflush( stdout );
+            continue;
+        }
+
+        pps.init( bb_out.get_dir( ind % 3 ), start, size );
+
+        pps.compute();
+        bb_tmp = pps.get_bbox();
+
+        if  ( bb_tmp.volume() < bb_out.volume() )
+            bb_out = bb_tmp;
+    }
+
+    return  bb_out;
+}
+
+
+gdiam_bbox   gdiam_approx_mvbb( gdiam_point  * start, int  size,
+                                gdiam_real  UNUSED(eps) )
+{
+    gdiam_bbox  bb, bb2;
+
+    bb = gdiam_approx_const_mvbb( start, size, 0.0, NULL );
+    bb2 = gdiam_mvbb_optimize( start, size,  bb, 10 );
+
+    return  bb2;
+}
+
+
+static int  gcd2( int  a, int  b )
+{
+    if  ( a == 0  ||  a == b )
+        return  b;
+    if  ( b == 0 )
+        return  a;
+    if  ( a > b )
+        return  gcd2( a % b, b );
+    else
+        return  gcd2( a, b % a );
+}
+
+
+static int  gcd3( int  a, int  b, int  c )
+{
+    a = abs( a );
+    b = abs( b );
+    c = abs( c );
+    if   ( a == 0 )
+        return  gcd2( b, c );
+    if   ( b == 0 )
+        return  gcd2( a, c );
+    if   ( c == 0 )
+        return  gcd2( a, b );
+
+    return  gcd2( a, gcd2( b, c ) );
+}
+
+
+static void  try_direction( gdiam_bbox  & bb,
+                            gdiam_bbox  & bb_out,
+                            gdiam_point  * start,
+                            int  size,
+                            int  x_coef,
+                            int  y_coef,
+                            int  z_coef )
+{
+    gdiam_bbox  bb_new;
+
+    if  ( gcd3( x_coef, y_coef, z_coef ) > 1 )
+        return;
+    if  ( ( x_coef == 0 )  &&  ( y_coef == 0 )
+          &&  ( z_coef == 0 ) )
+        return;
+    gdiam_point_t  new_dir;
+    bb.combine( new_dir, x_coef, y_coef, z_coef );
+
+    ProjPointSet  pps;
+
+    pps.init( new_dir, start, size );
+
+    pps.compute();
+
+    bb_new = pps.get_bbox();
+    bb_new = gdiam_mvbb_optimize( start, size, bb_new, 10 );
+
+    if  ( bb_new.volume() < bb_out.volume() )
+        bb_out = bb_new;
+}
+
+
+gdiam_bbox   gdiam_approx_mvbb_grid( gdiam_point  * start, int  size,
+                                     int  grid_size )
+{
+    gdiam_bbox  bb, bb_out;
+
+    bb_out = bb = gdiam_approx_const_mvbb( start, size, 0.0, NULL );
+    if  ( bb.volume() == 0 ) {
+        dump_points( start, size );
+        printf( "1zero volume???\n" );
+        bb.dump();
+    }
+
+    bb_out = bb = gdiam_mvbb_optimize( start, size, bb_out, 10 );
+
+    if  ( bb.volume() == 0 ) {
+        printf( "2zero volume???\n" );
+        bb.dump();
+    }
+
+    for  ( int  x_coef = -grid_size; x_coef <= grid_size; x_coef++ )
+        for  ( int  y_coef = -grid_size; y_coef <= grid_size; y_coef++ )
+            for  ( int  z_coef = 0; z_coef <= grid_size; z_coef++ )
+                try_direction( bb, bb_out, start, size,
+                               x_coef, y_coef, z_coef );
+
+    bb_out = gdiam_mvbb_optimize( start, size, bb_out, 10 );
+
+    return  bb_out;
+}
+
+
+static void   register_point( gdiam_point  pnt,
+                              gdiam_point  * tops,
+                              gdiam_point  * bottoms,
+                              int  grid_size,
+                              gdiam_bbox  & bb )
+{
+    gdiam_point_t  pnt_bb, pnt_bottom, pnt_top;
+    int  x_ind, y_ind, position;
+
+    bb.get_normalized_coordinates( pnt, pnt_bb );
+
+    // x_ind
+    x_ind = (int)( pnt_bb[ 0 ] * grid_size );
+    assert( ( -1 <= x_ind )  &&  ( x_ind <= grid_size ) );
+    if  ( x_ind < 0 )
+        x_ind = 0;
+    if  ( x_ind >= grid_size )
+        x_ind = grid_size - 1;
+
+    // y_ind
+    y_ind = (int)( pnt_bb[ 1 ] * grid_size );
+    assert( ( -1 <= y_ind )  &&  ( y_ind <= grid_size ) );
+    if  ( y_ind < 0 )
+        y_ind = 0;
+    if  ( y_ind >= grid_size )
+        y_ind = grid_size - 1;
+
+    position = x_ind + y_ind * grid_size;
+    if  ( tops[ position ] == NULL ) {
+        tops[ position ] = bottoms[ position ] = pnt;
+        return;
+    }
+
+    bb.get_normalized_coordinates( tops[ position ], pnt_top );
+    if  ( pnt_top[ 2 ] < pnt_bb[ 2 ] )
+        tops[ position ] = pnt;
+
+    bb.get_normalized_coordinates( bottoms[ position ], pnt_bottom );
+    if  ( pnt_bottom[ 2 ] > pnt_bb[ 2 ] )
+        bottoms[ position ] = pnt;
+}
+
+
+
+// gdiam_convex_sample
+
+//   We are given a point set, and (hopefully) a tight fitting
+// bounding box. We compute a sample of the given size that represents
+// the point-set. The only guarenteed is that if we use ample of size m,
+// we get an approximation of quality about 1/\sqrt{m}. Note that we pad
+// the sample if necessary to get the desired size.
+gdiam_point  * gdiam_convex_sample( gdiam_point  * start, int  size,
+                                    gdiam_bbox  & bb,
+                                    int  sample_size )
+{
+    int  grid_size, mem_size, grid_entries;
+    gdiam_point  * bottoms, * tops, * out_arr;
+    int  out_count;
+
+    assert( sample_size > 1 );
+
+    // we want the grid to be on the two minor dimensions.
+    bb.set_third_dim_longest();
+
+    grid_size = (int)sqrt((double)(sample_size / 2) );
+
+    grid_entries = grid_size * grid_size;
+    mem_size = (int)( sizeof( gdiam_point ) * grid_size * grid_size );
+
+    bottoms = (gdiam_point *)malloc( mem_size );
+    tops = (gdiam_point *)malloc( mem_size );
+    out_arr = (gdiam_point *)malloc( sizeof( gdiam_point ) * sample_size );
+
+    assert( bottoms != NULL );
+    assert( tops != NULL );
+    assert( out_arr != NULL );
+
+    for  ( int  ind = 0; ind < grid_entries; ind++ )
+        tops[ ind ] = bottoms[ ind ] = NULL;
+
+    // Now we stream the points registering them with the relevant
+    // shaft in the grid.
+    for  ( int  ind = 0; ind < size; ind++ )
+        register_point( start[ ind ], tops, bottoms,
+                        grid_size, bb );
+
+    out_count = 0;
+    for  ( int  ind = 0; ind < grid_entries; ind++ ) {
+        if  ( tops[ ind ] == NULL )
+            continue;
+
+        out_arr[ out_count++ ] = tops[ ind ];
+        if  ( tops[ ind ] != bottoms[ ind ] )
+            out_arr[ out_count++ ] = bottoms[ ind ];
+    }
+
+    // We dont have enough entries in our sample - lets randomly pick
+    // points.
+    while  ( out_count < sample_size )
+        out_arr[ out_count++ ] = start[ rand() % size ];
+
+    free( tops );
+    free( bottoms );
+
+    return  out_arr;
+}
+
+
+gdiam_bbox   gdiam_approx_mvbb_grid_sample( gdiam_point  * start, int  size,
+                                            int  grid_size, int  sample_size )
+{
+    gdiam_bbox  bb, bb_new;
+    gdiam_point  * sample;
+
+    if  ( sample_size >= size )
+        return   gdiam_approx_mvbb_grid( start, size, grid_size );
+
+    bb = gdiam_approx_const_mvbb( start, size, 0.0, NULL );
+
+    sample = gdiam_convex_sample( start, size, bb, sample_size );
+
+    bb_new = gdiam_approx_mvbb_grid( sample, sample_size, grid_size );
+
+    for  ( int  ind = 0; ind < size; ind++ )
+        bb_new.bound( start[ ind ] );
+
+    return  bb_new;
+}
+
+
+
+gdiam_bbox   gdiam_approx_mvbb_grid_sample( gdiam_real  * start, int  size,
+                                            int  grid_size, int  sample_size )
+{
+    gdiam_point  * p_arr;
+    gdiam_bbox  bb;
+
+    p_arr = gdiam_convert( start, size );
+    bb = gdiam_approx_mvbb_grid_sample( p_arr, size, grid_size, sample_size );
+    free( p_arr );
+
+    return  bb;
+}
+
+#if defined(__GNUC__) && !defined(__clang__)
+#  pragma GCC diagnostic pop /* end ignoring warnings */
+#elif defined(__clang__)
+#  pragma clang diagnostic pop /* end ignoring warnings */
+#endif
+
+/* gdiam.C - End of File ------------------------------------------*/
+
+
+// Local Variables:
+// tab-width: 8
+// mode: C++
+// c-basic-offset: 4
+// indent-tabs-mode: t
+// c-file-style: "stroustrup"
+// End:
+// ex: shiftwidth=4 tabstop=8

Copied: brlcad/trunk/src/librt/gdiam/gdiam.hpp (from rev 77314, 
brlcad/trunk/src/other/libgdiam/gdiam.hpp)
===================================================================
--- brlcad/trunk/src/librt/gdiam/gdiam.hpp                              (rev 0)
+++ brlcad/trunk/src/librt/gdiam/gdiam.hpp      2020-10-01 21:41:50 UTC (rev 
77315)
@@ -0,0 +1,727 @@
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
+ * gdiam.hpp -
+ *     Implmeents an algorithm for computing a diameter,
+ *
+ * Copyright 2001 Sariel Har-Peled ([email protected])
+ * https://sarielhp.org/research/papers/00/diameter/diam_prog.html
+ *
+ * Note:  gdiam is available under multiple licenses - we make
+ * use of it under the MIT license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a 
copy of
+ * this software and associated documentation files (the "Software"), to deal 
in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
copies
+ * of the Software, and to permit persons to whom the Software is furnished to 
do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in 
all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
THE
+ * SOFTWARE.
+ *
+ * Code is based on the paper:
+ *   A Practical Approach for Computing the Diameter of a Point-Set.
+ *   Sariel Har-Peled
+ \*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+
+#ifndef  __GDIAM__H
+#define  __GDIAM__H
+
+/* for g++ to quell warnings */
+#if defined(__GNUC__) && !defined(__clang__)
+#  pragma GCC diagnostic push /* start new diagnostic pragma */
+#  pragma GCC diagnostic ignored "-Wfloat-equal"
+#elif defined(__clang__)
+#  pragma clang diagnostic push /* start new diagnostic pragma */
+#  pragma clang diagnostic ignored "-Wfloat-equal"
+#endif
+
+#define GDIAM_FLOAT_ZERO(val) (((val) > -1.0e-37) && ((val) < 1.0e-37))
+
+#define  GDIAM_DIM   3
+typedef  double  gdiam_real;
+typedef  gdiam_real    gdiam_point_t[ GDIAM_DIM ];
+typedef  gdiam_real    gdiam_point_2d_t[ 2 ];
+typedef  gdiam_real  * gdiam_point_2d;
+typedef  gdiam_real  * gdiam_point;
+typedef  const gdiam_real  * gdiam_point_cnt;
+
+#ifndef __MINMAX_DEFINED
+#define __MINMAX_DEFINED
+
+#include<stdio.h>
+#include<cmath>
+#include<algorithm>
+#include<assert.h>
+#define min std::min
+#define max std::max
+
+#endif /* MIN_MAX */
+
+template <class T>
+inline void     gdiam_exchange( T   & a, T    & b )
+{
+    T   tmp = a;
+
+    a = b;
+    b = tmp;
+}
+
+inline gdiam_real   pnt_length( const gdiam_point  pnt )
+{
+    return  sqrt( pnt[ 0 ] * pnt[ 0 ] + pnt[ 1 ] * pnt[ 1 ]
+           + pnt[ 2 ] * pnt[ 2 ] );
+}
+
+inline void  pnt_normalize( gdiam_point  pnt )
+{
+    gdiam_real  len = pnt_length( pnt );
+    if  ( GDIAM_FLOAT_ZERO(len) )
+       return;
+
+    pnt[ 0 ] /= len;
+    pnt[ 1 ] /= len;
+    pnt[ 2 ] /= len;
+}
+
+inline    void  pnt_copy( gdiam_point_t   dest,
+       gdiam_point_t   src )
+{
+    dest[ 0 ] = src[ 0 ];
+    dest[ 1 ] = src[ 1 ];
+    dest[ 2 ] = src[ 2 ];
+}
+inline void  pnt_zero( gdiam_point  dst ) {
+    dst[ 0 ] = dst[ 1 ] = dst[ 2 ] = 0;
+}
+inline void  pnt_dump( gdiam_point_cnt  pnt ) {
+    printf( "(%g, %g, %g)\n", pnt[ 0 ], pnt[ 1 ], pnt[ 2 ] );
+}
+
+
+inline gdiam_real  pnt_dot_prod( gdiam_point_cnt  a,
+       gdiam_point_cnt  b )
+{
+    return  a[ 0 ] * b[ 0 ]
+       + a[ 1 ] * b[ 1 ]
+       + a[ 2 ] * b[ 2 ];
+}
+
+inline void   pnt_cross_prod( const gdiam_point   a,
+       const gdiam_point   b,
+       const gdiam_point   out )
+{
+    out[ 0 ] = a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ];
+    out[ 1 ] = - ( a[ 0 ] * b[ 2 ] - a[ 2 ] * b[ 0 ] );
+    out[ 2 ] = a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ];
+}
+
+
+inline gdiam_real   pnt_distance_2d( gdiam_point_2d  p,
+       gdiam_point_2d  q )
+{
+    gdiam_real  valx = (p[ 0 ] - q[ 0 ]);
+    gdiam_real  valy = (p[ 1 ] - q[ 1 ]);
+
+    return  sqrt( valx * valx + valy * valy );
+}
+
+
+inline gdiam_real   pnt_distance( gdiam_point  p, gdiam_point  q )
+{
+    gdiam_real  valx = (p[ 0 ] - q[ 0 ]);
+    gdiam_real  valy = (p[ 1 ] - q[ 1 ]);
+    gdiam_real  valz = (p[ 2 ] - q[ 2 ]);
+
+    return  sqrt( valx * valx + valy * valy + valz * valz );
+}
+
+inline gdiam_real   pnt_distance( gdiam_point  p, gdiam_point  q,
+       gdiam_point_cnt  dir )
+{
+    gdiam_real  valx = (p[ 0 ] - q[ 0 ]);
+    gdiam_real  valy = (p[ 1 ] - q[ 1 ]);
+    gdiam_real  valz = (p[ 2 ] - q[ 2 ]);
+
+    gdiam_real  len, proj_len;
+
+    len = sqrt( valx * valx + valy * valy + valz * valz );
+
+    proj_len = dir[ 0 ] * valx + dir[ 1 ] * valy + dir[ 2 ] * valz;
+
+    return  sqrt( len * len - proj_len * proj_len );
+}
+
+inline void  pnt_init( gdiam_point  pnt,
+       gdiam_real  x,
+       gdiam_real  y,
+       gdiam_real  z )
+{
+    pnt[ 0 ] = x;
+    pnt[ 1 ] = y;
+    pnt[ 2 ] = z;
+}
+
+
+inline void  pnt_init_normalize( gdiam_point  pnt,
+       gdiam_real  x,
+       gdiam_real  y,
+       gdiam_real  z )
+{
+    pnt[ 0 ] = x;
+    pnt[ 1 ] = y;
+    pnt[ 2 ] = z;
+
+    pnt_normalize( pnt );
+}
+
+inline bool  pnt_isEqual( const gdiam_point  p,
+       const gdiam_point  q )
+{
+    // Assuming here the GDIAM_DIM == 3 !!!!
+    return  ( ( GDIAM_FLOAT_ZERO(p[0] - q[0]) )
+           &&  ( GDIAM_FLOAT_ZERO(p[0] - q[0]) )
+           &&  ( GDIAM_FLOAT_ZERO(p[0] - q[0]) ) );
+}
+
+inline void  pnt_scale_and_add( gdiam_point  dest,
+       gdiam_real  coef,
+       gdiam_point_cnt   vec ) {
+    dest[ 0 ] += coef * vec[ 0 ];
+    dest[ 1 ] += coef * vec[ 1 ];
+    dest[ 2 ] += coef * vec[ 2 ];
+}
+
+class  GPointPair
+{
+    public:
+       gdiam_real  distance;
+       gdiam_point  p, q;
+
+       GPointPair() : p(), q() {
+           distance = 0.0;
+       }
+
+       void  init( const gdiam_point  _p,
+               const gdiam_point  _q ) {
+           p = _p;
+           q = _q;
+           distance = pnt_distance( p, q );
+       }
+       void  init( const gdiam_point  _p,
+               const gdiam_point  _q,
+               const gdiam_point  proj ) {
+           p = _p;
+           q = _q;
+           distance = pnt_distance( p, q, proj );
+       }
+
+       void  init( const gdiam_point  pnt ) {
+           distance = 0;
+           p = q = pnt;
+       }
+
+       void  update_diam_simple( const gdiam_point  _p, const gdiam_point  _q 
) {
+           gdiam_real  new_dist;
+
+           new_dist = pnt_distance( _p, _q );
+           if  ( new_dist <= distance )
+               return;
+
+           //printf( "new_dist: %g\n", new_dist );
+           distance = new_dist;
+           p = _p;
+           q = _q;
+       }
+       void  update_diam_simple( const gdiam_point  _p, const gdiam_point  _q,
+               const gdiam_point  dir ) {
+           gdiam_real  new_dist;
+
+           new_dist = pnt_distance( _p, _q, dir );
+           if  ( new_dist <= distance )
+               return;
+
+           distance = new_dist;
+           p = _p;
+           q = _q;
+       }
+
+       void  update_diam( const gdiam_point  _p, const gdiam_point  _q ) {
+           //update_diam_simple( p, _p );
+           //update_diam_simple( p, _q );
+           //update_diam_simple( q, _p );
+           //update_diam_simple( q, _q );
+           update_diam_simple( _p, _q );
+       }
+       void  update_diam( const gdiam_point  _p, const gdiam_point  _q,
+               const gdiam_point  dir ) {
+           //update_diam_simple( p, _p );
+           //update_diam_simple( p, _q );
+           //update_diam_simple( q, _p );
+           //update_diam_simple( q, _q );
+           update_diam_simple( _p, _q, dir );
+       }
+
+
+       void  update_diam( GPointPair  & pp ) {
+           //update_diam_simple( p, pp.p );
+           //update_diam_simple( p, pp.q );
+           //update_diam_simple( q, pp.p );
+           //update_diam_simple( q, pp.q );
+           update_diam_simple( pp.p, pp.q );
+       }
+};
+
+
+
+
+class   GBBox {
+    private:
+       gdiam_real  min_coords[ GDIAM_DIM ];
+       gdiam_real  max_coords[ GDIAM_DIM ];
+
+    public:
+       void  init( const GBBox   & a,
+               const GBBox   & b ) {
+           for  (int  ind = 0; ind < GDIAM_DIM; ind++ ) {
+               min_coords[ ind ] = min( a.min_coords[ ind ],
+                       b.min_coords[ ind ] );
+               max_coords[ ind ] = max( a.max_coords[ ind ],
+                       b.max_coords[ ind ] );
+           }
+       }
+       void  dump() const {
+           gdiam_real  prod, diff;
+
+           prod = 1.0;
+           printf( "__________________________________________\n" );
+           for  (int  ind = 0; ind < GDIAM_DIM; ind++ ) {
+               printf( "%d: [%g...%g]\n", ind, min_coords[ ind ],
+                       max_coords[ ind ] );
+               diff = max_coords[ ind ] - min_coords[ ind ];
+               prod *= diff;
+           }
+           printf( "volume = %g\n", prod );
+           printf( "\\__________________________________________\n" );
+       }
+
+       void  center( gdiam_point  out ) const {
+           for  (int  ind = 0; ind < GDIAM_DIM; ind++ ) {
+               out[ ind ] = ( min_coords[ ind ] + max_coords[ ind ] ) / 2.0;
+           }
+       }
+
+       gdiam_real  volume() const {
+           gdiam_real  prod, val;
+
+           prod = 1;
+           for  ( int  ind = 0; ind < GDIAM_DIM; ind++ ) {
+               val = length_dim( ind );
+               prod *= val;
+           }
+
+           return  prod;
+       }
+       void  init() {
+           for  (int  ind = 0; ind < GDIAM_DIM; ind++ ) {
+               min_coords[ ind ] = 1e20;
+               max_coords[ ind ] = -1e20;
+           }
+       }
+       /*
+          void  dump() const {
+          printf( "---(" );
+          for  (int  ind = 0; ind < GDIAM_DIM; ind++ ) {
+          printf( "[%g, %g] ",
+          min_coords[ ind ],
+          max_coords[ ind ] );
+          }
+          printf( ")\n" );
+          }*/
+
+       const gdiam_real  & min_coord( int  coord ) const {
+           return  min_coords[ coord ];
+       }
+       const gdiam_real  & max_coord( int  coord ) const {
+           return  max_coords[ coord ];
+       }
+
+       void  bound( const gdiam_point   pnt ) {
+           //cout << "bounding: " << pnt << "\n";
+           for  ( int  ind = 0; ind < GDIAM_DIM; ind++ ) {
+               if  ( pnt[ ind ] < min_coords[ ind ] )
+                   min_coords[ ind ] = pnt[ ind ];
+               if  ( pnt[ ind ] > max_coords[ ind ] )
+                   max_coords[ ind ] = pnt[ ind ];
+           }
+       }
+
+       gdiam_real  length_dim( int  dim )  const {
+           return  max_coords[ dim ] - min_coords[ dim ];
+       }
+       int  getLongestDim() const {
+           int  dim = 0;
+           gdiam_real  len = length_dim( 0 );
+
+           for  ( int  ind = 1; ind < GDIAM_DIM; ind++ )
+               if  ( length_dim( ind ) > len ) {
+                   len = length_dim( ind );
+                   dim = ind;
+               }
+
+           return  dim;
+       }
+       gdiam_real  getLongestEdge() const {
+           return  length_dim( getLongestDim() );
+       }
+
+       gdiam_real   get_diam() const
+       {
+           gdiam_real  sum, val;
+
+           sum = 0;
+           for  ( int  ind = 0; ind < GDIAM_DIM; ind++ ) {
+               val = length_dim( ind );
+               sum += val * val;
+           }
+
+           return  sqrt( sum );
+       }
+
+       // in the following we assume that the length of dir is ONE!!!
+       // Note that the following is an overestaime - the diameter of
+       // projection of a cube, is bounded by the length of projections
+       // of its edges....
+       gdiam_real   get_diam_proj( gdiam_point  dir ) const
+       {
+           gdiam_real  sum, coord;
+           gdiam_real  prod, val;
+
+           //printf( "get_diam_proj: " );
+           sum = 0;
+           for  ( int  ind = 0; ind < GDIAM_DIM; ind++ ) {
+               coord = length_dim( ind );
+               //printf( "coord[%d]: %g\n",ind, coord );
+               prod = coord * dir [ ind ];
+               val = coord * coord - prod * prod;
+               assert( val >= 0 );
+               sum += sqrt( val );
+           }
+           //printf( "sum: %g, %g\n", sum, get_diam() );
+
+           // sum = squard diameter of the bounding box
+           // prod = length of projection of the diameter of cube on the
+           //      direction.
+
+           return  get_diam();
+       }
+
+       gdiam_real  get_min_coord( int  dim ) const {
+           return  min_coords[ dim ];
+       }
+       gdiam_real  get_max_coord( int  dim ) const {
+           return  max_coords[ dim ];
+       }
+};
+
+
+// gdiam_bbox is the famous - arbitrary orieted bounding box
+class  gdiam_bbox
+{
+    private:
+       gdiam_point_t  dir_1, dir_2, dir_3;
+
+       gdiam_real  low_1, high_1;
+       gdiam_real  low_2, high_2;
+       gdiam_real  low_3, high_3;
+       bool  f_init;
+
+    public:
+       gdiam_bbox() {
+           f_init = false;
+       }
+
+       gdiam_real  volume() const {
+           gdiam_real  len1, len2, len3;
+
+           len1 = ( high_1 - low_1 );
+           len2 = ( high_2 - low_2 );
+           len3 = ( high_3 - low_3 );
+
+           return  len1 * len2 * len3;
+       }
+
+
+       void  set_third_dim_longest() {
+           gdiam_point_t  pnt_tmp;
+
+           if  ( ( high_1 - low_1 ) > ( high_3 - low_3 ) ) {
+               gdiam_exchange( high_1, high_3 );
+               gdiam_exchange( low_1, low_3 );
+
+               memcpy( pnt_tmp, dir_1, sizeof( dir_1 ) );
+               //pnt_tmp = dir_1;
+               memcpy( dir_1, dir_3, sizeof( dir_3) );
+               //dir_1 = dir_3;
+               memcpy( dir_3, pnt_tmp, sizeof( dir_3 ) );
+               //dir_3 = pnt_tmp;
+           }
+           if  ( ( high_2 - low_2 ) > ( high_3 - low_3 ) ) {
+               gdiam_exchange( high_2, high_3 );
+               gdiam_exchange( low_2, low_3 );
+
+               pnt_copy( pnt_tmp, dir_2 );
+               pnt_copy( dir_2, dir_3 );
+               pnt_copy( dir_3, pnt_tmp );
+           }
+       }
+
+       gdiam_point  get_dir( int  ind ) {
+           if  ( ind == 0 )
+               return  dir_1;
+           if  ( ind == 1 )
+               return  dir_2;
+           if  ( ind == 2 )
+               return  dir_3;
+
+           assert( false );
+
+           return  NULL;
+       }
+
+       void  combine( gdiam_point  out,
+               double  a_coef, double  b_coef,
+               double  c_coef ) {
+           for  ( int  ind = 0; ind < GDIAM_DIM; ind++ )
+               out[ ind ] = a_coef * dir_1[ ind ]
+                   + b_coef * dir_2[ ind ]
+                   + c_coef * dir_3[ ind ];
+       }
+
+       void  get_vertex( double sel1, double sel2, double sel3, double *p_x, 
double *p_y, double *p_z ) {
+           gdiam_real  coef1, coef2, coef3;
+           gdiam_point_t  pnt;
+
+           coef1 = low_1 + sel1 * ( high_1 - low_1 );
+           coef2 = low_2 + sel2 * ( high_2 - low_2 );
+           coef3 = low_3 + sel3 * ( high_3 - low_3 );
+
+           pnt_zero( pnt );
+           pnt_scale_and_add( pnt, coef1, dir_1 );
+           pnt_scale_and_add( pnt, coef2, dir_2 );
+           pnt_scale_and_add( pnt, coef3, dir_3 );
+
+           (*p_x) = pnt[0];
+           (*p_y) = pnt[1];
+           (*p_z) = pnt[2];
+
+       }
+
+
+       void  dump_vertex( double  sel1, double  sel2, double  sel3 ) const {
+           gdiam_real  coef1, coef2, coef3;
+
+           //printf( "selection: (%g, %g, %g)\n", sel1, sel2, sel3 );
+           coef1 = low_1 + sel1 * ( high_1 - low_1 );
+           coef2 = low_2 + sel2 * ( high_2 - low_2 );
+           coef3 = low_3 + sel3 * ( high_3 - low_3 );
+
+           //printf( "coeficients: (%g, %g,  %g)\n",
+           //        coef1, coef2, coef3 );
+
+           gdiam_point_t  pnt;
+           pnt_zero( pnt );
+
+           //printf( "starting...\n" );
+           //pnt_dump( pnt );
+           pnt_scale_and_add( pnt, coef1, dir_1 );
+           //pnt_dump( pnt );
+           pnt_scale_and_add( pnt, coef2, dir_2 );
+           //pnt_dump( pnt );
+           pnt_scale_and_add( pnt, coef3, dir_3 );
+           //pnt_dump( pnt );
+
+           pnt_dump( pnt );
+       }
+
+       void  dump() const {
+           printf( "-----------------------------------------------\n" );
+           dump_vertex( 0, 0, 0 );
+           dump_vertex( 0, 0, 1 );
+           dump_vertex( 0, 1, 0 );
+           dump_vertex( 0, 1, 1 );
+           dump_vertex( 1, 0, 0 );
+           dump_vertex( 1, 0, 1 );
+           dump_vertex( 1, 1, 0 );
+           dump_vertex( 1, 1, 1 );
+           printf( "volume: %g\n", volume() );
+           printf( "Directions:\n" );
+           pnt_dump( dir_1 );
+           pnt_dump( dir_2 );
+           pnt_dump( dir_3 );
+           printf( "prods: %g, %g, %g\n",
+                   pnt_dot_prod( dir_1, dir_2 ),
+                   pnt_dot_prod( dir_1, dir_3 ),
+                   pnt_dot_prod( dir_2, dir_3 ) );
+
+           printf( "--------------------------------------------------\n" );
+           //printf( "range_1: %g... %g\n", low_1, high_1 );
+           //printf( "range_2: %g... %g\n", low_2, high_2 );
+           //printf( "range_3: %g... %g\n", low_3, high_3 );
+           //printf( "prd: %g\n", pnt_dot_prod( dir_1, dir_2 ) );
+           //printf( "prd: %g\n", pnt_dot_prod( dir_2, dir_3 ) );
+           //printf( "prd: %g\n", pnt_dot_prod( dir_1, dir_3 ) );
+       }
+
+
+       void  init( const GBBox  & bb ) {
+           pnt_init( dir_1, 1, 0, 0 );
+           pnt_init( dir_2, 0, 1, 0 );
+           pnt_init( dir_3, 0, 0, 1 );
+
+           low_1 = bb.min_coord( 0 );
+           high_1 = bb.max_coord( 0 );
+
+           low_2 = bb.min_coord( 1 );
+           high_2 = bb.max_coord( 1 );
+
+           low_3 = bb.min_coord( 2 );
+           high_3 = bb.max_coord( 2 );
+           f_init = true;
+       }
+
+       void  init( const gdiam_point  _dir_1,
+               const gdiam_point  _dir_2,
+               const gdiam_point  _dir_3 ) {
+           memset( this, 0, sizeof( gdiam_bbox ) );
+
+           pnt_copy( dir_1, _dir_1 );
+           pnt_copy( dir_2, _dir_2 );
+           pnt_copy( dir_3, _dir_3 );
+           pnt_normalize( dir_1 );
+           pnt_normalize( dir_2 );
+           pnt_normalize( dir_3 );
+
+           if  ( ( ! (fabs( pnt_dot_prod( dir_1, dir_2 ) ) < 1e-6 ) )
+                   ||  ( ! (fabs( pnt_dot_prod( dir_1, dir_3 ) ) < 1e-6 ) )
+                   ||  ( ! (fabs( pnt_dot_prod( dir_2, dir_3 ) ) < 1e-6 ) ) ) {
+               printf( "should be all close to zero: %g, %g, %g\n",
+                       pnt_dot_prod( dir_1, dir_2 ),
+                       pnt_dot_prod( dir_1, dir_3 ),
+                       pnt_dot_prod( dir_2, dir_3 ) );
+               pnt_dump( _dir_1 );
+               pnt_dump( _dir_2 );
+               pnt_dump( _dir_3 );
+               fflush( stdout );
+               fflush( stderr );
+               assert( fabs( pnt_dot_prod( dir_1, dir_2 ) ) < 1e-6 );
+               assert( fabs( pnt_dot_prod( dir_1, dir_3 ) ) < 1e-6 );
+               assert( fabs( pnt_dot_prod( dir_2, dir_3 ) ) < 1e-6 );
+           }
+
+           // The following reduce the error by slightly improve the

@@ Diff output truncated at 100000 characters. @@
This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.



_______________________________________________
BRL-CAD Source Commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/brlcad-commits

Reply via email to