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