1
/*<html><pre> -<a href="qh-geom.htm"
2
>-------------------------------</a><a name="TOP">-</a>
6
infrequently used geometric routines of qhull
8
see qh-geom.htm and geom.h
10
copyright (c) 1993-2003 The Geometry Center
12
frequently used code goes into geom.c
17
/*================== functions in alphabetic order ============*/
19
/*-<a href="qh-geom.htm#TOC"
20
>-------------------------------</a><a name="copypoints">-</a>
22
qh_copypoints( points, numpoints, dimension)
23
return malloc'd copy of points
25
coordT *qh_copypoints (coordT *points, int numpoints, int dimension) {
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",
33
qh_errexit(qh_ERRmem, NULL, NULL);
35
memcpy ((char *)newpoints, (char *)points, size);
39
/*-<a href="qh-geom.htm#TOC"
40
>-------------------------------</a><a name="crossproduct">-</a>
42
qh_crossproduct( dim, vecA, vecB, vecC )
43
crossproduct of 2 dim vectors
47
from Glasner, Graphics Gems I, p. 639
48
only defined for dim==3
50
void qh_crossproduct (int dim, realT vecA[3], realT vecB[3], realT vecC[3]){
53
vecC[0]= det2_(vecA[1], vecA[2],
55
vecC[1]= - det2_(vecA[0], vecA[2],
57
vecC[2]= det2_(vecA[0], vecA[1],
62
/*-<a href="qh-geom.htm#TOC"
63
>-------------------------------</a><a name="determinant">-</a>
65
qh_determinant( rows, dim, nearzero )
66
compute signed determinant of a square matrix
67
uses qh.NEARzero to test for degenerate matrices
71
overwrites rows and the matrix
73
nearzero iff determinant < qh NEARzero[dim-1]
74
(not quite correct, not critical)
76
nearzero iff diagonal[k] < qh NEARzero[k]
78
realT qh_determinant (realT **rows, int dim, boolT *nearzero) {
85
fprintf (qh ferr, "qhull internal error (qh_determinate): only implemented for dimension >= 2\n");
86
qh_errexit (qh_ERRqhull, NULL, NULL);
88
det= det2_(rows[0][0], rows[0][1],
89
rows[1][0], rows[1][1]);
90
if (fabs_(det) < qh NEARzero[1]) /* not really correct, what should this be? */
93
det= det3_(rows[0][0], rows[0][1], rows[0][2],
94
rows[1][0], rows[1][1], rows[1][2],
95
rows[2][0], rows[2][1], rows[2][2]);
96
if (fabs_(det) < qh NEARzero[2]) /* not really correct, what should this be? */
99
qh_gausselim(rows, dim, dim, &sign, nearzero); /* if nearzero, diagonal still ok*/
109
/*-<a href="qh-geom.htm#TOC"
110
>-------------------------------</a><a name="detjoggle">-</a>
112
qh_detjoggle( points, numpoints, dimension )
113
determine default max joggle for point array
114
as qh_distround * qh_JOGGLEdefault
117
initial value for JOGGLEmax from points and REALepsilon
120
computes DISTround since qh_maxmin not called yet
121
if qh SCALElast, last dimension will be scaled later to MAXwidth
123
loop duplicated from qh_maxmin
125
realT qh_detjoggle (pointT *points, int numpoints, int dimension) {
126
realT abscoord, distround, joggle, maxcoord, mincoord;
127
pointT *point, *pointtemp;
128
realT maxabs= -REALmax;
133
for (k= 0; k < dimension; k++) {
134
if (qh SCALElast && k == dimension-1)
136
else if (qh DELAUNAY && k == dimension-1) /* will qh_setdelaunay() */
137
abscoord= 2 * maxabs * maxabs; /* may be low by qh hull_dim/2 */
141
FORALLpoint_(points, numpoints) {
142
maximize_(maxcoord, point[k]);
143
minimize_(mincoord, point[k]);
145
maximize_(maxwidth, maxcoord-mincoord);
146
abscoord= fmax_(maxcoord, -mincoord);
149
maximize_(maxabs, abscoord);
151
distround= qh_distround (qh hull_dim, maxabs, sumabs);
152
joggle= distround * qh_JOGGLEdefault;
153
maximize_(joggle, REALepsilon * qh_JOGGLEdefault);
154
trace2((qh ferr, "qh_detjoggle: joggle=%2.2g maxwidth=%2.2g\n", joggle, maxwidth));
158
/*-<a href="qh-geom.htm#TOC"
159
>-------------------------------</a><a name="detroundoff">-</a>
162
determine maximum roundoff errors from
163
REALepsilon, REALmax, REALmin, qh.hull_dim, qh.MAXabs_coord,
164
qh.MAXsumcoord, qh.MAXwidth, qh.MINdenom_1
166
accounts for qh.SETroundoff, qh.RANDOMdist, qh MERGEexact
167
qh.premerge_cos, qh.postmerge_cos, qh.premerge_centrum,
168
qh.postmerge_centrum, qh.MINoutside,
169
qh_RATIOnearinside, qh_COPLANARratio, qh_WIDEcoplanar
172
sets qh.DISTround, etc. (see below)
173
appends precision constants to qh.qhull_options
176
qh_maxmin() for qh.NEARzero
179
determine qh.DISTround for distance computations
180
determine minimum denominators for qh_divzero
181
determine qh.ANGLEround for angle computations
182
adjust qh.premerge_cos,... for roundoff error
183
determine qh.ONEmerge for maximum error due to a single merge
184
determine qh.NEARinside, qh.MAXcoplanar, qh.MINvisible,
185
qh.MINoutside, qh.WIDEfacet
186
initialize qh.max_vertex and qh.minvertex
188
void qh_detroundoff (void) {
190
qh_option ("_max-width", NULL, &qh MAXwidth);
191
if (!qh SETroundoff) {
192
qh DISTround= qh_distround (qh hull_dim, qh MAXabs_coord, qh MAXsumcoord);
194
qh DISTround += qh RANDOMfactor * qh MAXabs_coord;
195
qh_option ("Error-roundoff", NULL, &qh DISTround);
197
qh MINdenom= qh MINdenom_1 * qh MAXabs_coord;
198
qh MINdenom_1_2= sqrt (qh MINdenom_1 * qh hull_dim) ; /* if will be normalized */
199
qh MINdenom_2= qh MINdenom_1_2 * qh MAXabs_coord;
200
/* for inner product */
201
qh ANGLEround= 1.01 * qh hull_dim * REALepsilon;
203
qh ANGLEround += qh RANDOMfactor;
204
if (qh premerge_cos < REALmax/2) {
205
qh premerge_cos -= qh ANGLEround;
207
qh_option ("Angle-premerge-with-random", NULL, &qh premerge_cos);
209
if (qh postmerge_cos < REALmax/2) {
210
qh postmerge_cos -= qh ANGLEround;
212
qh_option ("Angle-postmerge-with-random", NULL, &qh postmerge_cos);
214
qh premerge_centrum += 2 * qh DISTround; /*2 for centrum and distplane()*/
215
qh postmerge_centrum += 2 * qh DISTround;
216
if (qh RANDOMdist && (qh MERGEexact || qh PREmerge))
217
qh_option ("Centrum-premerge-with-random", NULL, &qh premerge_centrum);
218
if (qh RANDOMdist && qh POSTmerge)
219
qh_option ("Centrum-postmerge-with-random", NULL, &qh postmerge_centrum);
220
{ /* compute ONEmerge, max vertex offset for merging simplicial facets */
221
realT maxangle= 1.0, maxrho;
223
minimize_(maxangle, qh premerge_cos);
224
minimize_(maxangle, qh postmerge_cos);
225
/* max diameter * sin theta + DISTround for vertex to its hyperplane */
226
qh ONEmerge= sqrt (qh hull_dim) * qh MAXwidth *
227
sqrt (1.0 - maxangle * maxangle) + qh DISTround;
228
maxrho= qh hull_dim * qh premerge_centrum + qh DISTround;
229
maximize_(qh ONEmerge, maxrho);
230
maxrho= qh hull_dim * qh postmerge_centrum + qh DISTround;
231
maximize_(qh ONEmerge, maxrho);
233
qh_option ("_one-merge", NULL, &qh ONEmerge);
235
qh NEARinside= qh ONEmerge * qh_RATIOnearinside; /* only used if qh KEEPnearinside */
236
if (qh JOGGLEmax < REALmax/2 && (qh KEEPcoplanar || qh KEEPinside)) {
237
realT maxdist; /* adjust qh.NEARinside for joggle */
238
qh KEEPnearinside= True;
239
maxdist= sqrt (qh hull_dim) * qh JOGGLEmax + qh DISTround;
240
maxdist= 2*maxdist; /* vertex and coplanar point can joggle in opposite directions */
241
maximize_(qh NEARinside, maxdist); /* must agree with qh_nearcoplanar() */
243
if (qh KEEPnearinside)
244
qh_option ("_near-inside", NULL, &qh NEARinside);
245
if (qh JOGGLEmax < qh DISTround) {
246
fprintf (qh ferr, "qhull error: the joggle for 'QJn', %.2g, is below roundoff for distance computations, %.2g\n",
247
qh JOGGLEmax, qh DISTround);
248
qh_errexit (qh_ERRinput, NULL, NULL);
250
if (qh MINvisible > REALmax/2) {
252
qh MINvisible= qh DISTround;
253
else if (qh hull_dim <= 3)
254
qh MINvisible= qh premerge_centrum;
256
qh MINvisible= qh_COPLANARratio * qh premerge_centrum;
257
if (qh APPROXhull && qh MINvisible > qh MINoutside)
258
qh MINvisible= qh MINoutside;
259
qh_option ("Visible-distance", NULL, &qh MINvisible);
261
if (qh MAXcoplanar > REALmax/2) {
262
qh MAXcoplanar= qh MINvisible;
263
qh_option ("U-coplanar-distance", NULL, &qh MAXcoplanar);
265
if (!qh APPROXhull) { /* user may specify qh MINoutside */
266
qh MINoutside= 2 * qh MINvisible;
267
if (qh premerge_cos < REALmax/2)
268
maximize_(qh MINoutside, (1- qh premerge_cos) * qh MAXabs_coord);
269
qh_option ("Width-outside", NULL, &qh MINoutside);
271
qh WIDEfacet= qh MINoutside;
272
maximize_(qh WIDEfacet, qh_WIDEcoplanar * qh MAXcoplanar);
273
maximize_(qh WIDEfacet, qh_WIDEcoplanar * qh MINvisible);
274
qh_option ("_wide-facet", NULL, &qh WIDEfacet);
275
if (qh MINvisible > qh MINoutside + 3 * REALepsilon
276
&& !qh BESToutside && !qh FORCEoutput)
277
fprintf (qh ferr, "qhull input warning: minimum visibility V%.2g is greater than \nminimum outside W%.2g. Flipped facets are likely.\n",
278
qh MINvisible, qh MINoutside);
279
qh max_vertex= qh DISTround;
280
qh min_vertex= -qh DISTround;
281
/* numeric constants reported in printsummary */
284
/*-<a href="qh-geom.htm#TOC"
285
>-------------------------------</a><a name="detsimplex">-</a>
287
qh_detsimplex( apex, points, dim, nearzero )
288
compute determinant of a simplex with point apex and base points
291
signed determinant and nearzero from qh_determinant
294
uses qh.gm_matrix/qh.gm_row (assumes they're big enough)
297
construct qm_matrix by subtracting apex from points
300
realT qh_detsimplex(pointT *apex, setT *points, int dim, boolT *nearzero) {
301
pointT *coorda, *coordp, *gmcoord, *point, **pointp;
307
gmcoord= qh gm_matrix;
309
FOREACHpoint_(points) {
316
*(gmcoord++)= *coordp++ - *coorda++;
319
fprintf (qh ferr, "qhull internal error (qh_detsimplex): #points %d < dimension %d\n",
321
qh_errexit (qh_ERRqhull, NULL, NULL);
323
det= qh_determinant (rows, dim, nearzero);
324
trace2((qh ferr, "qh_detsimplex: det=%2.2g for point p%d, dim %d, nearzero? %d\n",
325
det, qh_pointid(apex), dim, *nearzero));
329
/*-<a href="qh-geom.htm#TOC"
330
>-------------------------------</a><a name="distnorm">-</a>
332
qh_distnorm( dim, point, normal, offset )
333
return distance from point to hyperplane at normal/offset
339
dist > 0 if point is outside of hyperplane
342
qh_distplane in geom.c
344
realT qh_distnorm (int dim, pointT *point, pointT *normal, realT *offsetp) {
345
coordT *normalp= normal, *coordp= point;
351
dist += *(coordp++) * *(normalp++);
355
/*-<a href="qh-geom.htm#TOC"
356
>-------------------------------</a><a name="distround">-</a>
358
qh_distround ( dimension, maxabs, maxsumabs )
359
compute maximum round-off error for a distance computation
360
to a normalized hyperplane
361
maxabs is the maximum absolute value of a coordinate
362
maxsumabs is the maximum possible sum of absolute coordinate values
365
max dist round for REALepsilon
368
calculate roundoff error according to
369
Lemma 3.2-1 of Golub and van Loan "Matrix Computation"
370
use sqrt(dim) since one vector is normalized
371
or use maxsumabs since one vector is < 1
373
realT qh_distround (int dimension, realT maxabs, realT maxsumabs) {
374
realT maxdistsum, maxround;
376
maxdistsum= sqrt (dimension) * maxabs;
377
minimize_( maxdistsum, maxsumabs);
378
maxround= REALepsilon * (dimension * maxdistsum * 1.01 + maxabs);
379
/* adds maxabs for offset */
380
trace4((qh ferr, "qh_distround: %2.2g maxabs %2.2g maxsumabs %2.2g maxdistsum %2.2g\n",
381
maxround, maxabs, maxsumabs, maxdistsum));
385
/*-<a href="qh-geom.htm#TOC"
386
>-------------------------------</a><a name="divzero">-</a>
388
qh_divzero( numer, denom, mindenom1, zerodiv )
389
divide by a number that's nearly zero
390
mindenom1= minimum denominator for dividing into 1.0
394
sets zerodiv and returns 0.0 if it would overflow
397
if numer is nearly zero and abs(numer) < abs(denom)
399
else if numer is nearly zero
401
else if denom/numer non-zero
406
realT qh_divzero (realT numer, realT denom, realT mindenom1, boolT *zerodiv) {
407
realT temp, numerx, denomx;
410
if (numer < mindenom1 && numer > -mindenom1) {
411
numerx= fabs_(numer);
412
denomx= fabs_(denom);
413
if (numerx < denomx) {
422
if (temp > mindenom1 || temp < -mindenom1) {
432
/*-<a href="qh-geom.htm#TOC"
433
>-------------------------------</a><a name="facetarea">-</a>
435
qh_facetarea( facet )
436
return area for a facet
440
uses centrum to triangulate facet and sums the projected areas.
442
computes projected area instead for last coordinate
443
assumes facet->normal exists
444
projecting tricoplanar facets to the hyperplane does not appear to make a difference
451
compute area from centrum to ridge
452
negate area if upper Delaunay facet
454
realT qh_facetarea (facetT *facet) {
458
ridgeT *ridge, **ridgep;
460
if (facet->simplicial) {
461
apex= SETfirstt_(facet->vertices, vertexT);
462
area= qh_facetarea_simplex (qh hull_dim, apex->point, facet->vertices,
463
apex, facet->toporient, facet->normal, &facet->offset);
465
if (qh CENTERtype == qh_AScentrum)
466
centrum= facet->center;
468
centrum= qh_getcentrum (facet);
469
FOREACHridge_(facet->ridges)
470
area += qh_facetarea_simplex (qh hull_dim, centrum, ridge->vertices,
471
NULL, (ridge->top == facet), facet->normal, &facet->offset);
472
if (qh CENTERtype != qh_AScentrum)
473
qh_memfree (centrum, qh normal_size);
475
if (facet->upperdelaunay && qh DELAUNAY)
476
area= -area; /* the normal should be [0,...,1] */
477
trace4((qh ferr, "qh_facetarea: f%d area %2.2g\n", facet->id, area));
481
/*-<a href="qh-geom.htm#TOC"
482
>-------------------------------</a><a name="facetarea_simplex">-</a>
484
qh_facetarea_simplex( dim, apex, vertices, notvertex, toporient, normal, offset )
485
return area for a simplex defined by
486
an apex, a base of vertices, an orientation, and a unit normal
487
if simplicial or tricoplanar facet,
488
notvertex is defined and it is skipped in vertices
491
computes area of simplex projected to plane [normal,offset]
492
returns 0 if vertex too far below plane (qh WIDEfacet)
493
vertex can't be apex of tricoplanar facet
497
computes projected area instead for last coordinate
498
uses qh gm_matrix/gm_row and qh hull_dim
499
helper function for qh_facetarea
503
translate simplex to apex
505
project simplex to normal/offset
506
translate simplex to apex
508
set last row/column to 0 with -1 on diagonal
510
set last row to Normal
512
scale and flip sign for area
514
realT qh_facetarea_simplex (int dim, coordT *apex, setT *vertices,
515
vertexT *notvertex, boolT toporient, coordT *normal, realT *offset) {
516
pointT *coorda, *coordp, *gmcoord;
517
coordT **rows, *normalp;
520
vertexT *vertex, **vertexp;
523
gmcoord= qh gm_matrix;
525
FOREACHvertex_(vertices) {
526
if (vertex == notvertex)
530
coordp= vertex->point;
534
*(gmcoord++)= *coordp++ - *coorda++;
538
dist += *coordp++ * *normalp++;
539
if (dist < -qh WIDEfacet) {
543
coordp= vertex->point;
546
*(gmcoord++)= (*coordp++ - dist * *normalp++) - *coorda++;
550
fprintf (qh ferr, "qhull internal error (qh_facetarea_simplex): #points %d != dim %d -1\n",
552
qh_errexit (qh_ERRqhull, NULL, NULL);
556
for (i= 0; i < dim-1; i++)
560
rows[dim-1][dim-1]= -1.0;
564
*(gmcoord++)= *normalp++;
567
area= qh_determinant (rows, dim, &nearzero);
570
area *= qh AREAfactor;
571
trace4((qh ferr, "qh_facetarea_simplex: area=%2.2g for point p%d, toporient %d, nearzero? %d\n",
572
area, qh_pointid(apex), toporient, nearzero));
574
} /* facetarea_simplex */
576
/*-<a href="qh-geom.htm#TOC"
577
>-------------------------------</a><a name="facetcenter">-</a>
579
qh_facetcenter( vertices )
580
return Voronoi center (Voronoi vertex) for a facet's vertices
583
return temporary point equal to the center
588
pointT *qh_facetcenter (setT *vertices) {
589
setT *points= qh_settemp (qh_setsize (vertices));
590
vertexT *vertex, **vertexp;
593
FOREACHvertex_(vertices)
594
qh_setappend (&points, vertex->point);
595
center= qh_voronoi_center (qh hull_dim-1, points);
596
qh_settempfree (&points);
600
/*-<a href="qh-geom.htm#TOC"
601
>-------------------------------</a><a name="findgooddist">-</a>
603
qh_findgooddist( point, facetA, dist, facetlist )
604
find best good facet visible for point from facetA
605
assumes facetA is visible from point
608
best facet, i.e., good facet that is furthest from point
609
distance to best facet
612
moves good, visible facets (and some other visible facets)
613
to end of qh facet_list
619
initialize bestfacet if facetA is good
620
move facetA to end of facetlist
621
for each facet on facetlist
622
for each unvisited neighbor of facet
623
move visible neighbors to end of facetlist
624
update best good neighbor
625
if no good neighbors, update best facet
627
facetT *qh_findgooddist (pointT *point, facetT *facetA, realT *distp,
628
facetT **facetlist) {
629
realT bestdist= -REALmax, dist;
630
facetT *neighbor, **neighborp, *bestfacet=NULL, *facet;
631
boolT goodseen= False;
634
zinc_(Zcheckpart); /* calls from check_bestdist occur after print stats */
635
qh_distplane (point, facetA, &bestdist);
639
qh_removefacet (facetA);
640
qh_appendfacet (facetA);
642
facetA->visitid= ++qh visit_id;
643
FORALLfacet_(*facetlist) {
644
FOREACHneighbor_(facet) {
645
if (neighbor->visitid == qh visit_id)
647
neighbor->visitid= qh visit_id;
648
if (goodseen && !neighbor->good)
651
qh_distplane (point, neighbor, &dist);
653
qh_removefacet (neighbor);
654
qh_appendfacet (neighbor);
655
if (neighbor->good) {
657
if (dist > bestdist) {
667
trace2((qh ferr, "qh_findgooddist: p%d is %2.2g above good facet f%d\n",
668
qh_pointid(point), bestdist, bestfacet->id));
671
trace4((qh ferr, "qh_findgooddist: no good facet for p%d above f%d\n",
672
qh_pointid(point), facetA->id));
676
/*-<a href="qh-geom.htm#TOC"
677
>-------------------------------</a><a name="getarea">-</a>
679
qh_getarea( facetlist )
680
set area of all facets in facetlist
684
sets qh totarea/totvol to total area and volume of convex hull
685
for Delaunay triangulation, computes projected area of the lower or upper hull
686
ignores upper hull if qh ATinfinity
689
could compute outer volume by expanding facet area by rays from interior
690
the following attempt at perpendicular projection underestimated badly:
691
qh.totoutvol += (-dist + facet->maxoutside + qh DISTround)
694
for each facet on facetlist
696
update qh.totarea and qh.totvol
698
void qh_getarea (facetT *facetlist) {
704
fprintf (qh ferr, "computing area of each facet and volume of the convex hull\n");
706
trace1((qh ferr, "qh_getarea: computing volume and area for each facet\n"));
707
qh totarea= qh totvol= 0.0;
708
FORALLfacet_(facetlist) {
711
if (facet->upperdelaunay && qh ATinfinity)
713
facet->f.area= area= qh_facetarea (facet);
716
if (facet->upperdelaunay == qh UPPERdelaunay)
720
qh_distplane (qh interior_point, facet, &dist);
721
qh totvol += -dist * area/ qh hull_dim;
723
if (qh PRINTstatistics) {
724
wadd_(Wareatot, area);
725
wmax_(Wareamax, area);
726
wmin_(Wareamin, area);
731
/*-<a href="qh-geom.htm#TOC"
732
>-------------------------------</a><a name="gram_schmidt">-</a>
734
qh_gram_schmidt( dim, row )
735
implements Gram-Schmidt orthogonalization by rows
739
overwrites rows[dim][dim]
742
see Golub & van Loan Algorithm 6.2-2
743
overflow due to small divisors not handled
748
if non-zero, normalize row
749
for each remaining rowA
750
compute inner product of row and rowA
751
reduce rowA by row * inner product
753
boolT qh_gram_schmidt(int dim, realT **row) {
754
realT *rowi, *rowj, norm;
757
for(i=0; i < dim; i++) {
759
for (norm= 0.0, k= dim; k--; rowi++)
760
norm += *rowi * *rowi;
762
wmin_(Wmindenom, norm);
763
if (norm == 0.0) /* either 0 or overflow due to sqrt */
767
for(j= i+1; j < dim; j++) {
769
for(norm= 0.0, k=dim; k--; )
770
norm += *rowi++ * *rowj++;
772
*(--rowj) -= *(--rowi) * norm;
779
/*-<a href="qh-geom.htm#TOC"
780
>-------------------------------</a><a name="inthresholds">-</a>
782
qh_inthresholds( normal, angle )
783
return True if normal within qh.lower_/upper_threshold
786
estimate of angle by summing of threshold diffs
788
smaller "angle" is better
791
invalid if qh.SPLITthresholds
794
qh.lower_threshold in qh_initbuild()
801
boolT qh_inthresholds (coordT *normal, realT *angle) {
808
for(k= 0; k < qh hull_dim; k++) {
809
threshold= qh lower_threshold[k];
810
if (threshold > -REALmax/2) {
811
if (normal[k] < threshold)
814
threshold -= normal[k];
815
*angle += fabs_(threshold);
818
if (qh upper_threshold[k] < REALmax/2) {
819
threshold= qh upper_threshold[k];
820
if (normal[k] > threshold)
823
threshold -= normal[k];
824
*angle += fabs_(threshold);
832
/*-<a href="qh-geom.htm#TOC"
833
>-------------------------------</a><a name="joggleinput">-</a>
836
randomly joggle input to Qhull by qh.JOGGLEmax
837
initial input is qh.first_point/qh.num_points of qh.hull_dim
838
repeated calls use qh.input_points/qh.num_points
841
joggles points at qh.first_point/qh.num_points
842
copies data to qh.input_points/qh.input_malloc if first time
843
determines qh.JOGGLEmax if it was zero
845
computes the Delaunay projection of the joggled points
848
if qh.DELAUNAY, unnecessarily joggles the last coordinate
849
the initial 'QJn' may be set larger than qh_JOGGLEmaxincrease
853
set qh.SCALElast for reduced precision errors
855
initialize qh.input_points to the original input points
857
determine default qh.JOGGLEmax
859
increase qh.JOGGLEmax according to qh.build_cnt
860
joggle the input by adding a random number in [-qh.JOGGLEmax,qh.JOGGLEmax]
862
sets the Delaunay projection
864
void qh_joggleinput (void) {
866
coordT *coordp, *inputp;
867
realT randr, randa, randb;
869
if (!qh input_points) { /* first call */
870
qh input_points= qh first_point;
871
qh input_malloc= qh POINTSmalloc;
872
size= qh num_points * qh hull_dim * sizeof(coordT);
873
if (!(qh first_point=(coordT*)malloc(size))) {
874
fprintf(qh ferr, "qhull error: insufficient memory to joggle %d points\n",
876
qh_errexit(qh_ERRmem, NULL, NULL);
878
qh POINTSmalloc= True;
879
if (qh JOGGLEmax == 0.0) {
880
qh JOGGLEmax= qh_detjoggle (qh input_points, qh num_points, qh hull_dim);
881
qh_option ("QJoggle", NULL, &qh JOGGLEmax);
883
}else { /* repeated call */
884
if (!qh RERUN && qh build_cnt > qh_JOGGLEretry) {
885
if (((qh build_cnt-qh_JOGGLEretry-1) % qh_JOGGLEagain) == 0) {
886
realT maxjoggle= qh MAXwidth * qh_JOGGLEmaxincrease;
887
if (qh JOGGLEmax < maxjoggle) {
888
qh JOGGLEmax *= qh_JOGGLEincrease;
889
minimize_(qh JOGGLEmax, maxjoggle);
893
qh_option ("QJoggle", NULL, &qh JOGGLEmax);
895
if (qh build_cnt > 1 && qh JOGGLEmax > fmax_(qh MAXwidth/4, 0.1)) {
896
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",
898
qh_errexit (qh_ERRqhull, NULL, NULL);
900
/* for some reason, using qh ROTATErandom and qh_RANDOMseed does not repeat the run. Use 'TRn' instead */
902
qh_option ("_joggle-seed", &seed, NULL);
903
trace0((qh ferr, "qh_joggleinput: joggle input by %2.2g with seed %d\n",
904
qh JOGGLEmax, seed));
905
inputp= qh input_points;
906
coordp= qh first_point;
907
randa= 2.0 * qh JOGGLEmax/qh_RANDOMmax;
908
randb= -qh JOGGLEmax;
909
size= qh num_points * qh hull_dim;
910
for (i= size; i--; ) {
912
*(coordp++)= *(inputp++) + (randr * randa + randb);
915
qh last_low= qh last_high= qh last_newhigh= REALmax;
916
qh_setdelaunay (qh hull_dim, qh num_points, qh first_point);
920
/*-<a href="qh-geom.htm#TOC"
921
>-------------------------------</a><a name="maxabsval">-</a>
923
qh_maxabsval( normal, dim )
924
return pointer to maximum absolute value of a dim vector
925
returns NULL if dim=0
927
realT *qh_maxabsval (realT *normal, int dim) {
928
realT maxval= -REALmax;
929
realT *maxp= NULL, *colp, absval;
932
for (k= dim, colp= normal; k--; colp++) {
933
absval= fabs_(*colp);
934
if (absval > maxval) {
943
/*-<a href="qh-geom.htm#TOC"
944
>-------------------------------</a><a name="maxmin">-</a>
946
qh_maxmin( points, numpoints, dimension )
947
return max/min points for each dimension
948
determine max and min coordinates
951
returns a temporary set of max and min points
952
may include duplicate points. Does not include qh.GOODpoint
953
sets qh.NEARzero, qh.MAXabs_coord, qh.MAXsumcoord, qh.MAXwidth
954
qh.MAXlastcoord, qh.MINlastcoord
955
initializes qh.max_outside, qh.min_vertex, qh.WAScoplanar, qh.ZEROall_ok
958
loop duplicated in qh_detjoggle()
961
initialize global precision variables
962
checks definition of REAL...
965
collect maximum and minimum point
966
collect maximum of maximums and minimum of minimums
967
determine qh.NEARzero for Gaussian Elimination
969
setT *qh_maxmin(pointT *points, int numpoints, int dimension) {
971
realT maxcoord, temp;
972
pointT *minimum, *maximum, *point, *pointtemp;
976
qh MAXabs_coord= 0.0;
977
qh MAXwidth= -REALmax;
980
qh WAScoplanar= False;
983
if (REALmin < REALepsilon && REALmin < REALmax && REALmin > -REALmax
984
&& REALmax > 0.0 && -REALmax < 0.0)
987
fprintf (qh ferr, "qhull error: floating point constants in user.h are wrong\n\
988
REALepsilon %g REALmin %g REALmax %g -REALmax %g\n",
989
REALepsilon, REALmin, REALmax, -REALmax);
990
qh_errexit (qh_ERRinput, NULL, NULL);
992
set= qh_settemp(2*dimension);
993
for(k= 0; k < dimension; k++) {
994
if (points == qh GOODpointp)
995
minimum= maximum= points + dimension;
997
minimum= maximum= points;
998
FORALLpoint_(points, numpoints) {
999
if (point == qh GOODpointp)
1001
if (maximum[k] < point[k])
1003
else if (minimum[k] > point[k])
1006
if (k == dimension-1) {
1007
qh MINlastcoord= minimum[k];
1008
qh MAXlastcoord= maximum[k];
1010
if (qh SCALElast && k == dimension-1)
1011
maxcoord= qh MAXwidth;
1013
maxcoord= fmax_(maximum[k], -minimum[k]);
1014
if (qh GOODpointp) {
1015
temp= fmax_(qh GOODpointp[k], -qh GOODpointp[k]);
1016
maximize_(maxcoord, temp);
1018
temp= maximum[k] - minimum[k];
1019
maximize_(qh MAXwidth, temp);
1021
maximize_(qh MAXabs_coord, maxcoord);
1022
qh MAXsumcoord += maxcoord;
1023
qh_setappend (&set, maximum);
1024
qh_setappend (&set, minimum);
1025
/* calculation of qh NEARzero is based on error formula 4.4-13 of
1026
Golub & van Loan, authors say n^3 can be ignored and 10 be used in
1028
qh NEARzero[k]= 80 * qh MAXsumcoord * REALepsilon;
1030
if (qh IStracing >=1)
1031
qh_printpoints (qh ferr, "qh_maxmin: found the max and min points (by dim):", set);
1035
/*-<a href="qh-geom.htm#TOC"
1036
>-------------------------------</a><a name="maxouter">-</a>
1039
return maximum distance from facet to outer plane
1040
normally this is qh.max_outside+qh.DISTround
1041
does not include qh.JOGGLEmax
1047
need to add another qh.DISTround if testing actual point with computation
1050
qh_setfacetplane() updated qh.max_outer for Wnewvertexmax (max distance to vertex)
1051
need to use Wnewvertexmax since could have a coplanar point for a high
1052
facet that is replaced by a low facet
1053
need to add qh.JOGGLEmax if testing input points
1055
realT qh_maxouter (void) {
1058
dist= fmax_(qh max_outside, qh DISTround);
1059
dist += qh DISTround;
1060
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));
1064
/*-<a href="qh-geom.htm#TOC"
1065
>-------------------------------</a><a name="maxsimplex">-</a>
1067
qh_maxsimplex( dim, maxpoints, points, numpoints, simplex )
1068
determines maximum simplex for a set of points
1069
starts from points already in simplex
1070
skips qh.GOODpointp (assumes that it isn't in maxpoints)
1073
simplex with dim+1 points
1076
assumes at least pointsneeded points in points
1077
maximizes determinate for x,y,z,w, etc.
1078
uses maxpoints as long as determinate is clearly non-zero
1081
initialize simplex with at least two points
1082
(find points with max or min x coordinate)
1083
for each remaining dimension
1084
add point that maximizes the determinate
1085
(use points from maxpoints first)
1087
void qh_maxsimplex (int dim, setT *maxpoints, pointT *points, int numpoints, setT **simplex) {
1088
pointT *point, **pointp, *pointtemp, *maxpoint, *minx=NULL, *maxx=NULL;
1089
boolT nearzero, maxnearzero= False;
1091
realT maxdet= -REALmax, det, mincoord= REALmax, maxcoord= -REALmax;
1093
sizinit= qh_setsize (*simplex);
1095
if (qh_setsize (maxpoints) >= 2) {
1096
FOREACHpoint_(maxpoints) {
1097
if (maxcoord < point[0]) {
1101
if (mincoord > point[0]) {
1107
FORALLpoint_(points, numpoints) {
1108
if (point == qh GOODpointp)
1110
if (maxcoord < point[0]) {
1114
if (mincoord > point[0]) {
1120
qh_setunique (simplex, minx);
1121
if (qh_setsize (*simplex) < 2)
1122
qh_setunique (simplex, maxx);
1123
sizinit= qh_setsize (*simplex);
1125
qh_precision ("input has same x coordinate");
1126
if (zzval_(Zsetplane) > qh hull_dim+1) {
1127
fprintf (qh ferr, "qhull precision error (qh_maxsimplex for voronoi_center):\n%d points with the same x coordinate.\n",
1128
qh_setsize(maxpoints)+numpoints);
1129
qh_errexit (qh_ERRprec, NULL, NULL);
1131
fprintf (qh ferr, "qhull input error: input is less than %d-dimensional since it has the same x coordinate\n", qh hull_dim);
1132
qh_errexit (qh_ERRinput, NULL, NULL);
1136
for(k= sizinit; k < dim+1; k++) {
1139
FOREACHpoint_(maxpoints) {
1140
if (!qh_setin (*simplex, point)) {
1141
det= qh_detsimplex(point, *simplex, k, &nearzero);
1142
if ((det= fabs_(det)) > maxdet) {
1145
maxnearzero= nearzero;
1149
if (!maxpoint || maxnearzero) {
1150
zinc_(Zsearchpoints);
1152
trace0((qh ferr, "qh_maxsimplex: searching all points for %d-th initial vertex.\n", k+1));
1154
trace0((qh ferr, "qh_maxsimplex: searching all points for %d-th initial vertex, better than p%d det %2.2g\n",
1155
k+1, qh_pointid(maxpoint), maxdet));
1157
FORALLpoint_(points, numpoints) {
1158
if (point == qh GOODpointp)
1160
if (!qh_setin (*simplex, point)) {
1161
det= qh_detsimplex(point, *simplex, k, &nearzero);
1162
if ((det= fabs_(det)) > maxdet) {
1165
maxnearzero= nearzero;
1171
fprintf (qh ferr, "qhull internal error (qh_maxsimplex): not enough points available\n");
1172
qh_errexit (qh_ERRqhull, NULL, NULL);
1174
qh_setappend(simplex, maxpoint);
1175
trace1((qh ferr, "qh_maxsimplex: selected point p%d for %d`th initial vertex, det=%2.2g\n",
1176
qh_pointid(maxpoint), k+1, maxdet));
1180
/*-<a href="qh-geom.htm#TOC"
1181
>-------------------------------</a><a name="minabsval">-</a>
1183
qh_minabsval( normal, dim )
1184
return minimum absolute value of a dim vector
1186
realT qh_minabsval (realT *normal, int dim) {
1192
for (k= dim, colp= normal; k--; colp++) {
1193
maximize_(maxval, *colp);
1194
minimize_(minval, *colp);
1196
return fmax_(maxval, -minval);
1200
/*-<a href="qh-geom.htm#TOC"
1201
>-------------------------------</a><a name="mindiff">-</a>
1203
qh_mindif( vecA, vecB, dim )
1204
return index of min abs. difference of two vectors
1206
int qh_mindiff (realT *vecA, realT *vecB, int dim) {
1207
realT mindiff= REALmax, diff;
1208
realT *vecAp= vecA, *vecBp= vecB;
1211
for (k= 0; k < dim; k++) {
1212
diff= *vecAp++ - *vecBp++;
1214
if (diff < mindiff) {
1224
/*-<a href="qh-geom.htm#TOC"
1225
>-------------------------------</a><a name="orientoutside">-</a>
1227
qh_orientoutside( facet )
1228
make facet outside oriented via qh.interior_point
1231
True if facet reversed orientation.
1233
boolT qh_orientoutside (facetT *facet) {
1237
qh_distplane (qh interior_point, facet, &dist);
1239
for (k= qh hull_dim; k--; )
1240
facet->normal[k]= -facet->normal[k];
1241
facet->offset= -facet->offset;
1245
} /* orientoutside */
1247
/*-<a href="qh-geom.htm#TOC"
1248
>-------------------------------</a><a name="outerinner">-</a>
1250
qh_outerinner( facet, outerplane, innerplane )
1251
if facet and qh.maxoutdone (i.e., qh_check_maxout)
1252
returns outer and inner plane for facet
1254
returns maximum outer and inner plane
1255
accounts for qh.JOGGLEmax
1258
qh_maxouter(), qh_check_bestdist(), qh_check_points()
1261
outerplaner or innerplane may be NULL
1263
includes qh.DISTround for actual points
1264
adds another qh.DISTround if testing with floating point arithmetic
1266
void qh_outerinner (facetT *facet, realT *outerplane, realT *innerplane) {
1267
realT dist, mindist;
1268
vertexT *vertex, **vertexp;
1271
if (!qh_MAXoutside || !facet || !qh maxoutdone) {
1272
*outerplane= qh_maxouter(); /* includes qh.DISTround */
1273
}else { /* qh_MAXoutside ... */
1275
*outerplane= facet->maxoutside + qh DISTround;
1279
if (qh JOGGLEmax < REALmax/2)
1280
*outerplane += qh JOGGLEmax * sqrt (qh hull_dim);
1285
FOREACHvertex_(facet->vertices) {
1287
qh_distplane (vertex->point, facet, &dist);
1288
minimize_(mindist, dist);
1290
*innerplane= mindist - qh DISTround;
1292
*innerplane= qh min_vertex - qh DISTround;
1293
if (qh JOGGLEmax < REALmax/2)
1294
*innerplane -= qh JOGGLEmax * sqrt (qh hull_dim);
1298
/*-<a href="qh-geom.htm#TOC"
1299
>-------------------------------</a><a name="pointdist">-</a>
1301
qh_pointdist( point1, point2, dim )
1302
return distance between two points
1305
returns distance squared if 'dim' is negative
1307
coordT qh_pointdist(pointT *point1, pointT *point2, int dim) {
1312
for (k= (dim > 0 ? dim : -dim); k--; ) {
1313
diff= *point1++ - *point2++;
1314
dist += diff * diff;
1322
/*-<a href="qh-geom.htm#TOC"
1323
>-------------------------------</a><a name="printmatrix">-</a>
1325
qh_printmatrix( fp, string, rows, numrow, numcol )
1326
print matrix to fp given by row vectors
1327
print string as header
1330
print a vector by qh_printmatrix(fp, "", &vect, 1, len)
1332
void qh_printmatrix (FILE *fp, char *string, realT **rows, int numrow, int numcol) {
1334
realT r; /*bug fix*/
1337
fprintf (fp, "%s\n", string);
1338
for (i= 0; i < numrow; i++) {
1340
for (k= 0; k < numcol; k++) {
1342
fprintf (fp, "%6.3g ", r);
1349
/*-<a href="qh-geom.htm#TOC"
1350
>-------------------------------</a><a name="printpoints">-</a>
1352
qh_printpoints( fp, string, points )
1353
print pointids to fp for a set of points
1354
if string, prints string and 'p' point ids
1356
void qh_printpoints (FILE *fp, char *string, setT *points) {
1357
pointT *point, **pointp;
1360
fprintf (fp, "%s", string);
1361
FOREACHpoint_(points)
1362
fprintf (fp, " p%d", qh_pointid(point));
1365
FOREACHpoint_(points)
1366
fprintf (fp, " %d", qh_pointid(point));
1372
/*-<a href="qh-geom.htm#TOC"
1373
>-------------------------------</a><a name="projectinput">-</a>
1376
project input points using qh.lower_bound/upper_bound and qh DELAUNAY
1377
if qh.lower_bound[k]=qh.upper_bound[k]= 0,
1379
if halfspace intersection
1380
removes dimension k from qh.feasible_point
1381
input points in qh first_point, num_points, input_dim
1384
new point array in qh first_point of qh hull_dim coordinates
1385
sets qh POINTSmalloc
1387
projects points to paraboloid
1388
lowbound/highbound is also projected
1390
adds point "at-infinity"
1392
frees old point array
1395
checks that qh.hull_dim agrees with qh.input_dim, PROJECTinput, and DELAUNAY
1399
sets project[k] to -1 (delete), 0 (keep), 1 (add for Delaunay)
1400
determines newdim and newnum for qh hull_dim and qh num_points
1401
projects points to newpoints
1402
projects qh.lower_bound to itself
1403
projects qh.upper_bound to itself
1406
projects points to paraboloid
1407
computes "infinity" point as vertex average and 10% above all points
1409
uses qh_setdelaunay to project points to paraboloid
1411
void qh_projectinput (void) {
1413
int newdim= qh input_dim, newnum= qh num_points;
1414
signed char *project;
1415
int size= (qh input_dim+1)*sizeof(*project);
1416
pointT *newpoints, *coord, *infinity;
1417
realT paraboloid, maxboloid= 0;
1419
project= (signed char*)qh_memalloc (size);
1420
memset ((char*)project, 0, size);
1421
for (k= 0; k < qh input_dim; k++) { /* skip Delaunay bound */
1422
if (qh lower_bound[k] == 0 && qh upper_bound[k] == 0) {
1433
if (newdim != qh hull_dim) {
1434
fprintf(qh ferr, "qhull internal error (qh_projectinput): dimension after projection %d != hull_dim %d\n", newdim, qh hull_dim);
1435
qh_errexit(qh_ERRqhull, NULL, NULL);
1437
if (!(newpoints=(coordT*)malloc(newnum*newdim*sizeof(coordT)))){
1438
fprintf(qh ferr, "qhull error: insufficient memory to project %d points\n",
1440
qh_errexit(qh_ERRmem, NULL, NULL);
1442
qh_projectpoints (project, qh input_dim+1, qh first_point,
1443
qh num_points, qh input_dim, newpoints, newdim);
1444
trace1((qh ferr, "qh_projectinput: updating lower and upper_bound\n"));
1445
qh_projectpoints (project, qh input_dim+1, qh lower_bound,
1446
1, qh input_dim+1, qh lower_bound, newdim+1);
1447
qh_projectpoints (project, qh input_dim+1, qh upper_bound,
1448
1, qh input_dim+1, qh upper_bound, newdim+1);
1450
if (!qh feasible_point) {
1451
fprintf(qh ferr, "qhull internal error (qh_projectinput): HALFspace defined without qh.feasible_point\n");
1452
qh_errexit(qh_ERRqhull, NULL, NULL);
1454
qh_projectpoints (project, qh input_dim, qh feasible_point,
1455
1, qh input_dim, qh feasible_point, newdim);
1457
qh_memfree(project, ((qh input_dim+1)*sizeof(*project)));
1458
if (qh POINTSmalloc)
1459
free (qh first_point);
1460
qh first_point= newpoints;
1461
qh POINTSmalloc= True;
1462
if (qh DELAUNAY && qh ATinfinity) {
1463
coord= qh first_point;
1464
infinity= qh first_point + qh hull_dim * qh num_points;
1465
for (k=qh hull_dim-1; k--; )
1467
for (i=qh num_points; i--; ) {
1469
for (k=0; k < qh hull_dim-1; k++) {
1470
paraboloid += *coord * *coord;
1471
infinity[k] += *coord;
1474
*(coord++)= paraboloid;
1475
maximize_(maxboloid, paraboloid);
1477
/* coord == infinity */
1478
for (k=qh hull_dim-1; k--; )
1479
*(coord++) /= qh num_points;
1480
*(coord++)= maxboloid * 1.1;
1482
trace0((qh ferr, "qh_projectinput: projected points to paraboloid for Delaunay\n"));
1483
}else if (qh DELAUNAY) /* !qh ATinfinity */
1484
qh_setdelaunay( qh hull_dim, qh num_points, qh first_point);
1485
} /* projectinput */
1488
/*-<a href="qh-geom.htm#TOC"
1489
>-------------------------------</a><a name="projectpoints">-</a>
1491
qh_projectpoints( project, n, points, numpoints, dim, newpoints, newdim )
1492
project points/numpoints/dim to newpoints/newdim
1496
add dimension k by duplicating previous column
1497
n is size of project
1500
newpoints may be points if only adding dimension at end
1503
check that 'project' and 'newdim' agree
1508
determine start of column in newpoints
1509
determine start of column in points
1510
if project == +1, duplicate previous column
1511
copy dimension (column) from points to newpoints
1513
void qh_projectpoints (signed char *project, int n, realT *points,
1514
int numpoints, int dim, realT *newpoints, int newdim) {
1515
int testdim= dim, oldk=0, newk=0, i,j=0,k;
1518
for (k= 0; k < n; k++)
1519
testdim += project[k];
1520
if (testdim != newdim) {
1521
fprintf (qh ferr, "qhull internal error (qh_projectpoints): newdim %d should be %d after projection\n",
1523
qh_errexit (qh_ERRqhull, NULL, NULL);
1525
for (j= 0; j<n; j++) {
1526
if (project[j] == -1)
1529
newp= newpoints+newk++;
1530
if (project[j] == +1) {
1535
oldp= points+oldk++;
1536
for (i=numpoints; i--; ) {
1545
trace1((qh ferr, "qh_projectpoints: projected %d points from dim %d to dim %d\n",
1546
numpoints, dim, newdim));
1547
} /* projectpoints */
1550
/*-<a href="qh-geom.htm#TOC"
1551
>-------------------------------</a><a name="rand">-</a>
1555
generate pseudo-random number between 1 and 2^31 -2
1558
from Park & Miller's minimimal standard random number generator
1559
Communications of the ACM, 31:1192-1201, 1988.
1560
does not use 0 or 2^31 -1
1561
this is silently enforced by qh_srand()
1562
can make 'Rn' much faster by moving qh_rand to qh_distplane
1564
int qh_rand_seed= 1; /* define as global variable instead of using qh */
1566
int qh_rand( void) {
1567
#define qh_rand_a 16807
1568
#define qh_rand_m 2147483647
1569
#define qh_rand_q 127773 /* m div a */
1570
#define qh_rand_r 2836 /* m mod a */
1572
int seed = qh_rand_seed;
1574
hi = seed / qh_rand_q; /* seed div q */
1575
lo = seed % qh_rand_q; /* seed mod q */
1576
test = qh_rand_a * lo - qh_rand_r * hi;
1580
seed= test + qh_rand_m;
1582
/* seed = seed < qh_RANDOMmax/2 ? 0 : qh_RANDOMmax; for testing */
1583
/* seed = qh_RANDOMmax; for testing */
1587
void qh_srand( int seed) {
1590
else if (seed >= qh_rand_m)
1591
qh_rand_seed= qh_rand_m - 1;
1596
/*-<a href="qh-geom.htm#TOC"
1597
>-------------------------------</a><a name="randomfactor">-</a>
1600
return a random factor within qh.RANDOMmax of 1.0
1603
qh.RANDOMa/b are defined in global.c
1605
realT qh_randomfactor (void) {
1608
randr= qh_RANDOMint;
1609
return randr * qh RANDOMa + qh RANDOMb;
1610
} /* randomfactor */
1612
/*-<a href="qh-geom.htm#TOC"
1613
>-------------------------------</a><a name="randommatrix">-</a>
1615
qh_randommatrix( buffer, dim, rows )
1616
generate a random dim X dim matrix in range [-1,1]
1617
assumes buffer is [dim+1, dim]
1620
sets buffer to random numbers
1621
sets rows to rows of buffer
1622
sets row[dim] as scratch row
1624
void qh_randommatrix (realT *buffer, int dim, realT **rows) {
1626
realT **rowi, *coord, realr;
1630
for (i=0; i < dim; i++) {
1632
for (k=0; k < dim; k++) {
1633
realr= qh_RANDOMint;
1634
*(coord++)= 2.0 * realr/(qh_RANDOMmax+1) - 1.0;
1638
} /* randommatrix */
1641
/*-<a href="qh-geom.htm#TOC"
1642
>-------------------------------</a><a name="rotateinput">-</a>
1644
qh_rotateinput( rows )
1645
rotate input using row matrix
1646
input points given by qh first_point, num_points, hull_dim
1647
assumes rows[dim] is a scratch buffer
1648
if qh POINTSmalloc, overwrites input points, else mallocs a new array
1652
sets qh POINTSmalloc
1657
void qh_rotateinput (realT **rows) {
1659
if (!qh POINTSmalloc) {
1660
qh first_point= qh_copypoints (qh first_point, qh num_points, qh hull_dim);
1661
qh POINTSmalloc= True;
1663
qh_rotatepoints (qh first_point, qh num_points, qh hull_dim, rows);
1666
/*-<a href="qh-geom.htm#TOC"
1667
>-------------------------------</a><a name="rotatepoints">-</a>
1669
qh_rotatepoints( points, numpoints, dim, row )
1670
rotate numpoints points by a d-dim row matrix
1671
assumes rows[dim] is a scratch buffer
1674
rotated points in place
1679
use row[dim] to compute partial inner product
1681
rotate by partial inner product
1683
void qh_rotatepoints (realT *points, int numpoints, int dim, realT **row) {
1684
realT *point, *rowi, *coord= NULL, sum, *newval;
1687
if (qh IStracing >= 1)
1688
qh_printmatrix (qh ferr, "qh_rotatepoints: rotate points by", row, dim, dim);
1689
for (point= points, j= numpoints; j--; point += dim) {
1691
for (i= 0; i < dim; i++) {
1694
for (sum= 0.0, k= dim; k--; )
1695
sum += *rowi++ * *coord++;
1699
*(--coord)= *(--newval);
1701
} /* rotatepoints */
1704
/*-<a href="qh-geom.htm#TOC"
1705
>-------------------------------</a><a name="scaleinput">-</a>
1708
scale input points using qh low_bound/high_bound
1709
input points given by qh first_point, num_points, hull_dim
1710
if qh POINTSmalloc, overwrites input points, else mallocs a new array
1713
scales coordinates of points to low_bound[k], high_bound[k]
1714
sets qh POINTSmalloc
1719
void qh_scaleinput (void) {
1721
if (!qh POINTSmalloc) {
1722
qh first_point= qh_copypoints (qh first_point, qh num_points, qh hull_dim);
1723
qh POINTSmalloc= True;
1725
qh_scalepoints (qh first_point, qh num_points, qh hull_dim,
1726
qh lower_bound, qh upper_bound);
1729
/*-<a href="qh-geom.htm#TOC"
1730
>-------------------------------</a><a name="scalelast">-</a>
1732
qh_scalelast( points, numpoints, dim, low, high, newhigh )
1733
scale last coordinate to [0,m] for Delaunay triangulations
1734
input points given by points, numpoints, dim
1737
changes scale of last coordinate from [low, high] to [0, newhigh]
1738
overwrites last coordinate of each point
1739
saves low/high/newhigh in qh.last_low, etc. for qh_setdelaunay()
1742
when called by qh_setdelaunay, low/high may not match actual data
1745
compute scale and shift factors
1746
apply to last coordinate of each point
1748
void qh_scalelast (coordT *points, int numpoints, int dim, coordT low,
1749
coordT high, coordT newhigh) {
1753
boolT nearzero= False;
1755
trace4((qh ferr, "qh_scalelast: scale last coordinate from [%2.2g, %2.2g] to [0,%2.2g]\n",
1756
low, high, newhigh));
1759
qh last_newhigh= newhigh;
1760
scale= qh_divzero (newhigh, high - low,
1761
qh MINdenom_1, &nearzero);
1764
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");
1766
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",
1767
newhigh, low, high, high-low);
1768
qh_errexit (qh_ERRinput, NULL, NULL);
1770
shift= - low * newhigh / (high-low);
1771
coord= points + dim - 1;
1772
for (i= numpoints; i--; coord += dim)
1773
*coord= *coord * scale + shift;
1776
/*-<a href="qh-geom.htm#TOC"
1777
>-------------------------------</a><a name="scalepoints">-</a>
1779
qh_scalepoints( points, numpoints, dim, newlows, newhighs )
1780
scale points to new lowbound and highbound
1781
retains old bound when newlow= -REALmax or newhigh= +REALmax
1785
overwrites old points
1789
compute current low and high bound
1790
compute scale and shift factors
1792
enforce new low and high bound for all points
1794
void qh_scalepoints (pointT *points, int numpoints, int dim,
1795
realT *newlows, realT *newhighs) {
1797
realT shift, scale, *coord, low, high, newlow, newhigh, mincoord, maxcoord;
1798
boolT nearzero= False;
1800
for (k= 0; k < dim; k++) {
1801
newhigh= newhighs[k];
1803
if (newhigh > REALmax/2 && newlow < -REALmax/2)
1807
for (i= numpoints, coord= points+k; i--; coord += dim) {
1808
minimize_(low, *coord);
1809
maximize_(high, *coord);
1811
if (newhigh > REALmax/2)
1813
if (newlow < -REALmax/2)
1815
if (qh DELAUNAY && k == dim-1 && newhigh < newlow) {
1816
fprintf (qh ferr, "qhull input error: 'Qb%d' or 'QB%d' inverts paraboloid since high bound %.2g < low bound %.2g\n",
1817
k, k, newhigh, newlow);
1818
qh_errexit (qh_ERRinput, NULL, NULL);
1820
scale= qh_divzero (newhigh - newlow, high - low,
1821
qh MINdenom_1, &nearzero);
1823
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",
1824
k, newlow, newhigh, low, high);
1825
qh_errexit (qh_ERRinput, NULL, NULL);
1827
shift= (newlow * high - low * newhigh)/(high-low);
1829
for (i= numpoints; i--; coord += dim)
1830
*coord= *coord * scale + shift;
1832
if (newlow < newhigh) {
1839
for (i= numpoints; i--; coord += dim) {
1840
minimize_(*coord, maxcoord); /* because of roundoff error */
1841
maximize_(*coord, mincoord);
1843
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",
1844
k, low, high, newlow, newhigh, numpoints, scale, shift));
1849
/*-<a href="qh-geom.htm#TOC"
1850
>-------------------------------</a><a name="setdelaunay">-</a>
1852
qh_setdelaunay( dim, count, points )
1853
project count points to dim-d paraboloid for Delaunay triangulation
1855
dim is one more than the dimension of the input set
1856
assumes dim is at least 3 (i.e., at least a 2-d Delaunay triangulation)
1858
points is a dim*count realT array. The first dim-1 coordinates
1859
are the coordinates of the first input point. array[dim] is
1860
the first coordinate of the second input point. array[2*dim] is
1861
the first coordinate of the third input point.
1863
if qh.last_low defined (i.e., 'Qbb' called qh_scalelast)
1864
calls qh_scalelast to scale the last coordinate the same as the other points
1868
sets point[dim-1] to sum of squares of coordinates
1869
scale points to 'Qbb' if needed
1872
to project one point, use
1873
qh_setdelaunay (qh hull_dim, 1, point)
1875
Do not use options 'Qbk', 'QBk', or 'QbB' since they scale
1876
the coordinates after the original projection.
1879
void qh_setdelaunay (int dim, int count, pointT *points) {
1881
coordT *coordp, coord;
1884
trace0((qh ferr, "qh_setdelaunay: project %d points to paraboloid for Delaunay triangulation\n", count));
1886
for (i= 0; i < count; i++) {
1888
paraboloid= coord*coord;
1889
for (k= dim-2; k--; ) {
1891
paraboloid += coord*coord;
1893
*coordp++ = paraboloid;
1895
if (qh last_low < REALmax/2)
1896
qh_scalelast (points, count, dim, qh last_low, qh last_high, qh last_newhigh);
1900
/*-<a href="qh-geom.htm#TOC"
1901
>-------------------------------</a><a name="sethalfspace">-</a>
1903
qh_sethalfspace( dim, coords, nextp, normal, offset, feasible )
1904
set point to dual of halfspace relative to feasible point
1905
halfspace is normal coefficients and offset.
1908
false if feasible point is outside of hull (error message already reported)
1909
overwrites coordinates for point at dim coords
1910
nextp= next point (coords)
1913
compute distance from feasible point to halfspace
1914
divide each normal coefficient by -dist
1916
boolT qh_sethalfspace (int dim, coordT *coords, coordT **nextp,
1917
coordT *normal, coordT *offset, coordT *feasible) {
1918
coordT *normp= normal, *feasiblep= feasible, *coordp= coords;
1920
realT r; /*bug fix*/
1926
dist += *(normp++) * *(feasiblep++);
1928
goto LABELerroroutside;
1930
if (dist < -qh MINdenom) {
1932
*(coordp++)= *(normp++) / -dist;
1934
for (k= dim; k--; ) {
1935
*(coordp++)= qh_divzero (*(normp++), -dist, qh MINdenom_1, &zerodiv);
1937
goto LABELerroroutside;
1941
if (qh IStracing >= 4) {
1942
fprintf (qh ferr, "qh_sethalfspace: halfspace at offset %6.2g to point: ", *offset);
1943
for (k= dim, coordp= coords; k--; ) {
1945
fprintf (qh ferr, " %6.2g", r);
1947
fprintf (qh ferr, "\n");
1951
feasiblep= feasible;
1953
fprintf(qh ferr, "qhull input error: feasible point is not clearly inside halfspace\nfeasible point: ");
1955
fprintf (qh ferr, qh_REAL_1, r=*(feasiblep++));
1956
fprintf (qh ferr, "\n halfspace: ");
1958
fprintf (qh ferr, qh_REAL_1, r=*(normp++));
1959
fprintf (qh ferr, "\n at offset: ");
1960
fprintf (qh ferr, qh_REAL_1, *offset);
1961
fprintf (qh ferr, " and distance: ");
1962
fprintf (qh ferr, qh_REAL_1, dist);
1963
fprintf (qh ferr, "\n");
1965
} /* sethalfspace */
1967
/*-<a href="qh-geom.htm#TOC"
1968
>-------------------------------</a><a name="sethalfspace_all">-</a>
1970
qh_sethalfspace_all( dim, count, halfspaces, feasible )
1971
generate dual for halfspace intersection with feasible point
1972
array of count halfspaces
1973
each halfspace is normal coefficients followed by offset
1974
the origin is inside the halfspace if the offset is negative
1977
malloc'd array of count X dim-1 points
1980
call before qh_init_B or qh_initqhull_globals
1981
unused/untested code: please email bradb@shore.net if this works ok for you
1982
If using option 'Fp', also set qh feasible_point. It is a malloc'd array
1983
that is freed by qh_freebuffers.
1988
coordT *qh_sethalfspace_all (int dim, int count, coordT *halfspaces, pointT *feasible) {
1991
coordT *coordp, *normalp, *offsetp;
1993
trace0((qh ferr, "qh_sethalfspace_all: compute dual for halfspace intersection\n"));
1995
if (!(newpoints=(coordT*)malloc(count*newdim*sizeof(coordT)))){
1996
fprintf(qh ferr, "qhull error: insufficient memory to compute dual of %d halfspaces\n",
1998
qh_errexit(qh_ERRmem, NULL, NULL);
2001
normalp= halfspaces;
2002
for (i= 0; i < count; i++) {
2003
offsetp= normalp + newdim;
2004
if (!qh_sethalfspace (newdim, coordp, &coordp, normalp, offsetp, feasible)) {
2005
fprintf (qh ferr, "The halfspace was at index %d\n", i);
2006
qh_errexit (qh_ERRinput, NULL, NULL);
2008
normalp= offsetp + 1;
2011
} /* sethalfspace_all */
2014
/*-<a href="qh-geom.htm#TOC"
2015
>-------------------------------</a><a name="sharpnewfacets">-</a>
2020
true if could be an acute angle (facets in different quadrants)
2026
for all facets on qh.newfacet_list
2027
if two facets are in different quadrants
2030
boolT qh_sharpnewfacets () {
2032
boolT issharp = False;
2035
quadrant= (int*)qh_memalloc (qh hull_dim * sizeof(int));
2036
FORALLfacet_(qh newfacet_list) {
2037
if (facet == qh newfacet_list) {
2038
for (k= qh hull_dim; k--; )
2039
quadrant[ k]= (facet->normal[ k] > 0);
2041
for (k= qh hull_dim; k--; ) {
2042
if (quadrant[ k] != (facet->normal[ k] > 0)) {
2051
qh_memfree( quadrant, qh hull_dim * sizeof(int));
2052
trace3((qh ferr, "qh_sharpnewfacets: %d\n", issharp));
2054
} /* sharpnewfacets */
2056
/*-<a href="qh-geom.htm#TOC"
2057
>-------------------------------</a><a name="voronoi_center">-</a>
2059
qh_voronoi_center( dim, points )
2060
return Voronoi center for a set of points
2061
dim is the orginal dimension of the points
2062
gh.gm_matrix/qh.gm_row are scratch buffers
2065
center as a temporary point
2067
returns center for max simplex of points
2070
from Bowyer & Woodwark, A Programmer's Geometry, 1983, p. 65
2074
determine max simplex for points
2075
translate point0 of simplex to origin
2076
compute sum of squares of diagonal
2078
compute Voronoi center (see Bowyer & Woodwark)
2080
pointT *qh_voronoi_center (int dim, setT *points) {
2081
pointT *point, **pointp, *point0;
2082
pointT *center= (pointT*)qh_memalloc (qh center_size);
2084
int i, j, k, size= qh_setsize(points);
2086
realT *diffp, sum2, *sum2row, *sum2p, det, factor;
2087
boolT nearzero, infinite;
2091
else if (size < dim+1) {
2092
fprintf (qh ferr, "qhull internal error (qh_voronoi_center):\n need at least %d points to construct a Voronoi center\n",
2094
qh_errexit (qh_ERRqhull, NULL, NULL);
2096
simplex= qh_settemp (dim+1);
2097
qh_maxsimplex (dim, points, NULL, 0, &simplex);
2099
point0= SETfirstt_(simplex, pointT);
2100
gmcoord= qh gm_matrix;
2101
for (k=0; k < dim; k++) {
2102
qh gm_row[k]= gmcoord;
2103
FOREACHpoint_(simplex) {
2104
if (point != point0)
2105
*(gmcoord++)= point[k] - point0[k];
2109
for (i=0; i < dim; i++) {
2111
for (k= 0; k < dim; k++) {
2112
diffp= qh gm_row[k] + i;
2113
sum2 += *diffp * *diffp;
2117
det= qh_determinant (qh gm_row, dim, &nearzero);
2118
factor= qh_divzero (0.5, det, qh MINdenom, &infinite);
2121
center[k]= qh_INFINITE;
2123
qh_printpoints (qh ferr, "qh_voronoi_center: at infinity for ", simplex);
2125
for (i=0; i < dim; i++) {
2126
gmcoord= qh gm_matrix;
2128
for (k=0; k < dim; k++) {
2129
qh gm_row[k]= gmcoord;
2132
*(gmcoord++)= *sum2p++;
2134
FOREACHpoint_(simplex) {
2135
if (point != point0)
2136
*(gmcoord++)= point[k] - point0[k];
2140
center[i]= qh_determinant (qh gm_row, dim, &nearzero)*factor + point0[i];
2143
if (qh IStracing >= 3) {
2144
fprintf (qh ferr, "qh_voronoi_center: det %2.2g factor %2.2g ", det, factor);
2145
qh_printmatrix (qh ferr, "center:", ¢er, 1, dim);
2146
if (qh IStracing >= 5) {
2147
qh_printpoints (qh ferr, "points", simplex);
2148
FOREACHpoint_(simplex)
2149
fprintf (qh ferr, "p%d dist %.2g, ", qh_pointid (point),
2150
qh_pointdist (point, center, dim));
2151
fprintf (qh ferr, "\n");
2156
if (simplex != points)
2157
qh_settempfree (&simplex);
2159
} /* voronoi_center */