ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/trunk/src/QuickHull/geom2.c
Revision: 1138
Committed: Tue May 29 22:51:00 2007 UTC (17 years, 11 months ago) by chuckv
Content type: text/plain
File size: 66767 byte(s)
Log Message:
Addded QuickHull to cvs.

File Contents

# User Rev Content
1 chuckv 1138 /*<html><pre> -<a href="qh-geom.htm"
2     >-------------------------------</a><a name="TOP">-</a>
3    
4    
5     geom2.c
6     infrequently used geometric routines of qhull
7    
8     see qh-geom.htm and geom.h
9    
10     copyright (c) 1993-2003 The Geometry Center
11    
12     frequently used code goes into geom.c
13     */
14    
15     #include "QuickHull/qhull_a.h"
16    
17     /*================== functions in alphabetic order ============*/
18    
19     /*-<a href="qh-geom.htm#TOC"
20     >-------------------------------</a><a name="copypoints">-</a>
21    
22     qh_copypoints( points, numpoints, dimension)
23     return malloc'd copy of points
24     */
25     coordT *qh_copypoints (coordT *points, int numpoints, int dimension) {
26     int size;
27     coordT *newpoints;
28    
29     size= numpoints * dimension * sizeof(coordT);
30     if (!(newpoints=(coordT*)malloc(size))) {
31     fprintf(qh ferr, "qhull error: insufficient memory to copy %d points\n",
32     numpoints);
33     qh_errexit(qh_ERRmem, NULL, NULL);
34     }
35     memcpy ((char *)newpoints, (char *)points, size);
36     return newpoints;
37     } /* copypoints */
38    
39     /*-<a href="qh-geom.htm#TOC"
40     >-------------------------------</a><a name="crossproduct">-</a>
41    
42     qh_crossproduct( dim, vecA, vecB, vecC )
43     crossproduct of 2 dim vectors
44     C= A x B
45    
46     notes:
47     from Glasner, Graphics Gems I, p. 639
48     only defined for dim==3
49     */
50     void qh_crossproduct (int dim, realT vecA[3], realT vecB[3], realT vecC[3]){
51    
52     if (dim == 3) {
53     vecC[0]= det2_(vecA[1], vecA[2], vecB[1], vecB[2]);
54     vecC[1]= - det2_(vecA[0], vecA[2], vecB[0], vecB[2]);
55     vecC[2]= det2_(vecA[0], vecA[1], vecB[0], vecB[1]);
56     }
57     } /* vcross */
58    
59     /*-<a href="qh-geom.htm#TOC"
60     >-------------------------------</a><a name="determinant">-</a>
61    
62     qh_determinant( rows, dim, nearzero )
63     compute signed determinant of a square matrix
64     uses qh.NEARzero to test for degenerate matrices
65    
66     returns:
67     determinant
68     overwrites rows and the matrix
69     if dim == 2 or 3
70     nearzero iff determinant < qh NEARzero[dim-1]
71     (not quite correct, not critical)
72     if dim >= 4
73     nearzero iff diagonal[k] < qh NEARzero[k]
74     */
75     realT qh_determinant (realT **rows, int dim, boolT *nearzero) {
76     realT det=0;
77     int i;
78     boolT sign= False;
79    
80     *nearzero= False;
81     if (dim < 2) {
82     fprintf (qh ferr, "qhull internal error (qh_determinate): only implemented for dimension >= 2\n");
83     qh_errexit (qh_ERRqhull, NULL, NULL);
84     }else if (dim == 2) {
85     det= det2_(rows[0][0], rows[0][1], rows[1][0], rows[1][1]);
86     if (fabs_(det) < qh NEARzero[1]) /* not really correct, what should this be? */
87     *nearzero= True;
88     }else if (dim == 3) {
89     det= det3_(rows[0][0], rows[0][1], rows[0][2], rows[1][0], rows[1][1], rows[1][2], rows[2][0], rows[2][1], rows[2][2]);
90     if (fabs_(det) < qh NEARzero[2]) /* not really correct, what should this be? */
91     *nearzero= True;
92     }else {
93     qh_gausselim(rows, dim, dim, &sign, nearzero); /* if nearzero, diagonal still ok*/
94     det= 1.0;
95     for (i= dim; i--; )
96     det *= (rows[i])[i];
97     if (sign)
98     det= -det;
99     }
100     return det;
101     } /* determinant */
102    
103     /*-<a href="qh-geom.htm#TOC"
104     >-------------------------------</a><a name="detjoggle">-</a>
105    
106     qh_detjoggle( points, numpoints, dimension )
107     determine default max joggle for point array
108     as qh_distround * qh_JOGGLEdefault
109    
110     returns:
111     initial value for JOGGLEmax from points and REALepsilon
112    
113     notes:
114     computes DISTround since qh_maxmin not called yet
115     if qh SCALElast, last dimension will be scaled later to MAXwidth
116    
117     loop duplicated from qh_maxmin
118     */
119     realT qh_detjoggle (pointT *points, int numpoints, int dimension) {
120     realT abscoord, distround, joggle, maxcoord, mincoord;
121     pointT *point, *pointtemp;
122     realT maxabs= -REALmax;
123     realT sumabs= 0;
124     realT maxwidth= 0;
125     int k;
126    
127     for (k= 0; k < dimension; k++) {
128     if (qh SCALElast && k == dimension-1)
129     abscoord= maxwidth;
130     else if (qh DELAUNAY && k == dimension-1) /* will qh_setdelaunay() */
131     abscoord= 2 * maxabs * maxabs; /* may be low by qh hull_dim/2 */
132     else {
133     maxcoord= -REALmax;
134     mincoord= REALmax;
135     FORALLpoint_(points, numpoints) {
136     maximize_(maxcoord, point[k]);
137     minimize_(mincoord, point[k]);
138     }
139     maximize_(maxwidth, maxcoord-mincoord);
140     abscoord= fmax_(maxcoord, -mincoord);
141     }
142     sumabs += abscoord;
143     maximize_(maxabs, abscoord);
144     } /* for k */
145     distround= qh_distround (qh hull_dim, maxabs, sumabs);
146     joggle= distround * qh_JOGGLEdefault;
147     maximize_(joggle, REALepsilon * qh_JOGGLEdefault);
148     trace2((qh ferr, "qh_detjoggle: joggle=%2.2g maxwidth=%2.2g\n", joggle, maxwidth));
149     return joggle;
150     } /* detjoggle */
151    
152     /*-<a href="qh-geom.htm#TOC"
153     >-------------------------------</a><a name="detroundoff">-</a>
154    
155     qh_detroundoff()
156     determine maximum roundoff errors from
157     REALepsilon, REALmax, REALmin, qh.hull_dim, qh.MAXabs_coord,
158     qh.MAXsumcoord, qh.MAXwidth, qh.MINdenom_1
159    
160     accounts for qh.SETroundoff, qh.RANDOMdist, qh MERGEexact
161     qh.premerge_cos, qh.postmerge_cos, qh.premerge_centrum,
162     qh.postmerge_centrum, qh.MINoutside,
163     qh_RATIOnearinside, qh_COPLANARratio, qh_WIDEcoplanar
164    
165     returns:
166     sets qh.DISTround, etc. (see below)
167     appends precision constants to qh.qhull_options
168    
169     see:
170     qh_maxmin() for qh.NEARzero
171    
172     design:
173     determine qh.DISTround for distance computations
174     determine minimum denominators for qh_divzero
175     determine qh.ANGLEround for angle computations
176     adjust qh.premerge_cos,... for roundoff error
177     determine qh.ONEmerge for maximum error due to a single merge
178     determine qh.NEARinside, qh.MAXcoplanar, qh.MINvisible,
179     qh.MINoutside, qh.WIDEfacet
180     initialize qh.max_vertex and qh.minvertex
181     */
182     void qh_detroundoff (void) {
183    
184     qh_option ("_max-width", NULL, &qh MAXwidth);
185     if (!qh SETroundoff) {
186     qh DISTround= qh_distround (qh hull_dim, qh MAXabs_coord, qh MAXsumcoord);
187     if (qh RANDOMdist)
188     qh DISTround += qh RANDOMfactor * qh MAXabs_coord;
189     qh_option ("Error-roundoff", NULL, &qh DISTround);
190     }
191     qh MINdenom= qh MINdenom_1 * qh MAXabs_coord;
192     qh MINdenom_1_2= sqrt (qh MINdenom_1 * qh hull_dim) ; /* if will be normalized */
193     qh MINdenom_2= qh MINdenom_1_2 * qh MAXabs_coord;
194     /* for inner product */
195     qh ANGLEround= 1.01 * qh hull_dim * REALepsilon;
196     if (qh RANDOMdist)
197     qh ANGLEround += qh RANDOMfactor;
198     if (qh premerge_cos < REALmax/2) {
199     qh premerge_cos -= qh ANGLEround;
200     if (qh RANDOMdist)
201     qh_option ("Angle-premerge-with-random", NULL, &qh premerge_cos);
202     }
203     if (qh postmerge_cos < REALmax/2) {
204     qh postmerge_cos -= qh ANGLEround;
205     if (qh RANDOMdist)
206     qh_option ("Angle-postmerge-with-random", NULL, &qh postmerge_cos);
207     }
208     qh premerge_centrum += 2 * qh DISTround; /*2 for centrum and distplane()*/
209     qh postmerge_centrum += 2 * qh DISTround;
210     if (qh RANDOMdist && (qh MERGEexact || qh PREmerge))
211     qh_option ("Centrum-premerge-with-random", NULL, &qh premerge_centrum);
212     if (qh RANDOMdist && qh POSTmerge)
213     qh_option ("Centrum-postmerge-with-random", NULL, &qh postmerge_centrum);
214     { /* compute ONEmerge, max vertex offset for merging simplicial facets */
215     realT maxangle= 1.0, maxrho;
216    
217     minimize_(maxangle, qh premerge_cos);
218     minimize_(maxangle, qh postmerge_cos);
219     /* max diameter * sin theta + DISTround for vertex to its hyperplane */
220     qh ONEmerge= sqrt (qh hull_dim) * qh MAXwidth *
221     sqrt (1.0 - maxangle * maxangle) + qh DISTround;
222     maxrho= qh hull_dim * qh premerge_centrum + qh DISTround;
223     maximize_(qh ONEmerge, maxrho);
224     maxrho= qh hull_dim * qh postmerge_centrum + qh DISTround;
225     maximize_(qh ONEmerge, maxrho);
226     if (qh MERGING)
227     qh_option ("_one-merge", NULL, &qh ONEmerge);
228     }
229     qh NEARinside= qh ONEmerge * qh_RATIOnearinside; /* only used if qh KEEPnearinside */
230     if (qh JOGGLEmax < REALmax/2 && (qh KEEPcoplanar || qh KEEPinside)) {
231     realT maxdist; /* adjust qh.NEARinside for joggle */
232     qh KEEPnearinside= True;
233     maxdist= sqrt (qh hull_dim) * qh JOGGLEmax + qh DISTround;
234     maxdist= 2*maxdist; /* vertex and coplanar point can joggle in opposite directions */
235     maximize_(qh NEARinside, maxdist); /* must agree with qh_nearcoplanar() */
236     }
237     if (qh KEEPnearinside)
238     qh_option ("_near-inside", NULL, &qh NEARinside);
239     if (qh JOGGLEmax < qh DISTround) {
240     fprintf (qh ferr, "qhull error: the joggle for 'QJn', %.2g, is below roundoff for distance computations, %.2g\n",
241     qh JOGGLEmax, qh DISTround);
242     qh_errexit (qh_ERRinput, NULL, NULL);
243     }
244     if (qh MINvisible > REALmax/2) {
245     if (!qh MERGING)
246     qh MINvisible= qh DISTround;
247     else if (qh hull_dim <= 3)
248     qh MINvisible= qh premerge_centrum;
249     else
250     qh MINvisible= qh_COPLANARratio * qh premerge_centrum;
251     if (qh APPROXhull && qh MINvisible > qh MINoutside)
252     qh MINvisible= qh MINoutside;
253     qh_option ("Visible-distance", NULL, &qh MINvisible);
254     }
255     if (qh MAXcoplanar > REALmax/2) {
256     qh MAXcoplanar= qh MINvisible;
257     qh_option ("U-coplanar-distance", NULL, &qh MAXcoplanar);
258     }
259     if (!qh APPROXhull) { /* user may specify qh MINoutside */
260     qh MINoutside= 2 * qh MINvisible;
261     if (qh premerge_cos < REALmax/2)
262     maximize_(qh MINoutside, (1- qh premerge_cos) * qh MAXabs_coord);
263     qh_option ("Width-outside", NULL, &qh MINoutside);
264     }
265     qh WIDEfacet= qh MINoutside;
266     maximize_(qh WIDEfacet, qh_WIDEcoplanar * qh MAXcoplanar);
267     maximize_(qh WIDEfacet, qh_WIDEcoplanar * qh MINvisible);
268     qh_option ("_wide-facet", NULL, &qh WIDEfacet);
269     if (qh MINvisible > qh MINoutside + 3 * REALepsilon
270     && !qh BESToutside && !qh FORCEoutput)
271     fprintf (qh ferr, "qhull input warning: minimum visibility V%.2g is greater than \nminimum outside W%.2g. Flipped facets are likely.\n",
272     qh MINvisible, qh MINoutside);
273     qh max_vertex= qh DISTround;
274     qh min_vertex= -qh DISTround;
275     /* numeric constants reported in printsummary */
276     } /* detroundoff */
277    
278     /*-<a href="qh-geom.htm#TOC"
279     >-------------------------------</a><a name="detsimplex">-</a>
280    
281     qh_detsimplex( apex, points, dim, nearzero )
282     compute determinant of a simplex with point apex and base points
283    
284     returns:
285     signed determinant and nearzero from qh_determinant
286    
287     notes:
288     uses qh.gm_matrix/qh.gm_row (assumes they're big enough)
289    
290     design:
291     construct qm_matrix by subtracting apex from points
292     compute determinate
293     */
294     realT qh_detsimplex(pointT *apex, setT *points, int dim, boolT *nearzero) {
295     pointT *coorda, *coordp, *gmcoord, *point, **pointp;
296     coordT **rows;
297     int k, i=0;
298     realT det;
299    
300     zinc_(Zdetsimplex);
301     gmcoord= qh gm_matrix;
302     rows= qh gm_row;
303     FOREACHpoint_(points) {
304     if (i == dim)
305     break;
306     rows[i++]= gmcoord;
307     coordp= point;
308     coorda= apex;
309     for (k= dim; k--; )
310     *(gmcoord++)= *coordp++ - *coorda++;
311     }
312     if (i < dim) {
313     fprintf (qh ferr, "qhull internal error (qh_detsimplex): #points %d < dimension %d\n",
314     i, dim);
315     qh_errexit (qh_ERRqhull, NULL, NULL);
316     }
317     det= qh_determinant (rows, dim, nearzero);
318     trace2((qh ferr, "qh_detsimplex: det=%2.2g for point p%d, dim %d, nearzero? %d\n", det, qh_pointid(apex), dim, *nearzero));
319     return det;
320     } /* detsimplex */
321    
322     /*-<a href="qh-geom.htm#TOC"
323     >-------------------------------</a><a name="distnorm">-</a>
324    
325     qh_distnorm( dim, point, normal, offset )
326     return distance from point to hyperplane at normal/offset
327    
328     returns:
329     dist
330    
331     notes:
332     dist > 0 if point is outside of hyperplane
333    
334     see:
335     qh_distplane in geom.c
336     */
337     realT qh_distnorm (int dim, pointT *point, pointT *normal, realT *offsetp) {
338     coordT *normalp= normal, *coordp= point;
339     realT dist;
340     int k;
341    
342     dist= *offsetp;
343     for (k= dim; k--; )
344     dist += *(coordp++) * *(normalp++);
345     return dist;
346     } /* distnorm */
347    
348     /*-<a href="qh-geom.htm#TOC"
349     >-------------------------------</a><a name="distround">-</a>
350    
351     qh_distround ( dimension, maxabs, maxsumabs )
352     compute maximum round-off error for a distance computation
353     to a normalized hyperplane
354     maxabs is the maximum absolute value of a coordinate
355     maxsumabs is the maximum possible sum of absolute coordinate values
356    
357     returns:
358     max dist round for REALepsilon
359    
360     notes:
361     calculate roundoff error according to
362     Lemma 3.2-1 of Golub and van Loan "Matrix Computation"
363     please use sqrt(dim) since one vector is normalized
364     or use maxsumabs since one vector is < 1
365     */
366     realT qh_distround (int dimension, realT maxabs, realT maxsumabs) {
367     realT maxdistsum, maxround;
368    
369     maxdistsum= sqrt (dimension) * maxabs;
370     minimize_( maxdistsum, maxsumabs);
371     maxround= REALepsilon * (dimension * maxdistsum * 1.01 + maxabs);
372     /* adds maxabs for offset */
373     trace4((qh ferr, "qh_distround: %2.2g maxabs %2.2g maxsumabs %2.2g maxdistsum %2.2g\n", maxround, maxabs, maxsumabs, maxdistsum));
374     return maxround;
375     } /* distround */
376    
377     /*-<a href="qh-geom.htm#TOC"
378     >-------------------------------</a><a name="divzero">-</a>
379    
380     qh_divzero( numer, denom, mindenom1, zerodiv )
381     divide by a number that's nearly zero
382     mindenom1= minimum denominator for dividing into 1.0
383    
384     returns:
385     quotient
386     sets zerodiv and returns 0.0 if it would overflow
387    
388     design:
389     if numer is nearly zero and abs(numer) < abs(denom)
390     return numer/denom
391     else if numer is nearly zero
392     return 0 and zerodiv
393     else if denom/numer non-zero
394     return numer/denom
395     else
396     return 0 and zerodiv
397     */
398     realT qh_divzero (realT numer, realT denom, realT mindenom1, boolT *zerodiv) {
399     realT temp, numerx, denomx;
400    
401    
402     if (numer < mindenom1 && numer > -mindenom1) {
403     numerx= fabs_(numer);
404     denomx= fabs_(denom);
405     if (numerx < denomx) {
406     *zerodiv= False;
407     return numer/denom;
408     }else {
409     *zerodiv= True;
410     return 0.0;
411     }
412     }
413     temp= denom/numer;
414     if (temp > mindenom1 || temp < -mindenom1) {
415     *zerodiv= False;
416     return numer/denom;
417     }else {
418     *zerodiv= True;
419     return 0.0;
420     }
421     } /* divzero */
422    
423    
424     /*-<a href="qh-geom.htm#TOC"
425     >-------------------------------</a><a name="facetarea">-</a>
426    
427     qh_facetarea( facet )
428     return area for a facet
429    
430     notes:
431     if non-simplicial,
432     uses centrum to triangulate facet and sums the projected areas.
433     if (qh DELAUNAY),
434     computes projected area instead for last coordinate
435     assumes facet->normal exists
436     projecting tricoplanar facets to the hyperplane does not appear to make a difference
437    
438     design:
439     if simplicial
440     compute area
441     else
442     for each ridge
443     compute area from centrum to ridge
444     negate area if upper Delaunay facet
445     */
446     realT qh_facetarea (facetT *facet) {
447     vertexT *apex;
448     pointT *centrum;
449     realT area= 0.0;
450     ridgeT *ridge, **ridgep;
451    
452     if (facet->simplicial) {
453     apex= SETfirstt_(facet->vertices, vertexT);
454     area= qh_facetarea_simplex (qh hull_dim, apex->point, facet->vertices,
455     apex, facet->toporient, facet->normal, &facet->offset);
456     }else {
457     if (qh CENTERtype == qh_AScentrum)
458     centrum= facet->center;
459     else
460     centrum= qh_getcentrum (facet);
461     FOREACHridge_(facet->ridges)
462     area += qh_facetarea_simplex (qh hull_dim, centrum, ridge->vertices,
463     NULL, (ridge->top == facet), facet->normal, &facet->offset);
464     if (qh CENTERtype != qh_AScentrum)
465     qh_memfree (centrum, qh normal_size);
466     }
467     if (facet->upperdelaunay && qh DELAUNAY)
468     area= -area; /* the normal should be [0,...,1] */
469     trace4((qh ferr, "qh_facetarea: f%d area %2.2g\n", facet->id, area));
470     return area;
471     } /* facetarea */
472    
473     /*-<a href="qh-geom.htm#TOC"
474     >-------------------------------</a><a name="facetarea_simplex">-</a>
475    
476     qh_facetarea_simplex( dim, apex, vertices, notvertex, toporient, normal, offset )
477     return area for a simplex defined by
478     an apex, a base of vertices, an orientation, and a unit normal
479     if simplicial or tricoplanar facet,
480     notvertex is defined and it is skipped in vertices
481    
482     returns:
483     computes area of simplex projected to plane [normal,offset]
484     returns 0 if vertex too far below plane (qh WIDEfacet)
485     vertex can't be apex of tricoplanar facet
486    
487     notes:
488     if (qh DELAUNAY),
489     computes projected area instead for last coordinate
490     uses qh gm_matrix/gm_row and qh hull_dim
491     helper function for qh_facetarea
492    
493     design:
494     if Notvertex
495     translate simplex to apex
496     else
497     project simplex to normal/offset
498     translate simplex to apex
499     if Delaunay
500     set last row/column to 0 with -1 on diagonal
501     else
502     set last row to Normal
503     compute determinate
504     scale and flip sign for area
505     */
506     realT qh_facetarea_simplex (int dim, coordT *apex, setT *vertices,
507     vertexT *notvertex, boolT toporient, coordT *normal, realT *offset) {
508     pointT *coorda, *coordp, *gmcoord;
509     coordT **rows, *normalp;
510     int k, i=0;
511     realT area, dist;
512     vertexT *vertex, **vertexp;
513     boolT nearzero;
514    
515     gmcoord= qh gm_matrix;
516     rows= qh gm_row;
517     FOREACHvertex_(vertices) {
518     if (vertex == notvertex)
519     continue;
520     rows[i++]= gmcoord;
521     coorda= apex;
522     coordp= vertex->point;
523     normalp= normal;
524     if (notvertex) {
525     for (k= dim; k--; )
526     *(gmcoord++)= *coordp++ - *coorda++;
527     }else {
528     dist= *offset;
529     for (k= dim; k--; )
530     dist += *coordp++ * *normalp++;
531     if (dist < -qh WIDEfacet) {
532     zinc_(Znoarea);
533     return 0.0;
534     }
535     coordp= vertex->point;
536     normalp= normal;
537     for (k= dim; k--; )
538     *(gmcoord++)= (*coordp++ - dist * *normalp++) - *coorda++;
539     }
540     }
541     if (i != dim-1) {
542     fprintf (qh ferr, "qhull internal error (qh_facetarea_simplex): #points %d != dim %d -1\n",
543     i, dim);
544     qh_errexit (qh_ERRqhull, NULL, NULL);
545     }
546     rows[i]= gmcoord;
547     if (qh DELAUNAY) {
548     for (i= 0; i < dim-1; i++)
549     rows[i][dim-1]= 0.0;
550     for (k= dim; k--; )
551     *(gmcoord++)= 0.0;
552     rows[dim-1][dim-1]= -1.0;
553     }else {
554     normalp= normal;
555     for (k= dim; k--; )
556     *(gmcoord++)= *normalp++;
557     }
558     zinc_(Zdetsimplex);
559     area= qh_determinant (rows, dim, &nearzero);
560     if (toporient)
561     area= -area;
562     area *= qh AREAfactor;
563     trace4((qh ferr, "qh_facetarea_simplex: area=%2.2g for point p%d, toporient %d, nearzero? %d\n", area, qh_pointid(apex), toporient, nearzero));
564     return area;
565     } /* facetarea_simplex */
566    
567     /*-<a href="qh-geom.htm#TOC"
568     >-------------------------------</a><a name="facetcenter">-</a>
569    
570     qh_facetcenter( vertices )
571     return Voronoi center (Voronoi vertex) for a facet's vertices
572    
573     returns:
574     return temporary point equal to the center
575    
576     see:
577     qh_voronoi_center()
578     */
579     pointT *qh_facetcenter (setT *vertices) {
580     setT *points= qh_settemp (qh_setsize (vertices));
581     vertexT *vertex, **vertexp;
582     pointT *center;
583    
584     FOREACHvertex_(vertices)
585     qh_setappend (&points, vertex->point);
586     center= qh_voronoi_center (qh hull_dim-1, points);
587     qh_settempfree (&points);
588     return center;
589     } /* facetcenter */
590    
591     /*-<a href="qh-geom.htm#TOC"
592     >-------------------------------</a><a name="findgooddist">-</a>
593    
594     qh_findgooddist( point, facetA, dist, facetlist )
595     find best good facet visible for point from facetA
596     assumes facetA is visible from point
597    
598     returns:
599     best facet, i.e., good facet that is furthest from point
600     distance to best facet
601     NULL if none
602    
603     moves good, visible facets (and some other visible facets)
604     to end of qh facet_list
605    
606     notes:
607     uses qh visit_id
608    
609     design:
610     initialize bestfacet if facetA is good
611     move facetA to end of facetlist
612     for each facet on facetlist
613     for each unvisited neighbor of facet
614     move visible neighbors to end of facetlist
615     update best good neighbor
616     if no good neighbors, update best facet
617     */
618     facetT *qh_findgooddist (pointT *point, facetT *facetA, realT *distp,
619     facetT **facetlist) {
620     realT bestdist= -REALmax, dist;
621     facetT *neighbor, **neighborp, *bestfacet=NULL, *facet;
622     boolT goodseen= False;
623    
624     if (facetA->good) {
625     zinc_(Zcheckpart); /* calls from check_bestdist occur after print stats */
626     qh_distplane (point, facetA, &bestdist);
627     bestfacet= facetA;
628     goodseen= True;
629     }
630     qh_removefacet (facetA);
631     qh_appendfacet (facetA);
632     *facetlist= facetA;
633     facetA->visitid= ++qh visit_id;
634     FORALLfacet_(*facetlist) {
635     FOREACHneighbor_(facet) {
636     if (neighbor->visitid == qh visit_id)
637     continue;
638     neighbor->visitid= qh visit_id;
639     if (goodseen && !neighbor->good)
640     continue;
641     zinc_(Zcheckpart);
642     qh_distplane (point, neighbor, &dist);
643     if (dist > 0) {
644     qh_removefacet (neighbor);
645     qh_appendfacet (neighbor);
646     if (neighbor->good) {
647     goodseen= True;
648     if (dist > bestdist) {
649     bestdist= dist;
650     bestfacet= neighbor;
651     }
652     }
653     }
654     }
655     }
656     if (bestfacet) {
657     *distp= bestdist;
658     trace2((qh ferr, "qh_findgooddist: p%d is %2.2g above good facet f%d\n", qh_pointid(point), bestdist, bestfacet->id));
659     return bestfacet;
660     }
661     trace4((qh ferr, "qh_findgooddist: no good facet for p%d above f%d\n", qh_pointid(point), facetA->id));
662     return NULL;
663     } /* findgooddist */
664    
665     /*-<a href="qh-geom.htm#TOC"
666     >-------------------------------</a><a name="getarea">-</a>
667    
668     qh_getarea( facetlist )
669     set area of all facets in facetlist
670     collect statistics
671    
672     returns:
673     sets qh totarea/totvol to total area and volume of convex hull
674     for Delaunay triangulation, computes projected area of the lower or upper hull
675     ignores upper hull if qh ATinfinity
676    
677     notes:
678     could compute outer volume by expanding facet area by rays from interior
679     the following attempt at perpendicular projection underestimated badly:
680     qh.totoutvol += (-dist + facet->maxoutside + qh DISTround)
681     * area/ qh hull_dim;
682     design:
683     for each facet on facetlist
684     compute facet->area
685     update qh.totarea and qh.totvol
686     */
687     void qh_getarea (facetT *facetlist) {
688     realT area;
689     realT dist;
690     facetT *facet;
691    
692     if (qh REPORTfreq)
693     fprintf (qh ferr, "computing area of each facet and volume of the convex hull\n");
694     else
695     trace1((qh ferr, "qh_getarea: computing volume and area for each facet\n"));
696     qh totarea= qh totvol= 0.0;
697     FORALLfacet_(facetlist) {
698     if (!facet->normal)
699     continue;
700     if (facet->upperdelaunay && qh ATinfinity)
701     continue;
702     facet->f.area= area= qh_facetarea (facet);
703     facet->isarea= True;
704     if (qh DELAUNAY) {
705     if (facet->upperdelaunay == qh UPPERdelaunay)
706     qh totarea += area;
707     }else {
708     qh totarea += area;
709     qh_distplane (qh interior_point, facet, &dist);
710     qh totvol += -dist * area/ qh hull_dim;
711     }
712     if (qh PRINTstatistics) {
713     wadd_(Wareatot, area);
714     wmax_(Wareamax, area);
715     wmin_(Wareamin, area);
716     }
717     }
718     } /* getarea */
719    
720     /*-<a href="qh-geom.htm#TOC"
721     >-------------------------------</a><a name="gram_schmidt">-</a>
722    
723     qh_gram_schmidt( dim, row )
724     implements Gram-Schmidt orthogonalization by rows
725    
726     returns:
727     false if zero norm
728     overwrites rows[dim][dim]
729    
730     notes:
731     see Golub & van Loan Algorithm 6.2-2
732     overflow due to small divisors not handled
733    
734     design:
735     for each row
736     compute norm for row
737     if non-zero, normalize row
738     for each remaining rowA
739     compute inner product of row and rowA
740     reduce rowA by row * inner product
741     */
742     boolT qh_gram_schmidt(int dim, realT **row) {
743     realT *rowi, *rowj, norm;
744     int i, j, k;
745    
746     for(i=0; i < dim; i++) {
747     rowi= row[i];
748     for (norm= 0.0, k= dim; k--; rowi++)
749     norm += *rowi * *rowi;
750     norm= sqrt(norm);
751     wmin_(Wmindenom, norm);
752     if (norm == 0.0) /* either 0 or overflow due to sqrt */
753     return False;
754     for(k= dim; k--; )
755     *(--rowi) /= norm;
756     for(j= i+1; j < dim; j++) {
757     rowj= row[j];
758     for(norm= 0.0, k=dim; k--; )
759     norm += *rowi++ * *rowj++;
760     for(k=dim; k--; )
761     *(--rowj) -= *(--rowi) * norm;
762     }
763     }
764     return True;
765     } /* gram_schmidt */
766    
767    
768     /*-<a href="qh-geom.htm#TOC"
769     >-------------------------------</a><a name="inthresholds">-</a>
770    
771     qh_inthresholds( normal, angle )
772     return True if normal within qh.lower_/upper_threshold
773    
774     returns:
775     estimate of angle by summing of threshold diffs
776     angle may be NULL
777     smaller "angle" is better
778    
779     notes:
780     invalid if qh.SPLITthresholds
781    
782     see:
783     qh.lower_threshold in qh_initbuild()
784     qh_initthresholds()
785    
786     design:
787     for each dimension
788     test threshold
789     */
790     boolT qh_inthresholds (coordT *normal, realT *angle) {
791     boolT within= True;
792     int k;
793     realT threshold;
794    
795     if (angle)
796     *angle= 0.0;
797     for(k= 0; k < qh hull_dim; k++) {
798     threshold= qh lower_threshold[k];
799     if (threshold > -REALmax/2) {
800     if (normal[k] < threshold)
801     within= False;
802     if (angle) {
803     threshold -= normal[k];
804     *angle += fabs_(threshold);
805     }
806     }
807     if (qh upper_threshold[k] < REALmax/2) {
808     threshold= qh upper_threshold[k];
809     if (normal[k] > threshold)
810     within= False;
811     if (angle) {
812     threshold -= normal[k];
813     *angle += fabs_(threshold);
814     }
815     }
816     }
817     return within;
818     } /* inthresholds */
819    
820    
821     /*-<a href="qh-geom.htm#TOC"
822     >-------------------------------</a><a name="joggleinput">-</a>
823    
824     qh_joggleinput()
825     randomly joggle input to Qhull by qh.JOGGLEmax
826     initial input is qh.first_point/qh.num_points of qh.hull_dim
827     repeated calls use qh.input_points/qh.num_points
828    
829     returns:
830     joggles points at qh.first_point/qh.num_points
831     copies data to qh.input_points/qh.input_malloc if first time
832     determines qh.JOGGLEmax if it was zero
833     if qh.DELAUNAY
834     computes the Delaunay projection of the joggled points
835    
836     notes:
837     if qh.DELAUNAY, unnecessarily joggles the last coordinate
838     the initial 'QJn' may be set larger than qh_JOGGLEmaxincrease
839    
840     design:
841     if qh.DELAUNAY
842     set qh.SCALElast for reduced precision errors
843     if first call
844     initialize qh.input_points to the original input points
845     if qh.JOGGLEmax == 0
846     determine default qh.JOGGLEmax
847     else
848     increase qh.JOGGLEmax according to qh.build_cnt
849     joggle the input by adding a random number in [-qh.JOGGLEmax,qh.JOGGLEmax]
850     if qh.DELAUNAY
851     sets the Delaunay projection
852     */
853     void qh_joggleinput (void) {
854     int size, i, seed;
855     coordT *coordp, *inputp;
856     realT randr, randa, randb;
857    
858     if (!qh input_points) { /* first call */
859     qh input_points= qh first_point;
860     qh input_malloc= qh POINTSmalloc;
861     size= qh num_points * qh hull_dim * sizeof(coordT);
862     if (!(qh first_point=(coordT*)malloc(size))) {
863     fprintf(qh ferr, "qhull error: insufficient memory to joggle %d points\n",
864     qh num_points);
865     qh_errexit(qh_ERRmem, NULL, NULL);
866     }
867     qh POINTSmalloc= True;
868     if (qh JOGGLEmax == 0.0) {
869     qh JOGGLEmax= qh_detjoggle (qh input_points, qh num_points, qh hull_dim);
870     qh_option ("QJoggle", NULL, &qh JOGGLEmax);
871     }
872     }else { /* repeated call */
873     if (!qh RERUN && qh build_cnt > qh_JOGGLEretry) {
874     if (((qh build_cnt-qh_JOGGLEretry-1) % qh_JOGGLEagain) == 0) {
875     realT maxjoggle= qh MAXwidth * qh_JOGGLEmaxincrease;
876     if (qh JOGGLEmax < maxjoggle) {
877     qh JOGGLEmax *= qh_JOGGLEincrease;
878     minimize_(qh JOGGLEmax, maxjoggle);
879     }
880     }
881     }
882     qh_option ("QJoggle", NULL, &qh JOGGLEmax);
883     }
884     if (qh build_cnt > 1 && qh JOGGLEmax > fmax_(qh MAXwidth/4, 0.1)) {
885     fprintf (qh ferr, "qhull error: the current joggle for 'QJn', %.2g, is too large for the width\nof the input. If possible, recompile Qhull with higher-precision reals.\n",
886     qh JOGGLEmax);
887     qh_errexit (qh_ERRqhull, NULL, NULL);
888     }
889     /* for some reason, using qh ROTATErandom and qh_RANDOMseed does not repeat the run. Use 'TRn' instead */
890     seed= qh_RANDOMint;
891     qh_option ("_joggle-seed", &seed, NULL);
892     trace0((qh ferr, "qh_joggleinput: joggle input by %2.2g with seed %d\n", qh JOGGLEmax, seed));
893     inputp= qh input_points;
894     coordp= qh first_point;
895     randa= 2.0 * qh JOGGLEmax/qh_RANDOMmax;
896     randb= -qh JOGGLEmax;
897     size= qh num_points * qh hull_dim;
898     for (i= size; i--; ) {
899     randr= qh_RANDOMint;
900     *(coordp++)= *(inputp++) + (randr * randa + randb);
901     }
902     if (qh DELAUNAY) {
903     qh last_low= qh last_high= qh last_newhigh= REALmax;
904     qh_setdelaunay (qh hull_dim, qh num_points, qh first_point);
905     }
906     } /* joggleinput */
907    
908     /*-<a href="qh-geom.htm#TOC"
909     >-------------------------------</a><a name="maxabsval">-</a>
910    
911     qh_maxabsval( normal, dim )
912     return pointer to maximum absolute value of a dim vector
913     returns NULL if dim=0
914     */
915     realT *qh_maxabsval (realT *normal, int dim) {
916     realT maxval= -REALmax;
917     realT *maxp= NULL, *colp, absval;
918     int k;
919    
920     for (k= dim, colp= normal; k--; colp++) {
921     absval= fabs_(*colp);
922     if (absval > maxval) {
923     maxval= absval;
924     maxp= colp;
925     }
926     }
927     return maxp;
928     } /* maxabsval */
929    
930    
931     /*-<a href="qh-geom.htm#TOC"
932     >-------------------------------</a><a name="maxmin">-</a>
933    
934     qh_maxmin( points, numpoints, dimension )
935     return max/min points for each dimension
936     determine max and min coordinates
937    
938     returns:
939     returns a temporary set of max and min points
940     may include duplicate points. Does not include qh.GOODpoint
941     sets qh.NEARzero, qh.MAXabs_coord, qh.MAXsumcoord, qh.MAXwidth
942     qh.MAXlastcoord, qh.MINlastcoord
943     initializes qh.max_outside, qh.min_vertex, qh.WAScoplanar, qh.ZEROall_ok
944    
945     notes:
946     loop duplicated in qh_detjoggle()
947    
948     design:
949     initialize global precision variables
950     checks definition of REAL...
951     for each dimension
952     for each point
953     collect maximum and minimum point
954     collect maximum of maximums and minimum of minimums
955     determine qh.NEARzero for Gaussian Elimination
956     */
957     setT *qh_maxmin(pointT *points, int numpoints, int dimension) {
958     int k;
959     realT maxcoord, temp;
960     pointT *minimum, *maximum, *point, *pointtemp;
961     setT *set;
962    
963     qh max_outside= 0.0;
964     qh MAXabs_coord= 0.0;
965     qh MAXwidth= -REALmax;
966     qh MAXsumcoord= 0.0;
967     qh min_vertex= 0.0;
968     qh WAScoplanar= False;
969     if (qh ZEROcentrum)
970     qh ZEROall_ok= True;
971     if (REALmin < REALepsilon && REALmin < REALmax && REALmin > -REALmax
972     && REALmax > 0.0 && -REALmax < 0.0)
973     ; /* all ok */
974     else {
975     fprintf (qh ferr, "qhull error: floating point constants in user.h are wrong\n\
976     REALepsilon %g REALmin %g REALmax %g -REALmax %g\n",
977     REALepsilon, REALmin, REALmax, -REALmax);
978     qh_errexit (qh_ERRinput, NULL, NULL);
979     }
980     set= qh_settemp(2*dimension);
981     for(k= 0; k < dimension; k++) {
982     if (points == qh GOODpointp)
983     minimum= maximum= points + dimension;
984     else
985     minimum= maximum= points;
986     FORALLpoint_(points, numpoints) {
987     if (point == qh GOODpointp)
988     continue;
989     if (maximum[k] < point[k])
990     maximum= point;
991     else if (minimum[k] > point[k])
992     minimum= point;
993     }
994     if (k == dimension-1) {
995     qh MINlastcoord= minimum[k];
996     qh MAXlastcoord= maximum[k];
997     }
998     if (qh SCALElast && k == dimension-1)
999     maxcoord= qh MAXwidth;
1000     else {
1001     maxcoord= fmax_(maximum[k], -minimum[k]);
1002     if (qh GOODpointp) {
1003     temp= fmax_(qh GOODpointp[k], -qh GOODpointp[k]);
1004     maximize_(maxcoord, temp);
1005     }
1006     temp= maximum[k] - minimum[k];
1007     maximize_(qh MAXwidth, temp);
1008     }
1009     maximize_(qh MAXabs_coord, maxcoord);
1010     qh MAXsumcoord += maxcoord;
1011     qh_setappend (&set, maximum);
1012     qh_setappend (&set, minimum);
1013     /* calculation of qh NEARzero is based on error formula 4.4-13 of
1014     Golub & van Loan, authors say n^3 can be ignored and 10 be used in
1015     place of rho */
1016     qh NEARzero[k]= 80 * qh MAXsumcoord * REALepsilon;
1017     }
1018     if (qh IStracing >=1)
1019     qh_printpoints (qh ferr, "qh_maxmin: found the max and min points (by dim):", set);
1020     return(set);
1021     } /* maxmin */
1022    
1023     /*-<a href="qh-geom.htm#TOC"
1024     >-------------------------------</a><a name="maxouter">-</a>
1025    
1026     qh_maxouter()
1027     return maximum distance from facet to outer plane
1028     normally this is qh.max_outside+qh.DISTround
1029     does not include qh.JOGGLEmax
1030    
1031     see:
1032     qh_outerinner()
1033    
1034     notes:
1035     need to add another qh.DISTround if testing actual point with computation
1036    
1037     for joggle:
1038     qh_setfacetplane() updated qh.max_outer for Wnewvertexmax (max distance to vertex)
1039     need to use Wnewvertexmax since could have a coplanar point for a high
1040     facet that is replaced by a low facet
1041     need to add qh.JOGGLEmax if testing input points
1042     */
1043     realT qh_maxouter (void) {
1044     realT dist;
1045    
1046     dist= fmax_(qh max_outside, qh DISTround);
1047     dist += qh DISTround;
1048     trace4((qh ferr, "qh_maxouter: max distance from facet to outer plane is %2.2g max_outside is %2.2g\n", dist, qh max_outside));
1049     return dist;
1050     } /* maxouter */
1051    
1052     /*-<a href="qh-geom.htm#TOC"
1053     >-------------------------------</a><a name="maxsimplex">-</a>
1054    
1055     qh_maxsimplex( dim, maxpoints, points, numpoints, simplex )
1056     determines maximum simplex for a set of points
1057     starts from points already in simplex
1058     skips qh.GOODpointp (assumes that it isn't in maxpoints)
1059    
1060     returns:
1061     simplex with dim+1 points
1062    
1063     notes:
1064     assumes at least pointsneeded points in points
1065     maximizes determinate for x,y,z,w, etc.
1066     uses maxpoints as long as determinate is clearly non-zero
1067    
1068     design:
1069     initialize simplex with at least two points
1070     (find points with max or min x coordinate)
1071     for each remaining dimension
1072     add point that maximizes the determinate
1073     (use points from maxpoints first)
1074     */
1075     void qh_maxsimplex (int dim, setT *maxpoints, pointT *points, int numpoints, setT **simplex) {
1076     pointT *point, **pointp, *pointtemp, *maxpoint, *minx=NULL, *maxx=NULL;
1077     boolT nearzero, maxnearzero= False;
1078     int k, sizinit;
1079     realT maxdet= -REALmax, det, mincoord= REALmax, maxcoord= -REALmax;
1080    
1081     sizinit= qh_setsize (*simplex);
1082     if (sizinit < 2) {
1083     if (qh_setsize (maxpoints) >= 2) {
1084     FOREACHpoint_(maxpoints) {
1085     if (maxcoord < point[0]) {
1086     maxcoord= point[0];
1087     maxx= point;
1088     }
1089     if (mincoord > point[0]) {
1090     mincoord= point[0];
1091     minx= point;
1092     }
1093     }
1094     }else {
1095     FORALLpoint_(points, numpoints) {
1096     if (point == qh GOODpointp)
1097     continue;
1098     if (maxcoord < point[0]) {
1099     maxcoord= point[0];
1100     maxx= point;
1101     }
1102     if (mincoord > point[0]) {
1103     mincoord= point[0];
1104     minx= point;
1105     }
1106     }
1107     }
1108     qh_setunique (simplex, minx);
1109     if (qh_setsize (*simplex) < 2)
1110     qh_setunique (simplex, maxx);
1111     sizinit= qh_setsize (*simplex);
1112     if (sizinit < 2) {
1113     qh_precision ("input has same x coordinate");
1114     if (zzval_(Zsetplane) > qh hull_dim+1) {
1115     fprintf (qh ferr, "qhull precision error (qh_maxsimplex for voronoi_center):\n%d points with the same x coordinate.\n",
1116     qh_setsize(maxpoints)+numpoints);
1117     qh_errexit (qh_ERRprec, NULL, NULL);
1118     }else {
1119     fprintf (qh ferr, "qhull input error: input is less than %d-dimensional since it has the same x coordinate\n", qh hull_dim);
1120     qh_errexit (qh_ERRinput, NULL, NULL);
1121     }
1122     }
1123     }
1124     for(k= sizinit; k < dim+1; k++) {
1125     maxpoint= NULL;
1126     maxdet= -REALmax;
1127     FOREACHpoint_(maxpoints) {
1128     if (!qh_setin (*simplex, point)) {
1129     det= qh_detsimplex(point, *simplex, k, &nearzero);
1130     if ((det= fabs_(det)) > maxdet) {
1131     maxdet= det;
1132     maxpoint= point;
1133     maxnearzero= nearzero;
1134     }
1135     }
1136     }
1137     if (!maxpoint || maxnearzero) {
1138     zinc_(Zsearchpoints);
1139     if (!maxpoint) {
1140     trace0((qh ferr, "qh_maxsimplex: searching all points for %d-th initial vertex.\n", k+1));
1141     }else {
1142     trace0((qh ferr, "qh_maxsimplex: searching all points for %d-th initial vertex, better than p%d det %2.2g\n", k+1, qh_pointid(maxpoint), maxdet));
1143     }
1144     FORALLpoint_(points, numpoints) {
1145     if (point == qh GOODpointp)
1146     continue;
1147     if (!qh_setin (*simplex, point)) {
1148     det= qh_detsimplex(point, *simplex, k, &nearzero);
1149     if ((det= fabs_(det)) > maxdet) {
1150     maxdet= det;
1151     maxpoint= point;
1152     maxnearzero= nearzero;
1153     }
1154     }
1155     }
1156     } /* !maxpoint */
1157     if (!maxpoint) {
1158     fprintf (qh ferr, "qhull internal error (qh_maxsimplex): not enough points available\n");
1159     qh_errexit (qh_ERRqhull, NULL, NULL);
1160     }
1161     qh_setappend(simplex, maxpoint);
1162     trace1((qh ferr, "qh_maxsimplex: selected point p%d for %d`th initial vertex, det=%2.2g\n", qh_pointid(maxpoint), k+1, maxdet));
1163     } /* k */
1164     } /* maxsimplex */
1165    
1166     /*-<a href="qh-geom.htm#TOC"
1167     >-------------------------------</a><a name="minabsval">-</a>
1168    
1169     qh_minabsval( normal, dim )
1170     return minimum absolute value of a dim vector
1171     */
1172     realT qh_minabsval (realT *normal, int dim) {
1173     realT minval= 0;
1174     realT maxval= 0;
1175     realT *colp;
1176     int k;
1177    
1178     for (k= dim, colp= normal; k--; colp++) {
1179     maximize_(maxval, *colp);
1180     minimize_(minval, *colp);
1181     }
1182     return fmax_(maxval, -minval);
1183     } /* minabsval */
1184    
1185    
1186     /*-<a href="qh-geom.htm#TOC"
1187     >-------------------------------</a><a name="mindiff">-</a>
1188    
1189     qh_mindif( vecA, vecB, dim )
1190     return index of min abs. difference of two vectors
1191     */
1192     int qh_mindiff (realT *vecA, realT *vecB, int dim) {
1193     realT mindiff= REALmax, diff;
1194     realT *vecAp= vecA, *vecBp= vecB;
1195     int k, mink= 0;
1196    
1197     for (k= 0; k < dim; k++) {
1198     diff= *vecAp++ - *vecBp++;
1199     diff= fabs_(diff);
1200     if (diff < mindiff) {
1201     mindiff= diff;
1202     mink= k;
1203     }
1204     }
1205     return mink;
1206     } /* mindiff */
1207    
1208    
1209    
1210     /*-<a href="qh-geom.htm#TOC"
1211     >-------------------------------</a><a name="orientoutside">-</a>
1212    
1213     qh_orientoutside( facet )
1214     make facet outside oriented via qh.interior_point
1215    
1216     returns:
1217     True if facet reversed orientation.
1218     */
1219     boolT qh_orientoutside (facetT *facet) {
1220     int k;
1221     realT dist;
1222    
1223     qh_distplane (qh interior_point, facet, &dist);
1224     if (dist > 0) {
1225     for (k= qh hull_dim; k--; )
1226     facet->normal[k]= -facet->normal[k];
1227     facet->offset= -facet->offset;
1228     return True;
1229     }
1230     return False;
1231     } /* orientoutside */
1232    
1233     /*-<a href="qh-geom.htm#TOC"
1234     >-------------------------------</a><a name="outerinner">-</a>
1235    
1236     qh_outerinner( facet, outerplane, innerplane )
1237     if facet and qh.maxoutdone (i.e., qh_check_maxout)
1238     returns outer and inner plane for facet
1239     else
1240     returns maximum outer and inner plane
1241     accounts for qh.JOGGLEmax
1242    
1243     see:
1244     qh_maxouter(), qh_check_bestdist(), qh_check_points()
1245    
1246     notes:
1247     outerplaner or innerplane may be NULL
1248    
1249     includes qh.DISTround for actual points
1250     adds another qh.DISTround if testing with floating point arithmetic
1251     */
1252     void qh_outerinner (facetT *facet, realT *outerplane, realT *innerplane) {
1253     realT dist, mindist;
1254     vertexT *vertex, **vertexp;
1255    
1256     if (outerplane) {
1257     if (!qh_MAXoutside || !facet || !qh maxoutdone) {
1258     *outerplane= qh_maxouter(); /* includes qh.DISTround */
1259     }else { /* qh_MAXoutside ... */
1260     #if qh_MAXoutside
1261     *outerplane= facet->maxoutside + qh DISTround;
1262     #endif
1263    
1264     }
1265     if (qh JOGGLEmax < REALmax/2)
1266     *outerplane += qh JOGGLEmax * sqrt (qh hull_dim);
1267     }
1268     if (innerplane) {
1269     if (facet) {
1270     mindist= REALmax;
1271     FOREACHvertex_(facet->vertices) {
1272     zinc_(Zdistio);
1273     qh_distplane (vertex->point, facet, &dist);
1274     minimize_(mindist, dist);
1275     }
1276     *innerplane= mindist - qh DISTround;
1277     }else
1278     *innerplane= qh min_vertex - qh DISTround;
1279     if (qh JOGGLEmax < REALmax/2)
1280     *innerplane -= qh JOGGLEmax * sqrt (qh hull_dim);
1281     }
1282     } /* outerinner */
1283    
1284     /*-<a href="qh-geom.htm#TOC"
1285     >-------------------------------</a><a name="pointdist">-</a>
1286    
1287     qh_pointdist( point1, point2, dim )
1288     return distance between two points
1289    
1290     notes:
1291     returns distance squared if 'dim' is negative
1292     */
1293     coordT qh_pointdist(pointT *point1, pointT *point2, int dim) {
1294     coordT dist, diff;
1295     int k;
1296    
1297     dist= 0.0;
1298     for (k= (dim > 0 ? dim : -dim); k--; ) {
1299     diff= *point1++ - *point2++;
1300     dist += diff * diff;
1301     }
1302     if (dim > 0)
1303     return(sqrt(dist));
1304     return dist;
1305     } /* pointdist */
1306    
1307    
1308     /*-<a href="qh-geom.htm#TOC"
1309     >-------------------------------</a><a name="printmatrix">-</a>
1310    
1311     qh_printmatrix( fp, string, rows, numrow, numcol )
1312     print matrix to fp given by row vectors
1313     print string as header
1314    
1315     notes:
1316     print a vector by qh_printmatrix(fp, "", &vect, 1, len)
1317     */
1318     void qh_printmatrix (FILE *fp, char *string, realT **rows, int numrow, int numcol) {
1319     realT *rowp;
1320     realT r; /*bug fix*/
1321     int i,k;
1322    
1323     fprintf (fp, "%s\n", string);
1324     for (i= 0; i < numrow; i++) {
1325     rowp= rows[i];
1326     for (k= 0; k < numcol; k++) {
1327     r= *rowp++;
1328     fprintf (fp, "%6.3g ", r);
1329     }
1330     fprintf (fp, "\n");
1331     }
1332     } /* printmatrix */
1333    
1334    
1335     /*-<a href="qh-geom.htm#TOC"
1336     >-------------------------------</a><a name="printpoints">-</a>
1337    
1338     qh_printpoints( fp, string, points )
1339     print pointids to fp for a set of points
1340     if string, prints string and 'p' point ids
1341     */
1342     void qh_printpoints (FILE *fp, char *string, setT *points) {
1343     pointT *point, **pointp;
1344    
1345     if (string) {
1346     fprintf (fp, "%s", string);
1347     FOREACHpoint_(points)
1348     fprintf (fp, " p%d", qh_pointid(point));
1349     fprintf (fp, "\n");
1350     }else {
1351     FOREACHpoint_(points)
1352     fprintf (fp, " %d", qh_pointid(point));
1353     fprintf (fp, "\n");
1354     }
1355     } /* printpoints */
1356    
1357    
1358     /*-<a href="qh-geom.htm#TOC"
1359     >-------------------------------</a><a name="projectinput">-</a>
1360    
1361     qh_projectinput()
1362     project input points using qh.lower_bound/upper_bound and qh DELAUNAY
1363     if qh.lower_bound[k]=qh.upper_bound[k]= 0,
1364     removes dimension k
1365     if halfspace intersection
1366     removes dimension k from qh.feasible_point
1367     input points in qh first_point, num_points, input_dim
1368    
1369     returns:
1370     new point array in qh first_point of qh hull_dim coordinates
1371     sets qh POINTSmalloc
1372     if qh DELAUNAY
1373     projects points to paraboloid
1374     lowbound/highbound is also projected
1375     if qh ATinfinity
1376     adds point "at-infinity"
1377     if qh POINTSmalloc
1378     frees old point array
1379    
1380     notes:
1381     checks that qh.hull_dim agrees with qh.input_dim, PROJECTinput, and DELAUNAY
1382    
1383    
1384     design:
1385     sets project[k] to -1 (delete), 0 (keep), 1 (add for Delaunay)
1386     determines newdim and newnum for qh hull_dim and qh num_points
1387     projects points to newpoints
1388     projects qh.lower_bound to itself
1389     projects qh.upper_bound to itself
1390     if qh DELAUNAY
1391     if qh ATINFINITY
1392     projects points to paraboloid
1393     computes "infinity" point as vertex average and 10% above all points
1394     else
1395     uses qh_setdelaunay to project points to paraboloid
1396     */
1397     void qh_projectinput (void) {
1398     int k,i;
1399     int newdim= qh input_dim, newnum= qh num_points;
1400     signed char *project;
1401     int size= (qh input_dim+1)*sizeof(*project);
1402     pointT *newpoints, *coord, *infinity;
1403     realT paraboloid, maxboloid= 0;
1404    
1405     project= (signed char*)qh_memalloc (size);
1406     memset ((char*)project, 0, size);
1407     for (k= 0; k < qh input_dim; k++) { /* skip Delaunay bound */
1408     if (qh lower_bound[k] == 0 && qh upper_bound[k] == 0) {
1409     project[k]= -1;
1410     newdim--;
1411     }
1412     }
1413     if (qh DELAUNAY) {
1414     project[k]= 1;
1415     newdim++;
1416     if (qh ATinfinity)
1417     newnum++;
1418     }
1419     if (newdim != qh hull_dim) {
1420     fprintf(qh ferr, "qhull internal error (qh_projectinput): dimension after projection %d != hull_dim %d\n", newdim, qh hull_dim);
1421     qh_errexit(qh_ERRqhull, NULL, NULL);
1422     }
1423     if (!(newpoints=(coordT*)malloc(newnum*newdim*sizeof(coordT)))){
1424     fprintf(qh ferr, "qhull error: insufficient memory to project %d points\n",
1425     qh num_points);
1426     qh_errexit(qh_ERRmem, NULL, NULL);
1427     }
1428     qh_projectpoints (project, qh input_dim+1, qh first_point,
1429     qh num_points, qh input_dim, newpoints, newdim);
1430     trace1((qh ferr, "qh_projectinput: updating lower and upper_bound\n"));
1431     qh_projectpoints (project, qh input_dim+1, qh lower_bound,
1432     1, qh input_dim+1, qh lower_bound, newdim+1);
1433     qh_projectpoints (project, qh input_dim+1, qh upper_bound,
1434     1, qh input_dim+1, qh upper_bound, newdim+1);
1435     if (qh HALFspace) {
1436     if (!qh feasible_point) {
1437     fprintf(qh ferr, "qhull internal error (qh_projectinput): HALFspace defined without qh.feasible_point\n");
1438     qh_errexit(qh_ERRqhull, NULL, NULL);
1439     }
1440     qh_projectpoints (project, qh input_dim, qh feasible_point,
1441     1, qh input_dim, qh feasible_point, newdim);
1442     }
1443     qh_memfree(project, ((qh input_dim+1)*sizeof(*project)));
1444     if (qh POINTSmalloc)
1445     free (qh first_point);
1446     qh first_point= newpoints;
1447     qh POINTSmalloc= True;
1448     if (qh DELAUNAY && qh ATinfinity) {
1449     coord= qh first_point;
1450     infinity= qh first_point + qh hull_dim * qh num_points;
1451     for (k=qh hull_dim-1; k--; )
1452     infinity[k]= 0.0;
1453     for (i=qh num_points; i--; ) {
1454     paraboloid= 0.0;
1455     for (k=0; k < qh hull_dim-1; k++) {
1456     paraboloid += *coord * *coord;
1457     infinity[k] += *coord;
1458     coord++;
1459     }
1460     *(coord++)= paraboloid;
1461     maximize_(maxboloid, paraboloid);
1462     }
1463     /* coord == infinity */
1464     for (k=qh hull_dim-1; k--; )
1465     *(coord++) /= qh num_points;
1466     *(coord++)= maxboloid * 1.1;
1467     qh num_points++;
1468     trace0((qh ferr, "qh_projectinput: projected points to paraboloid for Delaunay\n"));
1469     }else if (qh DELAUNAY) /* !qh ATinfinity */
1470     qh_setdelaunay( qh hull_dim, qh num_points, qh first_point);
1471     } /* projectinput */
1472    
1473    
1474     /*-<a href="qh-geom.htm#TOC"
1475     >-------------------------------</a><a name="projectpoints">-</a>
1476    
1477     qh_projectpoints( project, n, points, numpoints, dim, newpoints, newdim )
1478     project points/numpoints/dim to newpoints/newdim
1479     if project[k] == -1
1480     delete dimension k
1481     if project[k] == 1
1482     add dimension k by duplicating previous column
1483     n is size of project
1484    
1485     notes:
1486     newpoints may be points if only adding dimension at end
1487    
1488     design:
1489     check that 'project' and 'newdim' agree
1490     for each dimension
1491     if project == -1
1492     skip dimension
1493     else
1494     determine start of column in newpoints
1495     determine start of column in points
1496     if project == +1, duplicate previous column
1497     copy dimension (column) from points to newpoints
1498     */
1499     void qh_projectpoints (signed char *project, int n, realT *points,
1500     int numpoints, int dim, realT *newpoints, int newdim) {
1501     int testdim= dim, oldk=0, newk=0, i,j=0,k;
1502     realT *newp, *oldp;
1503    
1504     for (k= 0; k < n; k++)
1505     testdim += project[k];
1506     if (testdim != newdim) {
1507     fprintf (qh ferr, "qhull internal error (qh_projectpoints): newdim %d should be %d after projection\n",
1508     newdim, testdim);
1509     qh_errexit (qh_ERRqhull, NULL, NULL);
1510     }
1511     for (j= 0; j<n; j++) {
1512     if (project[j] == -1)
1513     oldk++;
1514     else {
1515     newp= newpoints+newk++;
1516     if (project[j] == +1) {
1517     if (oldk >= dim)
1518     continue;
1519     oldp= points+oldk;
1520     }else
1521     oldp= points+oldk++;
1522     for (i=numpoints; i--; ) {
1523     *newp= *oldp;
1524     newp += newdim;
1525     oldp += dim;
1526     }
1527     }
1528     if (oldk >= dim)
1529     break;
1530     }
1531     trace1((qh ferr, "qh_projectpoints: projected %d points from dim %d to dim %d\n", numpoints, dim, newdim));
1532     } /* projectpoints */
1533    
1534    
1535     /*-<a href="qh-geom.htm#TOC"
1536     >-------------------------------</a><a name="rand">-</a>
1537    
1538     qh_rand()
1539     qh_srand( seed )
1540     generate pseudo-random number between 1 and 2^31 -2
1541    
1542     notes:
1543     from Park & Miller's minimimal standard random number generator
1544     Communications of the ACM, 31:1192-1201, 1988.
1545     does not use 0 or 2^31 -1
1546     this is silently enforced by qh_srand()
1547     can make 'Rn' much faster by moving qh_rand to qh_distplane
1548     */
1549     int qh_rand_seed= 1; /* define as global variable instead of using qh */
1550    
1551     int qh_rand( void) {
1552     #define qh_rand_a 16807
1553     #define qh_rand_m 2147483647
1554     /* m div a */
1555     #define qh_rand_q 127773
1556     /* m mod a */
1557     #define qh_rand_r 2836
1558     int lo, hi, test;
1559     int seed = qh_rand_seed;
1560    
1561     hi = seed / qh_rand_q; /* seed div q */
1562     lo = seed % qh_rand_q; /* seed mod q */
1563     test = qh_rand_a * lo - qh_rand_r * hi;
1564     if (test > 0)
1565     seed= test;
1566     else
1567     seed= test + qh_rand_m;
1568     qh_rand_seed= seed;
1569     /* seed = seed < qh_RANDOMmax/2 ? 0 : qh_RANDOMmax; for testing */
1570     /* seed = qh_RANDOMmax; for testing */
1571     return seed;
1572     } /* rand */
1573    
1574     void qh_srand( int seed) {
1575     if (seed < 1)
1576     qh_rand_seed= 1;
1577     else if (seed >= qh_rand_m)
1578     qh_rand_seed= qh_rand_m - 1;
1579     else
1580     qh_rand_seed= seed;
1581     } /* qh_srand */
1582    
1583     /*-<a href="qh-geom.htm#TOC"
1584     >-------------------------------</a><a name="randomfactor">-</a>
1585    
1586     qh_randomfactor()
1587     return a random factor within qh.RANDOMmax of 1.0
1588    
1589     notes:
1590     qh.RANDOMa/b are defined in global.c
1591     */
1592     realT qh_randomfactor (void) {
1593     realT randr;
1594    
1595     randr= qh_RANDOMint;
1596     return randr * qh RANDOMa + qh RANDOMb;
1597     } /* randomfactor */
1598    
1599     /*-<a href="qh-geom.htm#TOC"
1600     >-------------------------------</a><a name="randommatrix">-</a>
1601    
1602     qh_randommatrix( buffer, dim, rows )
1603     generate a random dim X dim matrix in range [-1,1]
1604     assumes buffer is [dim+1, dim]
1605    
1606     returns:
1607     sets buffer to random numbers
1608     sets rows to rows of buffer
1609     sets row[dim] as scratch row
1610     */
1611     void qh_randommatrix (realT *buffer, int dim, realT **rows) {
1612     int i, k;
1613     realT **rowi, *coord, realr;
1614    
1615     coord= buffer;
1616     rowi= rows;
1617     for (i=0; i < dim; i++) {
1618     *(rowi++)= coord;
1619     for (k=0; k < dim; k++) {
1620     realr= qh_RANDOMint;
1621     *(coord++)= 2.0 * realr/(qh_RANDOMmax+1) - 1.0;
1622     }
1623     }
1624     *rowi= coord;
1625     } /* randommatrix */
1626    
1627    
1628     /*-<a href="qh-geom.htm#TOC"
1629     >-------------------------------</a><a name="rotateinput">-</a>
1630    
1631     qh_rotateinput( rows )
1632     rotate input using row matrix
1633     input points given by qh first_point, num_points, hull_dim
1634     assumes rows[dim] is a scratch buffer
1635     if qh POINTSmalloc, overwrites input points, else mallocs a new array
1636    
1637     returns:
1638     rotated input
1639     sets qh POINTSmalloc
1640    
1641     design:
1642     see qh_rotatepoints
1643     */
1644     void qh_rotateinput (realT **rows) {
1645    
1646     if (!qh POINTSmalloc) {
1647     qh first_point= qh_copypoints (qh first_point, qh num_points, qh hull_dim);
1648     qh POINTSmalloc= True;
1649     }
1650     qh_rotatepoints (qh first_point, qh num_points, qh hull_dim, rows);
1651     } /* rotateinput */
1652    
1653     /*-<a href="qh-geom.htm#TOC"
1654     >-------------------------------</a><a name="rotatepoints">-</a>
1655    
1656     qh_rotatepoints( points, numpoints, dim, row )
1657     rotate numpoints points by a d-dim row matrix
1658     assumes rows[dim] is a scratch buffer
1659    
1660     returns:
1661     rotated points in place
1662    
1663     design:
1664     for each point
1665     for each coordinate
1666     please use row[dim] to compute partial inner product
1667     for each coordinate
1668     rotate by partial inner product
1669     */
1670     void qh_rotatepoints (realT *points, int numpoints, int dim, realT **row) {
1671     realT *point, *rowi, *coord= NULL, sum, *newval;
1672     int i,j,k;
1673    
1674     if (qh IStracing >= 1)
1675     qh_printmatrix (qh ferr, "qh_rotatepoints: rotate points by", row, dim, dim);
1676     for (point= points, j= numpoints; j--; point += dim) {
1677     newval= row[dim];
1678     for (i= 0; i < dim; i++) {
1679     rowi= row[i];
1680     coord= point;
1681     for (sum= 0.0, k= dim; k--; )
1682     sum += *rowi++ * *coord++;
1683     *(newval++)= sum;
1684     }
1685     for (k= dim; k--; )
1686     *(--coord)= *(--newval);
1687     }
1688     } /* rotatepoints */
1689    
1690    
1691     /*-<a href="qh-geom.htm#TOC"
1692     >-------------------------------</a><a name="scaleinput">-</a>
1693    
1694     qh_scaleinput()
1695     scale input points using qh low_bound/high_bound
1696     input points given by qh first_point, num_points, hull_dim
1697     if qh POINTSmalloc, overwrites input points, else mallocs a new array
1698    
1699     returns:
1700     scales coordinates of points to low_bound[k], high_bound[k]
1701     sets qh POINTSmalloc
1702    
1703     design:
1704     see qh_scalepoints
1705     */
1706     void qh_scaleinput (void) {
1707    
1708     if (!qh POINTSmalloc) {
1709     qh first_point= qh_copypoints (qh first_point, qh num_points, qh hull_dim);
1710     qh POINTSmalloc= True;
1711     }
1712     qh_scalepoints (qh first_point, qh num_points, qh hull_dim,
1713     qh lower_bound, qh upper_bound);
1714     } /* scaleinput */
1715    
1716     /*-<a href="qh-geom.htm#TOC"
1717     >-------------------------------</a><a name="scalelast">-</a>
1718    
1719     qh_scalelast( points, numpoints, dim, low, high, newhigh )
1720     scale last coordinate to [0,m] for Delaunay triangulations
1721     input points given by points, numpoints, dim
1722    
1723     returns:
1724     changes scale of last coordinate from [low, high] to [0, newhigh]
1725     overwrites last coordinate of each point
1726     saves low/high/newhigh in qh.last_low, etc. for qh_setdelaunay()
1727    
1728     notes:
1729     when called by qh_setdelaunay, low/high may not match actual data
1730    
1731     design:
1732     compute scale and shift factors
1733     apply to last coordinate of each point
1734     */
1735     void qh_scalelast (coordT *points, int numpoints, int dim, coordT low,
1736     coordT high, coordT newhigh) {
1737     realT scale, shift;
1738     coordT *coord;
1739     int i;
1740     boolT nearzero= False;
1741    
1742     trace4((qh ferr, "qh_scalelast: scale last coordinate from [%2.2g, %2.2g] to [0,%2.2g]\n", low, high, newhigh));
1743     qh last_low= low;
1744     qh last_high= high;
1745     qh last_newhigh= newhigh;
1746     scale= qh_divzero (newhigh, high - low,
1747     qh MINdenom_1, &nearzero);
1748     if (nearzero) {
1749     if (qh DELAUNAY)
1750     fprintf (qh ferr, "qhull input error: can not scale last coordinate. Input is cocircular\n or cospherical. Use option 'Qz' to add a point at infinity.\n");
1751     else
1752     fprintf (qh ferr, "qhull input error: can not scale last coordinate. New bounds [0, %2.2g] are too wide for\nexisting bounds [%2.2g, %2.2g] (width %2.2g)\n",
1753     newhigh, low, high, high-low);
1754     qh_errexit (qh_ERRinput, NULL, NULL);
1755     }
1756     shift= - low * newhigh / (high-low);
1757     coord= points + dim - 1;
1758     for (i= numpoints; i--; coord += dim)
1759     *coord= *coord * scale + shift;
1760     } /* scalelast */
1761    
1762     /*-<a href="qh-geom.htm#TOC"
1763     >-------------------------------</a><a name="scalepoints">-</a>
1764    
1765     qh_scalepoints( points, numpoints, dim, newlows, newhighs )
1766     scale points to new lowbound and highbound
1767     retains old bound when newlow= -REALmax or newhigh= +REALmax
1768    
1769     returns:
1770     scaled points
1771     overwrites old points
1772    
1773     design:
1774     for each coordinate
1775     compute current low and high bound
1776     compute scale and shift factors
1777     scale all points
1778     enforce new low and high bound for all points
1779     */
1780     void qh_scalepoints (pointT *points, int numpoints, int dim,
1781     realT *newlows, realT *newhighs) {
1782     int i,k;
1783     realT shift, scale, *coord, low, high, newlow, newhigh, mincoord, maxcoord;
1784     boolT nearzero= False;
1785    
1786     for (k= 0; k < dim; k++) {
1787     newhigh= newhighs[k];
1788     newlow= newlows[k];
1789     if (newhigh > REALmax/2 && newlow < -REALmax/2)
1790     continue;
1791     low= REALmax;
1792     high= -REALmax;
1793     for (i= numpoints, coord= points+k; i--; coord += dim) {
1794     minimize_(low, *coord);
1795     maximize_(high, *coord);
1796     }
1797     if (newhigh > REALmax/2)
1798     newhigh= high;
1799     if (newlow < -REALmax/2)
1800     newlow= low;
1801     if (qh DELAUNAY && k == dim-1 && newhigh < newlow) {
1802     fprintf (qh ferr, "qhull input error: 'Qb%d' or 'QB%d' inverts paraboloid since high bound %.2g < low bound %.2g\n",
1803     k, k, newhigh, newlow);
1804     qh_errexit (qh_ERRinput, NULL, NULL);
1805     }
1806     scale= qh_divzero (newhigh - newlow, high - low,
1807     qh MINdenom_1, &nearzero);
1808     if (nearzero) {
1809     fprintf (qh ferr, "qhull input error: %d'th dimension's new bounds [%2.2g, %2.2g] too wide for\nexisting bounds [%2.2g, %2.2g]\n",
1810     k, newlow, newhigh, low, high);
1811     qh_errexit (qh_ERRinput, NULL, NULL);
1812     }
1813     shift= (newlow * high - low * newhigh)/(high-low);
1814     coord= points+k;
1815     for (i= numpoints; i--; coord += dim)
1816     *coord= *coord * scale + shift;
1817     coord= points+k;
1818     if (newlow < newhigh) {
1819     mincoord= newlow;
1820     maxcoord= newhigh;
1821     }else {
1822     mincoord= newhigh;
1823     maxcoord= newlow;
1824     }
1825     for (i= numpoints; i--; coord += dim) {
1826     minimize_(*coord, maxcoord); /* because of roundoff error */
1827     maximize_(*coord, mincoord);
1828     }
1829     trace0((qh ferr, "qh_scalepoints: scaled %d'th coordinate [%2.2g, %2.2g] to [%.2g, %.2g] for %d points by %2.2g and shifted %2.2g\n", k, low, high, newlow, newhigh, numpoints, scale, shift));
1830     }
1831     } /* scalepoints */
1832    
1833    
1834     /*-<a href="qh-geom.htm#TOC"
1835     >-------------------------------</a><a name="setdelaunay">-</a>
1836    
1837     qh_setdelaunay( dim, count, points )
1838     project count points to dim-d paraboloid for Delaunay triangulation
1839    
1840     dim is one more than the dimension of the input set
1841     assumes dim is at least 3 (i.e., at least a 2-d Delaunay triangulation)
1842    
1843     points is a dim*count realT array. The first dim-1 coordinates
1844     are the coordinates of the first input point. array[dim] is
1845     the first coordinate of the second input point. array[2*dim] is
1846     the first coordinate of the third input point.
1847    
1848     if qh.last_low defined (i.e., 'Qbb' called qh_scalelast)
1849     calls qh_scalelast to scale the last coordinate the same as the other points
1850    
1851     returns:
1852     for each point
1853     sets point[dim-1] to sum of squares of coordinates
1854     scale points to 'Qbb' if needed
1855    
1856     notes:
1857     to project one point, use
1858     qh_setdelaunay (qh hull_dim, 1, point)
1859    
1860     Do not use options 'Qbk', 'QBk', or 'QbB' since they scale
1861     the coordinates after the original projection.
1862    
1863     */
1864     void qh_setdelaunay (int dim, int count, pointT *points) {
1865     int i, k;
1866     coordT *coordp, coord;
1867     realT paraboloid;
1868    
1869     trace0((qh ferr, "qh_setdelaunay: project %d points to paraboloid for Delaunay triangulation\n", count));
1870     coordp= points;
1871     for (i= 0; i < count; i++) {
1872     coord= *coordp++;
1873     paraboloid= coord*coord;
1874     for (k= dim-2; k--; ) {
1875     coord= *coordp++;
1876     paraboloid += coord*coord;
1877     }
1878     *coordp++ = paraboloid;
1879     }
1880     if (qh last_low < REALmax/2)
1881     qh_scalelast (points, count, dim, qh last_low, qh last_high, qh last_newhigh);
1882     } /* setdelaunay */
1883    
1884    
1885     /*-<a href="qh-geom.htm#TOC"
1886     >-------------------------------</a><a name="sethalfspace">-</a>
1887    
1888     qh_sethalfspace( dim, coords, nextp, normal, offset, feasible )
1889     set point to dual of halfspace relative to feasible point
1890     halfspace is normal coefficients and offset.
1891    
1892     returns:
1893     false if feasible point is outside of hull (error message already reported)
1894     overwrites coordinates for point at dim coords
1895     nextp= next point (coords)
1896    
1897     design:
1898     compute distance from feasible point to halfspace
1899     divide each normal coefficient by -dist
1900     */
1901     boolT qh_sethalfspace (int dim, coordT *coords, coordT **nextp,
1902     coordT *normal, coordT *offset, coordT *feasible) {
1903     coordT *normp= normal, *feasiblep= feasible, *coordp= coords;
1904     realT dist;
1905     realT r; /*bug fix*/
1906     int k;
1907     boolT zerodiv;
1908    
1909     dist= *offset;
1910     for (k= dim; k--; )
1911     dist += *(normp++) * *(feasiblep++);
1912     if (dist > 0)
1913     goto LABELerroroutside;
1914     normp= normal;
1915     if (dist < -qh MINdenom) {
1916     for (k= dim; k--; )
1917     *(coordp++)= *(normp++) / -dist;
1918     }else {
1919     for (k= dim; k--; ) {
1920     *(coordp++)= qh_divzero (*(normp++), -dist, qh MINdenom_1, &zerodiv);
1921     if (zerodiv)
1922     goto LABELerroroutside;
1923     }
1924     }
1925     *nextp= coordp;
1926     if (qh IStracing >= 4) {
1927     fprintf (qh ferr, "qh_sethalfspace: halfspace at offset %6.2g to point: ", *offset);
1928     for (k= dim, coordp= coords; k--; ) {
1929     r= *coordp++;
1930     fprintf (qh ferr, " %6.2g", r);
1931     }
1932     fprintf (qh ferr, "\n");
1933     }
1934     return True;
1935     LABELerroroutside:
1936     feasiblep= feasible;
1937     normp= normal;
1938     fprintf(qh ferr, "qhull input error: feasible point is not clearly inside halfspace\nfeasible point: ");
1939     for (k= dim; k--; )
1940     fprintf (qh ferr, qh_REAL_1, r=*(feasiblep++));
1941     fprintf (qh ferr, "\n halfspace: ");
1942     for (k= dim; k--; )
1943     fprintf (qh ferr, qh_REAL_1, r=*(normp++));
1944     fprintf (qh ferr, "\n at offset: ");
1945     fprintf (qh ferr, qh_REAL_1, *offset);
1946     fprintf (qh ferr, " and distance: ");
1947     fprintf (qh ferr, qh_REAL_1, dist);
1948     fprintf (qh ferr, "\n");
1949     return False;
1950     } /* sethalfspace */
1951    
1952     /*-<a href="qh-geom.htm#TOC"
1953     >-------------------------------</a><a name="sethalfspace_all">-</a>
1954    
1955     qh_sethalfspace_all( dim, count, halfspaces, feasible )
1956     generate dual for halfspace intersection with feasible point
1957     array of count halfspaces
1958     each halfspace is normal coefficients followed by offset
1959     the origin is inside the halfspace if the offset is negative
1960    
1961     returns:
1962     malloc'd array of count X dim-1 points
1963    
1964     notes:
1965     call before qh_init_B or qh_initqhull_globals
1966     unused/untested code: please email bradb@shore.net if this works ok for you
1967     If using option 'Fp', also set qh feasible_point. It is a malloc'd array
1968     that is freed by qh_freebuffers.
1969    
1970     design:
1971     see qh_sethalfspace
1972     */
1973     coordT *qh_sethalfspace_all (int dim, int count, coordT *halfspaces, pointT *feasible) {
1974     int i, newdim;
1975     pointT *newpoints;
1976     coordT *coordp, *normalp, *offsetp;
1977    
1978     trace0((qh ferr, "qh_sethalfspace_all: compute dual for halfspace intersection\n"));
1979     newdim= dim - 1;
1980     if (!(newpoints=(coordT*)malloc(count*newdim*sizeof(coordT)))){
1981     fprintf(qh ferr, "qhull error: insufficient memory to compute dual of %d halfspaces\n",
1982     count);
1983     qh_errexit(qh_ERRmem, NULL, NULL);
1984     }
1985     coordp= newpoints;
1986     normalp= halfspaces;
1987     for (i= 0; i < count; i++) {
1988     offsetp= normalp + newdim;
1989     if (!qh_sethalfspace (newdim, coordp, &coordp, normalp, offsetp, feasible)) {
1990     fprintf (qh ferr, "The halfspace was at index %d\n", i);
1991     qh_errexit (qh_ERRinput, NULL, NULL);
1992     }
1993     normalp= offsetp + 1;
1994     }
1995     return newpoints;
1996     } /* sethalfspace_all */
1997    
1998    
1999     /*-<a href="qh-geom.htm#TOC"
2000     >-------------------------------</a><a name="sharpnewfacets">-</a>
2001    
2002     qh_sharpnewfacets()
2003    
2004     returns:
2005     true if could be an acute angle (facets in different quadrants)
2006    
2007     notes:
2008     for qh_findbest
2009    
2010     design:
2011     for all facets on qh.newfacet_list
2012     if two facets are in different quadrants
2013     set issharp
2014     */
2015     boolT qh_sharpnewfacets () {
2016     facetT *facet;
2017     boolT issharp = False;
2018     int *quadrant, k;
2019    
2020     quadrant= (int*)qh_memalloc (qh hull_dim * sizeof(int));
2021     FORALLfacet_(qh newfacet_list) {
2022     if (facet == qh newfacet_list) {
2023     for (k= qh hull_dim; k--; )
2024     quadrant[ k]= (facet->normal[ k] > 0);
2025     }else {
2026     for (k= qh hull_dim; k--; ) {
2027     if (quadrant[ k] != (facet->normal[ k] > 0)) {
2028     issharp= True;
2029     break;
2030     }
2031     }
2032     }
2033     if (issharp)
2034     break;
2035     }
2036     qh_memfree( quadrant, qh hull_dim * sizeof(int));
2037     trace3((qh ferr, "qh_sharpnewfacets: %d\n", issharp));
2038     return issharp;
2039     } /* sharpnewfacets */
2040    
2041     /*-<a href="qh-geom.htm#TOC"
2042     >-------------------------------</a><a name="voronoi_center">-</a>
2043    
2044     qh_voronoi_center( dim, points )
2045     return Voronoi center for a set of points
2046     dim is the orginal dimension of the points
2047     gh.gm_matrix/qh.gm_row are scratch buffers
2048    
2049     returns:
2050     center as a temporary point
2051     if non-simplicial,
2052     returns center for max simplex of points
2053    
2054     notes:
2055     from Bowyer & Woodwark, A Programmer's Geometry, 1983, p. 65
2056    
2057     design:
2058     if non-simplicial
2059     determine max simplex for points
2060     translate point0 of simplex to origin
2061     compute sum of squares of diagonal
2062     compute determinate
2063     compute Voronoi center (see Bowyer & Woodwark)
2064     */
2065     pointT *qh_voronoi_center (int dim, setT *points) {
2066     pointT *point, **pointp, *point0;
2067     pointT *center= (pointT*)qh_memalloc (qh center_size);
2068     setT *simplex;
2069     int i, j, k, size= qh_setsize(points);
2070     coordT *gmcoord;
2071     realT *diffp, sum2, *sum2row, *sum2p, det, factor;
2072     boolT nearzero, infinite;
2073    
2074     if (size == dim+1)
2075     simplex= points;
2076     else if (size < dim+1) {
2077     fprintf (qh ferr, "qhull internal error (qh_voronoi_center):\n need at least %d points to construct a Voronoi center\n",
2078     dim+1);
2079     qh_errexit (qh_ERRqhull, NULL, NULL);
2080     }else {
2081     simplex= qh_settemp (dim+1);
2082     qh_maxsimplex (dim, points, NULL, 0, &simplex);
2083     }
2084     point0= SETfirstt_(simplex, pointT);
2085     gmcoord= qh gm_matrix;
2086     for (k=0; k < dim; k++) {
2087     qh gm_row[k]= gmcoord;
2088     FOREACHpoint_(simplex) {
2089     if (point != point0)
2090     *(gmcoord++)= point[k] - point0[k];
2091     }
2092     }
2093     sum2row= gmcoord;
2094     for (i=0; i < dim; i++) {
2095     sum2= 0.0;
2096     for (k= 0; k < dim; k++) {
2097     diffp= qh gm_row[k] + i;
2098     sum2 += *diffp * *diffp;
2099     }
2100     *(gmcoord++)= sum2;
2101     }
2102     det= qh_determinant (qh gm_row, dim, &nearzero);
2103     factor= qh_divzero (0.5, det, qh MINdenom, &infinite);
2104     if (infinite) {
2105     for (k=dim; k--; )
2106     center[k]= qh_INFINITE;
2107     if (qh IStracing)
2108     qh_printpoints (qh ferr, "qh_voronoi_center: at infinity for ", simplex);
2109     }else {
2110     for (i=0; i < dim; i++) {
2111     gmcoord= qh gm_matrix;
2112     sum2p= sum2row;
2113     for (k=0; k < dim; k++) {
2114     qh gm_row[k]= gmcoord;
2115     if (k == i) {
2116     for (j= dim; j--; )
2117     *(gmcoord++)= *sum2p++;
2118     }else {
2119     FOREACHpoint_(simplex) {
2120     if (point != point0)
2121     *(gmcoord++)= point[k] - point0[k];
2122     }
2123     }
2124     }
2125     center[i]= qh_determinant (qh gm_row, dim, &nearzero)*factor + point0[i];
2126     }
2127     #ifndef qh_NOtrace
2128     if (qh IStracing >= 3) {
2129     fprintf (qh ferr, "qh_voronoi_center: det %2.2g factor %2.2g ", det, factor);
2130     qh_printmatrix (qh ferr, "center:", &center, 1, dim);
2131     if (qh IStracing >= 5) {
2132     qh_printpoints (qh ferr, "points", simplex);
2133     FOREACHpoint_(simplex)
2134     fprintf (qh ferr, "p%d dist %.2g, ", qh_pointid (point),
2135     qh_pointdist (point, center, dim));
2136     fprintf (qh ferr, "\n");
2137     }
2138     }
2139     #endif
2140     }
2141     if (simplex != points)
2142     qh_settempfree (&simplex);
2143     return center;
2144     } /* voronoi_center */
2145