Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Analysis.AlgorithmBehavior/qhull-2012.1/src/libqhullcpp/UsingLibQhull.cpp @ 10207

Last change on this file since 10207 was 10207, checked in by ascheibe, 11 years ago

#1886 added a unit test for volume calculation and the qhull library

File size: 11.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (c) 2008-2012 C.B. Barber. All rights reserved.
4** $Id: //main/2011/qhull/src/libqhullcpp/UsingLibQhull.cpp#4 $$Change: 1464 $
5** $DateTime: 2012/01/25 22:58:41 $$Author: bbarber $
6**
7****************************************************************************/
8
9#//! UsingLibQhull -- Set up qhull C code from C++
10
11#include "Qhull.h"
12#include "UsingLibQhull.h"
13#include "QhullError.h"
14#include "QhullQh.h"
15
16#ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
17#endif
18
19namespace orgQhull {
20
21#//Class objects
22
23const double UsingLibQhull::
24DEFAULTdistanceEpsilon= 1e-15*FACTORepsilon; //! ~DISTround*FACTORepsilon for unit cube
25
26const double UsingLibQhull::
27DEFAULTangleEpsilon= 1e-15*FACTORepsilon; //! ~ANGLEround*FACTORepsilon for unit cube
28
29    //! Global pointer to Qhull for qh_fprintf callback and QhullError
30Qhull *
31s_qhull_output= 0;
32
33double UsingLibQhull::
34s_angle_epsilon= 0;
35
36double UsingLibQhull::
37s_distance_epsilon= 0;
38
39//! For QhullPoint.id() w/o qhRunId.  Initialized by Qhull
40const coordT *UsingLibQhull::
41s_points_begin= 0;
42const coordT *UsingLibQhull::
43s_points_end= 0;
44int UsingLibQhull::
45s_points_dimension= 0;
46
47int UsingLibQhull::
48s_vertex_dimension= 0;  // FIXUP QH11023: s_vertex_dimension is required if dimension>15.  Cannot store in QhullVertex
49
50bool UsingLibQhull::
51s_has_points= false;
52
53bool UsingLibQhull::
54s_has_angle_epsilon= false;
55
56bool UsingLibQhull::
57s_has_vertex_dimension= false;
58
59bool UsingLibQhull::
60s_has_distance_epsilon= false;
61
62bool UsingLibQhull::
63s_using_libqhull= false;
64
65#//Constructors
66
67//! Grabs global state (qh_qh, qh_qhstat, qhmem.tempstack)
68//! Follow immediately with setjmp(qh errexit), otherwise errors in libqhull are not caught properly
69//! See qh_restore_qhull [global.c]
70UsingLibQhull::
71UsingLibQhull(Qhull *q)
72: my_qhull(q)
73, qh_exitcode(0)
74{
75    checkUsingLibQhull();
76    QhullQh *qhullqh= q->qhullQh();
77    if(!qhullqh){
78        throw QhullError(10014, "Qhull internal error: Qhull.qhullQh() not defined. initializeQhull() not called.");
79    }
80    if(qhullqh->run_id != q->qhull_run_id){
81        throw QhullError(10015, "Qhull error: QhullQh.runId %d != Qhull.runId %d.  Overwritten?", qhullqh->run_id, q->qhull_run_id);
82    }
83    // qh.old_qhstat is zero at initialization
84    // qh.old_tempstack is zero when empty
85    // QhullQh() and UsingLibQhull() are the same
86#if qh_QHpointer
87    if(qh_qh){
88        qh old_qhstat= qh_qhstat;
89        qh old_tempstack= qhmem.tempstack;
90    }
91    qh_qh= qhullqh;
92    qh_qhstat= qhullqh->old_qhstat;
93    qhmem.tempstack= qhullqh->old_tempstack;
94    qhullqh->old_qhstat= 0;
95    qhullqh->old_tempstack= 0;
96#else
97    #error FIXUP QH11024 static qh_qh not tested.  Delete the line to try.
98    if(qhullqh!=&qh_qh){
99        throw QhullError(10040, "Qhull internal error: Qhull.qhullQh() is not qh_qh (%x, static).  Overwrite?", 0,0,0.0, &qh_qh);
100    }
101#endif
102    s_qhull_output= q;      // set s_qhull_output for qh_fprintf()
103    qh NOerrexit= False;   // assumes setjmp called next
104}//UsingLibQhull qhull
105
106//! Same as UsingLibQhull but does not throw exceptions
107//! !defined() on failure.  For use in destructors
108UsingLibQhull::
109UsingLibQhull(Qhull *q, int noThrow)
110: my_qhull(0)  // Fail by default
111, qh_exitcode(0)
112{
113    QHULL_UNUSED(noThrow);
114
115    QhullQh *qhullqh= q->qhullQh();
116    if(s_using_libqhull){
117        QhullError e(10050, "Qhull error: UsingLibQhull already in use");
118        e.logError();
119    }else if(!qhullqh || qhullqh->run_id != q->qhull_run_id){
120        QhullError e(10051, "Qhull error: Qhull.qhullQh (%x) undefined or QhullQh.runId %d != Qhull.runId %d.  Overwritten?", (qhullqh ? qhullqh->run_id : -1), q->qhull_run_id, 0.0, qhullqh);
121        e.logError();
122    }else{
123        // qh.old_qhstat is zero at initialization
124        // qh.old_tempstack is zero when empty
125        // QhullQh() and UsingLibQhull() are the same
126#if qh_QHpointer
127        if(qh_qh){
128            qh old_qhstat= qh_qhstat;
129            qh old_tempstack= qhmem.tempstack;
130        }
131        qh_qh= qhullqh;
132        qh_qhstat= qhullqh->old_qhstat;
133        qhmem.tempstack= qhullqh->old_tempstack;
134        qhullqh->old_qhstat= 0;
135        qhullqh->old_tempstack= 0;
136#endif
137        my_qhull= q;
138        s_qhull_output= q;          // set s_qhull_output for qh_fprintf()
139        qh NOerrexit= False;   // assumes setjmp called next
140    }
141}//UsingLibQhull qhull noThrow
142
143//! Reuses current global state (qh_qh) from prior UsingQhull
144//! Errors if runId is not the same
145UsingLibQhull::
146UsingLibQhull(int qhRunId)
147: my_qhull(0)
148, qh_exitcode(0)
149{
150    checkUsingLibQhull();
151#if qh_QHpointer
152    if(!qh_qh || !qh_qhstat){
153        throw QhullError(10024, "Qhull error: UsingLibQhull is not active (qh_qh %x or qh_qhstat is not defined)", 0,0,0.0, qh_qh);
154    }
155#endif
156    if(qh run_id!=qhRunId){
157        throw QhullError(10036, "Qhull error: qhRunId %d != qh_qh.runId %d.  Is another Qhull active?", qhRunId, qh run_id);
158    }
159    if(!s_qhull_output){
160        throw QhullError(10037, "Qhull error: UsingLibQhull not active(s_qhull_output undefined).  Invoke UsingLibQhull before this call");
161    }
162    if(s_qhull_output->qhull_run_id!=qhRunId){
163        throw QhullError(10046, "Qhull error: qhRunId %d != s_qhull_output.runId %d.  Is another Qhull active", qhRunId, s_qhull_output->qhull_run_id);
164    }
165    my_qhull= s_qhull_output;
166    qh NOerrexit= False;   // assumes setjmp called next
167}//UsingLibQhull runId
168
169//Leaves libqhull active for runId access
170UsingLibQhull::
171~UsingLibQhull()
172{
173    QhullError e= checkRunId();
174    if(e.isDefined()){
175        e.logError();
176    }else{
177#if qh_QHpointer
178        if(qh_qh){
179            qh NOerrexit= true;
180        }
181#else
182        qh NOerrexit= true;
183#endif
184    }
185    s_using_libqhull= false;
186}//~UsingLibQhull
187
188#//Class methods
189
190void UsingLibQhull::
191checkQhullMemoryEmpty()
192{
193    int curlong, totlong, curshort, totshort, maxlong, totbuffer;
194    // qh_memtotal does not error
195    qh_memtotal(&curlong, &totlong, &curshort, &totshort, &maxlong, &totbuffer);
196    if (curlong || totlong){
197        throw QhullError(10026, "Qhull error: qhull did not free %d bytes of long memory (%d pieces).", totlong, curlong);
198    }
199    if (curshort || totshort){
200        throw QhullError(10035, "Qhull error: qhull did not free %d bytes of short memory (%d pieces).", totshort, curshort);
201    }
202}//checkQhullMemoryEmpty
203
204double UsingLibQhull::
205currentAngleEpsilon()
206{
207    if(s_qhull_output && s_qhull_output->initialized()){
208        return s_qhull_output->qhullQh()->ANGLEround*FACTORepsilon;
209    }else if(s_has_angle_epsilon){
210        return s_angle_epsilon;
211    }
212    return UsingLibQhull::DEFAULTangleEpsilon;
213}//currentAngleEpsilon
214
215double UsingLibQhull::
216currentDistanceEpsilon()
217{
218    if(s_qhull_output && s_qhull_output->initialized()){
219        return s_qhull_output->qhullQh()->DISTround*FACTORepsilon;
220    }else if(s_has_distance_epsilon){
221        return s_distance_epsilon;
222    }
223    return UsingLibQhull::DEFAULTdistanceEpsilon;
224}//currentDistanceEpsilon
225
226const coordT *UsingLibQhull::
227currentPoints(int *dimension, const coordT **pointsEnd)
228{
229    if(s_qhull_output && s_qhull_output->initialized()){
230        *dimension= qh hull_dim;
231        *pointsEnd= qh first_point+qh num_points*qh hull_dim;
232        return qh first_point;
233    }else if(s_has_points){
234        *dimension= s_points_dimension;
235        *pointsEnd= s_points_end;
236        return s_points_begin;
237    }
238    throw QhullError(10059, "Qhull error: missing definition for currentPoints().  Need currentQhull() or setGlobalDistanceEpsilon()");
239}//currentPoints
240
241Qhull &UsingLibQhull::
242currentQhull()
243{
244    if(!s_qhull_output){
245        throw QhullError(10055, "Qhull error: currentQhull not defined.  Run qhull first.");
246    }
247    return *s_qhull_output;
248}//currentQhull
249
250// for QhullVertex::dimension() when >= 16
251int UsingLibQhull::
252currentVertexDimension()
253{
254    if(s_qhull_output && s_qhull_output->initialized()){
255        return s_qhull_output->dimension();
256    }else if(s_has_vertex_dimension){
257        return s_vertex_dimension;
258    }
259    throw QhullError(10057, "Qhull error: missing definition for currentVertexDimension().  Need currentQhull() or setGlobalVertexDimension()");
260}//currentVertexDimension
261
262const coordT *UsingLibQhull::
263globalPoints(int *dimension, const coordT **pointsEnd)
264{
265    if(s_has_points){
266        *dimension= s_points_dimension;
267        *pointsEnd= s_points_end;
268        return s_points_begin;
269    }else{
270        return currentPoints(dimension, pointsEnd);
271    }
272}//globalPoints
273
274bool UsingLibQhull::
275hasPoints()
276{
277    return s_has_points || (s_qhull_output && s_qhull_output->initialized());
278}
279
280bool UsingLibQhull::
281hasVertexDimension()
282{
283    return s_has_vertex_dimension || (s_qhull_output && s_qhull_output->initialized());
284}
285
286void UsingLibQhull::
287setGlobals()
288{
289    if(s_qhull_output && s_qhull_output->initialized()){
290        QhullQh *qqh= s_qhull_output->qhullQh();
291        s_angle_epsilon= qqh->ANGLEround*FACTORepsilon;
292        s_distance_epsilon= qqh->DISTround*FACTORepsilon;
293        s_points_begin= qqh->first_point;
294        s_points_dimension= qqh->hull_dim;
295        s_points_end= s_points_begin+qqh->num_points*s_points_dimension;
296        s_vertex_dimension= qqh->hull_dim;
297        s_has_angle_epsilon= true;
298        s_has_distance_epsilon= true;
299        s_has_points= true;
300        s_has_vertex_dimension= true;
301    }else{
302        throw QhullError(10058, "Qhull error: setGlobals can only be called for currentQhull().  Run qhull first.");
303    }
304 }//setGlobals
305
306void UsingLibQhull::
307unsetGlobals()
308{
309    s_has_angle_epsilon= false;
310    s_has_distance_epsilon= false;
311    s_has_points= false;
312    s_has_vertex_dimension= false;
313}//unsetGlobals
314
315#// Methods
316
317void UsingLibQhull::
318maybeThrowQhullMessage(int exitCode) const
319{
320    my_qhull->maybeThrowQhullMessage(exitCode);
321    QhullError e= checkRunId(); // Check for qhRunId after libqhull returns. For convenience, ought to be at end of libqhull try block
322    if(e.isDefined()){
323        throw e;
324    }
325}//maybeThrowQhullMessage
326
327void UsingLibQhull::
328maybeThrowQhullMessage(int exitCode, int noThrow) const
329{
330    my_qhull->maybeThrowQhullMessage(exitCode, noThrow);
331    QhullError e= checkRunId(); // Check for qhRunId after libqhull returns. For convenience, ought to be at end of libqhull try block
332    if(e.isDefined()){
333        e.logError();
334    }
335}//maybeThrowQhullMessage
336
337#//Helpers
338
339//! Return QhullError for maybeThrowFromDestructor()
340QhullError UsingLibQhull::
341checkRunId() const
342{
343    // Predeclaring QhullError results in four copy constructors, none used here
344#if qh_QHpointer
345    if(qh_qh){ // 0 if ~Qhull
346        if(my_qhull->qhull_run_id!=qh run_id){
347            return QhullError(10047, "Qhull internal error: Global state (qh_qh, run_id %d) changed.  Should be runId %d.  Another thread?", qh run_id, my_qhull->qhull_run_id);
348        }
349    }
350#else
351    if(qh run_id!=0 && my_qhull->qhull_run_id!=qh run_id){
352        return QhullError(10048, "Qhull internal error: Global state (qh_qh, run_id %d) changed.  Should be runId %d.  Another thread?", qh run_id, my_qhull->qhull_run_id);
353    }
354#endif
355    return QhullError();
356}//checkRunId
357
358//! Can not embed UsingLibQhull.  Otherwise allocated a C++ object missed by qh_errexit
359void UsingLibQhull::
360checkUsingLibQhull() const
361{
362    if(s_using_libqhull){
363        if(s_qhull_output){
364            throw QhullError(10049, "Qhull error: UsingLibQhull already in use by QhullQh.runId %d", s_qhull_output->qhull_run_id);
365        }else{
366            throw QhullError(10050, "Qhull error: UsingLibQhull already in use.  No s_qhull_output");
367        }
368    }
369    s_using_libqhull= true;
370}//checkUsingLibQhull
371
372}//namespace orgQhull
373
Note: See TracBrowser for help on using the repository browser.