1 
2 /****************************************************************************
3 **
4 ** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
5 ** $Id: //main/2019/qhull/src/libqhullcpp/QhullQh.cpp#7 $$Change: 3009 $
6 ** $DateTime: 2020/07/30 19:25:22 $$Author: bbarber $
7 **
8 ****************************************************************************/
9 
10 #//! QhullQh -- Qhull's global data structure, qhT, as a C++ class
11 
12 
13 #include "libqhullcpp/QhullQh.h"
14 
15 #include "libqhullcpp/QhullError.h"
16 #include "libqhullcpp/QhullStat.h"
17 
18 #include <sstream>
19 #include <iostream>
20 
21 #include <stdarg.h>
22 
23 using std::cerr;
24 using std::string;
25 using std::vector;
26 using std::ostream;
27 
28 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
29 #pragma warning( disable : 4611)  // interaction between '_setjmp' and C++ object destruction is non-portable
30 #pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
31 #endif
32 
33 namespace orgQhull {
34 
35 #//!\name Global variables
36 const double QhullQh::
37 default_factor_epsilon= 1.0;
38 
39 #//!\name Constructor, destructor, etc.
40 
41 //! Derived from qh_new_qhull[user.c]
42 QhullQh::
QhullQh()43 QhullQh()
44 : qhull_status(qh_ERRnone)
45 , qhull_message()
46 , error_stream(0)
47 , output_stream(0)
48 , factor_epsilon(QhullQh::default_factor_epsilon)
49 , use_output_stream(false)
50 {
51     // NOerrors: TRY_QHULL_ not needed since these routines do not call qh_errexit()
52     qh_meminit(this, NULL);
53     qh_initstatistics(this);
54     qh_initqhull_start2(this, NULL, NULL, qh_FILEstderr);  // Initialize qhT
55     this->ISqhullQh= True;
56 }//QhullQh
57 
58 QhullQh::
~QhullQh()59 ~QhullQh()
60 {
61     checkAndFreeQhullMemory();
62 }//~QhullQh
63 
64 #//!\name Methods
65 
66 //! Check memory for internal consistency
67 //! Free global memory used by qh_initbuild and qh_buildhull
68 //! Zero the qhT data structure, except for memory (qhmemT) and statistics (qhstatT)
69 //! Check and free short memory (e.g., facetT)
70 //! Zero the qhmemT data structure
71 void QhullQh::
checkAndFreeQhullMemory()72 checkAndFreeQhullMemory()
73 {
74 #ifdef qh_NOmem
75     qh_freeqhull(this, qh_ALL);
76 #else
77     qh_memcheck(this);
78     qh_freeqhull(this, !qh_ALL);
79     countT curlong;
80     countT totlong;
81     qh_memfreeshort(this, &curlong, &totlong);
82     if(curlong || totlong)
83         throw QhullError(10026, "Qhull error: qhull did not free %d bytes of long memory (%d pieces).", totlong, curlong);
84 #endif
85 }//checkAndFreeQhullMemory
86 
87 #//!\name Messaging
88 
89 void QhullQh::
appendQhullMessage(const string & s)90 appendQhullMessage(const string &s)
91 {
92     if(output_stream && use_output_stream && this->USEstdout){
93         *output_stream << s;
94     }else if(error_stream){
95         *error_stream << s;
96     }else{
97         qhull_message += s;
98     }
99 }//appendQhullMessage
100 
101 //! clearQhullMessage does not throw errors (~Qhull)
102 void QhullQh::
clearQhullMessage()103 clearQhullMessage()
104 {
105     qhull_status= qh_ERRnone;
106     qhull_message.clear();
107     RoadError::clearGlobalLog();
108 }//clearQhullMessage
109 
110 //! hasQhullMessage does not throw errors (~Qhull)
111 bool QhullQh::
hasQhullMessage() const112 hasQhullMessage() const
113 {
114     return (!qhull_message.empty() || qhull_status!=qh_ERRnone);
115     // QH11006 FIX: inconsistent usage with Rbox.  hasRboxMessage just tests rbox_status.  No appendRboxMessage()
116 }
117 
118 void QhullQh::
maybeThrowQhullMessage(int exitCode)119 maybeThrowQhullMessage(int exitCode)
120 {
121     if(!NOerrexit){
122         if(qhull_message.size()>0){
123             qhull_message.append("\n");
124         }
125         if(exitCode || qhull_status==qh_ERRnone){
126             qhull_status= 10073;
127         }else{
128             qhull_message.append("QH10073: ");
129         }
130         qhull_message.append("Cannot call maybeThrowQhullMessage() from QH_TRY_().  Or missing 'qh->NOerrexit=true;' after QH_TRY_(){...}.");
131     }
132     if(qhull_status==qh_ERRnone){
133         qhull_status= exitCode;
134     }
135     if(qhull_status!=qh_ERRnone){
136         QhullError e(qhull_status, qhull_message);
137         clearQhullMessage();
138         throw e; // QH11007 FIX: copy constructor is expensive if logging
139     }
140 }//maybeThrowQhullMessage
141 
142 void QhullQh::
maybeThrowQhullMessage(int exitCode,int noThrow)143 maybeThrowQhullMessage(int exitCode, int noThrow)  throw()
144 {
145     QHULL_UNUSED(noThrow);
146 
147     if(qhull_status==qh_ERRnone){
148         qhull_status= exitCode;
149     }
150     if(qhull_status!=qh_ERRnone){
151         QhullError e(qhull_status, qhull_message);
152         e.logErrorLastResort();
153     }
154 }//maybeThrowQhullMessage
155 
156 //! qhullMessage does not throw errors (~Qhull)
157 std::string QhullQh::
qhullMessage() const158 qhullMessage() const
159 {
160     if(qhull_message.empty() && qhull_status!=qh_ERRnone){
161         return "qhull: no message for error.  Check cerr or error stream\n";
162     }else{
163         return qhull_message;
164     }
165 }//qhullMessage
166 
167 int QhullQh::
qhullStatus() const168 qhullStatus() const
169 {
170     return qhull_status;
171 }//qhullStatus
172 
173 void QhullQh::
setErrorStream(ostream * os)174 setErrorStream(ostream *os)
175 {
176     error_stream= os;
177 }//setErrorStream
178 
179 //! Updates use_output_stream
180 void QhullQh::
setOutputStream(ostream * os)181 setOutputStream(ostream *os)
182 {
183     output_stream= os;
184     use_output_stream= (os!=0);
185 }//setOutputStream
186 
187 }//namespace orgQhull
188 
189