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

# Content
1 /*<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