1
/*<html><pre> -<a href="qh-io.htm"
2
>-------------------------------</a><a name="TOP">-</a>
5
Input/Output routines of qhull application
9
see user.c for qh_errprint and qh_printfacetlist
11
unix.c calls qh_readpoints and qh_produce_output
13
unix.c and user.c are the only callers of io.c functions
14
This allows the user to avoid loading io.o from qhull.a
16
copyright (c) 1993-2003 The Geometry Center
21
/*========= -functions in alphabetical order after qh_produce_output() =====*/
23
/*-<a href="qh-io.htm#TOC"
24
>-------------------------------</a><a name="produce_output">-</a>
27
prints out the result of qhull in desired format
29
computes and prints area and volume
30
qh.PRINTout[] is an array of output formats
33
prints output in qh.PRINTout order
35
void qh_produce_output(void) {
36
int i, tempsize= qh_setsize ((setT*)qhmem.tempstack), d_1;
39
qh_clearcenters (qh_ASvoronoi);
44
if (qh VERIFYoutput && !qh CHECKfrequently)
45
qh_checkpolygon (qh facet_list);
47
qh_findgood_all (qh facet_list);
49
qh_getarea(qh facet_list);
50
if (qh KEEParea || qh KEEPmerge || qh KEEPminArea < REALmax/2)
51
qh_markkeep (qh facet_list);
53
qh_printsummary(qh ferr);
54
else if (qh PRINTout[0] == qh_PRINTnone)
55
qh_printsummary(qh fout);
56
for (i= 0; i < qh_PRINTEND; i++)
57
qh_printfacets (qh fout, qh PRINTout[i], qh facet_list, NULL, !qh_ALL);
59
if (qh PRINTprecision && !qh MERGING && (qh JOGGLEmax > REALmax/2 || qh RERUN))
60
qh_printstats (qh ferr, qhstat precision, NULL);
61
if (qh VERIFYoutput && (zzval_(Zridge) > 0 || zzval_(Zridgemid) > 0))
62
qh_printstats (qh ferr, qhstat vridges, NULL);
63
if (qh PRINTstatistics) {
64
qh_collectstatistics();
65
qh_printstatistics(qh ferr, "");
66
qh_memstatistics (qh ferr);
67
d_1= sizeof(setT) + (qh hull_dim - 1) * SETelemsize;
69
size in bytes: merge %lu ridge %lu vertex %lu facet %lu\n\
70
normal %d ridge vertices %d facet vertices or neighbors %lu\n",
71
sizeof(mergeT), sizeof(ridgeT),
72
sizeof(vertexT), sizeof(facetT),
73
qh normal_size, d_1, d_1 + SETelemsize);
75
if (qh_setsize ((setT*)qhmem.tempstack) != tempsize) {
76
fprintf (qh ferr, "qhull internal error (qh_produce_output): temporary sets not empty (%d)\n",
77
qh_setsize ((setT*)qhmem.tempstack));
78
qh_errexit (qh_ERRqhull, NULL, NULL);
80
} /* produce_output */
83
/*-<a href="qh-io.htm#TOC"
84
>-------------------------------</a><a name="dfacet">-</a>
87
print facet by id, for debugging
90
void dfacet (unsigned id) {
94
if (facet->id == id) {
95
qh_printfacet (qh fout, facet);
102
/*-<a href="qh-io.htm#TOC"
103
>-------------------------------</a><a name="dvertex">-</a>
106
print vertex by id, for debugging
108
void dvertex (unsigned id) {
112
if (vertex->id == id) {
113
qh_printvertex (qh fout, vertex);
120
/*-<a href="qh-io.htm#TOC"
121
>-------------------------------</a><a name="compare_vertexpoint">-</a>
123
qh_compare_vertexpoint( p1, p2 )
124
used by qsort() to order vertices by point id
126
int qh_compare_vertexpoint(const void *p1, const void *p2) {
127
vertexT *a= *((vertexT **)p1), *b= *((vertexT **)p2);
129
return ((qh_pointid(a->point) > qh_pointid(b->point)?1:-1));
130
} /* compare_vertexpoint */
132
/*-<a href="qh-io.htm#TOC"
133
>-------------------------------</a><a name="compare_facetarea">-</a>
135
qh_compare_facetarea( p1, p2 )
136
used by qsort() to order facets by area
138
int qh_compare_facetarea(const void *p1, const void *p2) {
139
facetT *a= *((facetT **)p1), *b= *((facetT **)p2);
145
if (a->f.area > b->f.area)
147
else if (a->f.area == b->f.area)
150
} /* compare_facetarea */
152
/*-<a href="qh-io.htm#TOC"
153
>-------------------------------</a><a name="compare_facetmerge">-</a>
155
qh_compare_facetmerge( p1, p2 )
156
used by qsort() to order facets by number of merges
158
int qh_compare_facetmerge(const void *p1, const void *p2) {
159
facetT *a= *((facetT **)p1), *b= *((facetT **)p2);
161
return (a->nummerge - b->nummerge);
162
} /* compare_facetvisit */
164
/*-<a href="qh-io.htm#TOC"
165
>-------------------------------</a><a name="compare_facetvisit">-</a>
167
qh_compare_facetvisit( p1, p2 )
168
used by qsort() to order facets by visit id or id
170
int qh_compare_facetvisit(const void *p1, const void *p2) {
171
facetT *a= *((facetT **)p1), *b= *((facetT **)p2);
174
if (!(i= a->visitid))
175
i= - a->id; /* do not convert to int */
176
if (!(j= b->visitid))
179
} /* compare_facetvisit */
181
/*-<a href="qh-io.htm#TOC"
182
>-------------------------------</a><a name="countfacets">-</a>
184
qh_countfacets( facetlist, facets, printall,
185
numfacets, numsimplicial, totneighbors, numridges, numcoplanar, numtricoplanars )
186
count good facets for printing and set visitid
187
if allfacets, ignores qh_skipfacet()
190
qh_printsummary and qh_countfacets must match counts
193
numfacets, numsimplicial, total neighbors, numridges, coplanars
194
each facet with ->visitid indicating 1-relative position
195
->visitid==0 indicates not good
198
numfacets >= numsimplicial
200
does not count visible facets (matches qh_printafacet)
203
for all facets on facetlist and in facets set
204
unless facet is skipped or visible (i.e., will be deleted)
208
void qh_countfacets (facetT *facetlist, setT *facets, boolT printall,
209
int *numfacetsp, int *numsimplicialp, int *totneighborsp, int *numridgesp, int *numcoplanarsp, int *numtricoplanarsp) {
210
facetT *facet, **facetp;
211
int numfacets= 0, numsimplicial= 0, numridges= 0, totneighbors= 0, numcoplanars= 0, numtricoplanars= 0;
213
FORALLfacet_(facetlist) {
214
if ((facet->visible && qh NEWfacets)
215
|| (!printall && qh_skipfacet(facet)))
218
facet->visitid= ++numfacets;
219
totneighbors += qh_setsize (facet->neighbors);
220
if (facet->simplicial) {
222
if (facet->keepcentrum && facet->tricoplanar)
225
numridges += qh_setsize (facet->ridges);
226
if (facet->coplanarset)
227
numcoplanars += qh_setsize (facet->coplanarset);
230
FOREACHfacet_(facets) {
231
if ((facet->visible && qh NEWfacets)
232
|| (!printall && qh_skipfacet(facet)))
235
facet->visitid= ++numfacets;
236
totneighbors += qh_setsize (facet->neighbors);
237
if (facet->simplicial){
239
if (facet->keepcentrum && facet->tricoplanar)
242
numridges += qh_setsize (facet->ridges);
243
if (facet->coplanarset)
244
numcoplanars += qh_setsize (facet->coplanarset);
247
qh visit_id += numfacets+1;
248
*numfacetsp= numfacets;
249
*numsimplicialp= numsimplicial;
250
*totneighborsp= totneighbors;
251
*numridgesp= numridges;
252
*numcoplanarsp= numcoplanars;
253
*numtricoplanarsp= numtricoplanars;
256
/*-<a href="qh-io.htm#TOC"
257
>-------------------------------</a><a name="detvnorm">-</a>
259
qh_detvnorm( vertex, vertexA, centers, offset )
260
compute separating plane of the Voronoi diagram for a pair of input sites
261
centers= set of facets (i.e., Voronoi vertices)
262
facet->visitid= 0 iff vertex-at-infinity (i.e., unbounded)
265
qh_ASvoronoi and qh_vertexneighbors() already set
269
a pointer into qh.gm_matrix to qh.hull_dim-1 reals
270
copy the data before reusing qh.gm_matrix
273
sign adjusted so that qh.GOODvertexp is inside
275
sign adjusted so that vertex is inside
277
qh.gm_matrix= simplex of points from centers relative to first center
280
in io.c so that code for 'v Tv' can be removed by removing io.c
281
returns pointer into qh.gm_matrix to avoid tracking of temporary memory
284
determine midpoint of input sites
285
build points as the set of Voronoi vertices
286
select a simplex from points (if necessary)
287
include midpoint if the Voronoi region is unbounded
288
relocate the first vertex of the simplex to the origin
289
compute the normalized hyperplane through the simplex
290
orient the hyperplane toward 'QVn' or 'vertex'
293
test that hyperplane is the perpendicular bisector of the input sites
294
test that Voronoi vertices not in the simplex are still on the hyperplane
295
free up temporary memory
297
pointT *qh_detvnorm (vertexT *vertex, vertexT *vertexA, setT *centers, realT *offsetp) {
298
facetT *facet, **facetp;
299
int i, k, pointid, pointidA, point_i, point_n;
301
pointT *point, **pointp, *point0, *midpoint, *normal, *inpoint;
302
coordT *coord, *gmcoord, *normalp;
303
setT *points= qh_settemp (qh TEMPsize);
304
boolT nearzero= False;
305
boolT unbounded= False;
307
int dim= qh hull_dim - 1;
308
realT dist, offset, angle, zero= 0.0;
310
midpoint= qh gm_matrix + qh hull_dim * qh hull_dim; /* last row */
311
for (k= 0; k < dim; k++)
312
midpoint[k]= (vertex->point[k] + vertexA->point[k])/2;
313
FOREACHfacet_(centers) {
319
facet->center= qh_facetcenter (facet->vertices);
320
qh_setappend (&points, facet->center);
323
if (numcenters > dim) {
324
simplex= qh_settemp (qh TEMPsize);
325
qh_setappend (&simplex, vertex->point);
327
qh_setappend (&simplex, midpoint);
328
qh_maxsimplex (dim, points, NULL, 0, &simplex);
329
qh_setdelnth (simplex, 0);
330
}else if (numcenters == dim) {
332
qh_setappend (&points, midpoint);
335
fprintf(qh ferr, "qh_detvnorm: too few points (%d) to compute separating plane\n", numcenters);
336
qh_errexit (qh_ERRqhull, NULL, NULL);
339
gmcoord= qh gm_matrix;
340
point0= SETfirstt_(simplex, pointT);
341
FOREACHpoint_(simplex) {
342
if (qh IStracing >= 4)
343
qh_printmatrix(qh ferr, "qh_detvnorm: Voronoi vertex or midpoint",
345
if (point != point0) {
346
qh gm_row[i++]= gmcoord;
349
*(gmcoord++)= *point++ - *coord++;
352
qh gm_row[i]= gmcoord; /* does not overlap midpoint, may be used later for qh_areasimplex */
354
qh_sethyperplane_gauss (dim, qh gm_row, point0, True,
355
normal, &offset, &nearzero);
356
if (qh GOODvertexp == vertexA->point)
357
inpoint= vertexA->point;
359
inpoint= vertex->point;
361
dist= qh_distnorm (dim, inpoint, normal, &offset);
365
for (k= dim; k--; ) {
366
*normalp= -(*normalp);
370
if (qh VERIFYoutput || qh PRINTstatistics) {
371
pointid= qh_pointid (vertex->point);
372
pointidA= qh_pointid (vertexA->point);
375
dist= qh_distnorm (dim, midpoint, normal, &offset);
379
wwmax_(Wridgemidmax, dist);
380
wwadd_(Wridgemid, dist);
381
trace4((qh ferr, "qh_detvnorm: points %d %d midpoint dist %2.2g\n",
382
pointid, pointidA, dist));
383
for (k= 0; k < dim; k++)
384
midpoint[k]= vertexA->point[k] - vertex->point[k]; /* overwrites midpoint! */
385
qh_normalize (midpoint, dim, False);
386
angle= qh_distnorm (dim, midpoint, normal, &zero); /* qh_detangle uses dim+1 */
393
trace4((qh ferr, "qh_detvnorm: points %d %d angle %2.2g nearzero %d\n",
394
pointid, pointidA, angle, nearzero));
397
wwmax_(Wridge0max, angle);
398
wwadd_(Wridge0, angle);
401
wwmax_(Wridgeokmax, angle);
402
wwadd_(Wridgeok, angle);
405
if (simplex != points) {
406
FOREACHpoint_i_(points) {
407
if (!qh_setin (simplex, point)) {
408
facet= SETelemt_(centers, point_i, facetT);
410
dist= qh_distnorm (dim, point, normal, &offset);
414
wwmax_(Wridgemax, dist);
415
wwadd_(Wridge, dist);
416
trace4((qh ferr, "qh_detvnorm: points %d %d Voronoi vertex %d dist %2.2g\n",
417
pointid, pointidA, facet->visitid, dist));
423
if (simplex != points)
424
qh_settempfree (&simplex);
425
qh_settempfree (&points);
429
/*-<a href="qh-io.htm#TOC"
430
>-------------------------------</a><a name="detvridge">-</a>
432
qh_detvridge( vertexA )
433
determine Voronoi ridge from 'seen' neighbors of vertexA
434
include one vertex-at-infinite if an !neighbor->visitid
437
temporary set of centers (facets, i.e., Voronoi vertices)
440
setT *qh_detvridge (vertexT *vertex) {
441
setT *centers= qh_settemp (qh TEMPsize);
442
setT *tricenters= qh_settemp (qh TEMPsize);
443
facetT *neighbor, **neighborp;
444
boolT firstinf= True;
446
FOREACHneighbor_(vertex) {
447
if (neighbor->seen) {
448
if (neighbor->visitid) {
449
if (!neighbor->tricoplanar || qh_setunique (&tricenters, neighbor->center))
450
qh_setappend (¢ers, neighbor);
451
}else if (firstinf) {
453
qh_setappend (¢ers, neighbor);
457
qsort (SETaddr_(centers, facetT), qh_setsize (centers),
458
sizeof (facetT *), qh_compare_facetvisit);
459
qh_settempfree (&tricenters);
463
/*-<a href="qh-io.htm#TOC"
464
>-------------------------------</a><a name="detvridge3">-</a>
466
qh_detvridge3( atvertex, vertex )
467
determine 3-d Voronoi ridge from 'seen' neighbors of atvertex and vertex
468
include one vertex-at-infinite for !neighbor->visitid
469
assumes all facet->seen2= True
472
temporary set of centers (facets, i.e., Voronoi vertices)
473
listed in adjacency order (not oriented)
474
all facet->seen2= True
477
mark all neighbors of atvertex
478
for each adjacent neighbor of both atvertex and vertex
480
add neighbor to set of Voronoi vertices
482
setT *qh_detvridge3 (vertexT *atvertex, vertexT *vertex) {
483
setT *centers= qh_settemp (qh TEMPsize);
484
setT *tricenters= qh_settemp (qh TEMPsize);
485
facetT *neighbor, **neighborp, *facet= NULL;
486
boolT firstinf= True;
488
FOREACHneighbor_(atvertex)
489
neighbor->seen2= False;
490
FOREACHneighbor_(vertex) {
491
if (!neighbor->seen2) {
498
if (neighbor->seen) {
499
if (facet->visitid) {
500
if (!facet->tricoplanar || qh_setunique (&tricenters, facet->center))
501
qh_setappend (¢ers, facet);
502
}else if (firstinf) {
504
qh_setappend (¢ers, facet);
507
FOREACHneighbor_(facet) {
508
if (!neighbor->seen2) {
509
if (qh_setin (vertex->neighbors, neighbor))
512
neighbor->seen2= True;
517
if (qh CHECKfrequently) {
518
FOREACHneighbor_(vertex) {
519
if (!neighbor->seen2) {
520
fprintf (stderr, "qh_detvridge3: neigbors of vertex p%d are not connected at facet %d\n",
521
qh_pointid (vertex->point), neighbor->id);
522
qh_errexit (qh_ERRqhull, neighbor, NULL);
526
FOREACHneighbor_(atvertex)
527
neighbor->seen2= True;
528
qh_settempfree (&tricenters);
532
/*-<a href="qh-io.htm#TOC"
533
>-------------------------------</a><a name="eachvoronoi">-</a>
535
qh_eachvoronoi( fp, printvridge, vertex, visitall, innerouter, inorder )
537
visit all Voronoi ridges for vertex (i.e., an input site)
539
visit all unvisited Voronoi ridges for vertex
540
all vertex->seen= False if unvisited
542
all facet->seen= False
543
all facet->seen2= True (for qh_detvridge3)
544
all facet->visitid == 0 if vertex_at_infinity
545
== index of Voronoi vertex
546
>= qh.num_facets if ignored
548
qh_RIDGEall-- both inner (bounded) and outer (unbounded) ridges
549
qh_RIDGEinner- only inner
550
qh_RIDGEouter- only outer
553
orders vertices for 3-d Voronoi diagrams
556
number of visited ridges (does not include previously visited ridges)
559
calls printvridge( fp, vertex, vertexA, centers)
560
fp== any pointer (assumes FILE*)
561
vertex,vertexA= pair of input sites that define a Voronoi ridge
562
centers= set of facets (i.e., Voronoi vertices)
563
->visitid == index or 0 if vertex_at_infinity
564
ordered for 3-d Voronoi diagram
572
mark selected neighbors of atvertex
573
for each selected neighbor (either Voronoi vertex or vertex-at-infinity)
574
for each unvisited vertex
575
if atvertex and vertex share more than d-1 neighbors
577
if printvridge defined
578
build the set of shared neighbors (i.e., Voronoi vertices)
581
int qh_eachvoronoi (FILE *fp, printvridgeT printvridge, vertexT *atvertex, boolT visitall, qh_RIDGE innerouter, boolT inorder) {
584
facetT *neighbor, **neighborp, *neighborA, **neighborAp;
586
setT *tricenters= qh_settemp (qh TEMPsize);
588
vertexT *vertex, **vertexp;
590
unsigned int numfacets= (unsigned int)qh num_facets;
594
atvertex->seen= True;
599
FOREACHneighbor_(atvertex) {
600
if (neighbor->visitid < numfacets)
601
neighbor->seen= True;
603
FOREACHneighbor_(atvertex) {
604
if (neighbor->seen) {
605
FOREACHvertex_(neighbor->vertices) {
606
if (vertex->visitid != qh vertex_visit && !vertex->seen) {
607
vertex->visitid= qh vertex_visit;
610
qh_settruncate (tricenters, 0);
611
FOREACHneighborA_(vertex) {
612
if (neighborA->seen) {
613
if (neighborA->visitid) {
614
if (!neighborA->tricoplanar || qh_setunique (&tricenters, neighborA->center))
616
}else if (firstinf) {
622
if (count >= qh hull_dim - 1) { /* e.g., 3 for 3-d Voronoi */
624
if (innerouter == qh_RIDGEouter)
628
if (innerouter == qh_RIDGEinner)
633
trace4((qh ferr, "qh_eachvoronoi: Voronoi ridge of %d vertices between sites %d and %d\n",
634
count, qh_pointid (atvertex->point), qh_pointid (vertex->point)));
636
if (inorder && qh hull_dim == 3+1) /* 3-d Voronoi diagram */
637
centers= qh_detvridge3 (atvertex, vertex);
639
centers= qh_detvridge (vertex);
640
(*printvridge) (fp, atvertex, vertex, centers, unbounded);
641
qh_settempfree (¢ers);
648
FOREACHneighbor_(atvertex)
649
neighbor->seen= False;
650
qh_settempfree (&tricenters);
655
/*-<a href="qh-poly.htm#TOC"
656
>-------------------------------</a><a name="eachvoronoi_all">-</a>
658
qh_eachvoronoi_all( fp, printvridge, isupper, innerouter, inorder )
659
visit all Voronoi ridges
665
orders vertices for 3-d Voronoi diagrams
668
total number of ridges
670
if isupper == facet->upperdelaunay (i.e., a Vornoi vertex)
671
facet->visitid= Voronoi vertex index (same as 'o' format)
676
calls printvridge( fp, vertex, vertexA, centers)
680
Not used for qhull.exe
681
same effect as qh_printvdiagram but ridges not sorted by point id
683
int qh_eachvoronoi_all (FILE *fp, printvridgeT printvridge, boolT isupper, qh_RIDGE innerouter, boolT inorder) {
686
int numcenters= 1; /* vertex 0 is vertex-at-infinity */
689
qh_clearcenters (qh_ASvoronoi);
690
qh_vertexneighbors();
691
maximize_(qh visit_id, (unsigned) qh num_facets);
698
if (facet->upperdelaunay == isupper)
699
facet->visitid= numcenters++;
704
if (qh GOODvertex > 0 && qh_pointid(vertex->point)+1 != qh GOODvertex)
706
totridges += qh_eachvoronoi (fp, printvridge, vertex,
707
!qh_ALL, innerouter, inorder);
710
} /* eachvoronoi_all */
712
/*-<a href="qh-io.htm#TOC"
713
>-------------------------------</a><a name="facet2point">-</a>
715
qh_facet2point( facet, point0, point1, mindist )
716
return two projected temporary vertices for a 2-d facet
717
may be non-simplicial
720
point0 and point1 oriented and projected to the facet
721
returns mindist (maximum distance below plane)
723
void qh_facet2point(facetT *facet, pointT **point0, pointT **point1, realT *mindist) {
724
vertexT *vertex0, *vertex1;
727
if (facet->toporient ^ qh_ORIENTclock) {
728
vertex0= SETfirstt_(facet->vertices, vertexT);
729
vertex1= SETsecondt_(facet->vertices, vertexT);
731
vertex1= SETfirstt_(facet->vertices, vertexT);
732
vertex0= SETsecondt_(facet->vertices, vertexT);
735
qh_distplane(vertex0->point, facet, &dist);
737
*point0= qh_projectpoint(vertex0->point, facet, dist);
738
qh_distplane(vertex1->point, facet, &dist);
739
minimize_(*mindist, dist);
740
*point1= qh_projectpoint(vertex1->point, facet, dist);
744
/*-<a href="qh-io.htm#TOC"
745
>-------------------------------</a><a name="facetvertices">-</a>
747
qh_facetvertices( facetlist, facets, allfacets )
748
returns temporary set of vertices in a set and/or list of facets
749
if allfacets, ignores qh_skipfacet()
752
vertices with qh.vertex_visit
755
optimized for allfacets of facet_list
758
if allfacets of facet_list
759
create vertex set from vertex_list
761
for each selected facet in facets or facetlist
762
append unvisited vertices to vertex set
764
setT *qh_facetvertices (facetT *facetlist, setT *facets, boolT allfacets) {
766
facetT *facet, **facetp;
767
vertexT *vertex, **vertexp;
770
if (facetlist == qh facet_list && allfacets && !facets) {
771
vertices= qh_settemp (qh num_vertices);
773
vertex->visitid= qh vertex_visit;
774
qh_setappend (&vertices, vertex);
777
vertices= qh_settemp (qh TEMPsize);
778
FORALLfacet_(facetlist) {
779
if (!allfacets && qh_skipfacet (facet))
781
FOREACHvertex_(facet->vertices) {
782
if (vertex->visitid != qh vertex_visit) {
783
vertex->visitid= qh vertex_visit;
784
qh_setappend (&vertices, vertex);
789
FOREACHfacet_(facets) {
790
if (!allfacets && qh_skipfacet (facet))
792
FOREACHvertex_(facet->vertices) {
793
if (vertex->visitid != qh vertex_visit) {
794
vertex->visitid= qh vertex_visit;
795
qh_setappend (&vertices, vertex);
800
} /* facetvertices */
802
/*-<a href="qh-geom.htm#TOC"
803
>-------------------------------</a><a name="geomplanes">-</a>
805
qh_geomplanes( facet, outerplane, innerplane )
806
return outer and inner planes for Geomview
807
qh.PRINTradius is size of vertices and points (includes qh.JOGGLEmax)
810
assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
812
void qh_geomplanes (facetT *facet, realT *outerplane, realT *innerplane) {
815
if (qh MERGING || qh JOGGLEmax < REALmax/2) {
816
qh_outerinner (facet, outerplane, innerplane);
817
radius= qh PRINTradius;
818
if (qh JOGGLEmax < REALmax/2)
819
radius -= qh JOGGLEmax * sqrt (qh hull_dim); /* already accounted for in qh_outerinner() */
820
*outerplane += radius;
821
*innerplane -= radius;
822
if (qh PRINTcoplanar || qh PRINTspheres) {
823
*outerplane += qh MAXabs_coord * qh_GEOMepsilon;
824
*innerplane -= qh MAXabs_coord * qh_GEOMepsilon;
827
*innerplane= *outerplane= 0;
831
/*-<a href="qh-io.htm#TOC"
832
>-------------------------------</a><a name="markkeep">-</a>
834
qh_markkeep( facetlist )
835
mark good facets that meet qh.KEEParea, qh.KEEPmerge, and qh.KEEPminArea
836
ignores visible facets (not part of convex hull)
839
may clear facet->good
840
recomputes qh.num_good
843
get set of good facets
846
clear facet->good for all but n largest facets
848
sort facets by merge count
849
clear facet->good for all but n most merged facets
851
clear facet->good if area too small
854
void qh_markkeep (facetT *facetlist) {
855
facetT *facet, **facetp;
856
setT *facets= qh_settemp (qh num_facets);
859
trace2((qh ferr, "qh_markkeep: only keep %d largest and/or %d most merged facets and/or min area %.2g\n",
860
qh KEEParea, qh KEEPmerge, qh KEEPminArea));
861
FORALLfacet_(facetlist) {
862
if (!facet->visible && facet->good)
863
qh_setappend (&facets, facet);
865
size= qh_setsize (facets);
867
qsort (SETaddr_(facets, facetT), size,
868
sizeof (facetT *), qh_compare_facetarea);
869
if ((count= size - qh KEEParea) > 0) {
870
FOREACHfacet_(facets) {
878
qsort (SETaddr_(facets, facetT), size,
879
sizeof (facetT *), qh_compare_facetmerge);
880
if ((count= size - qh KEEPmerge) > 0) {
881
FOREACHfacet_(facets) {
888
if (qh KEEPminArea < REALmax/2) {
889
FOREACHfacet_(facets) {
890
if (!facet->isarea || facet->f.area < qh KEEPminArea)
894
qh_settempfree (&facets);
896
FORALLfacet_(facetlist) {
904
/*-<a href="qh-io.htm#TOC"
905
>-------------------------------</a><a name="markvoronoi">-</a>
907
qh_markvoronoi( facetlist, facets, printall, islower, numcenters )
908
mark voronoi vertices for printing by site pairs
911
temporary set of vertices indexed by pointid
912
islower set if printing lower hull (i.e., at least one facet is lower hull)
913
numcenters= total number of Voronoi vertices
914
bumps qh.printoutnum for vertex-at-infinity
915
clears all facet->seen and sets facet->seen2
918
facet->visitid= Voronoi vertex id
919
else if upper hull (or 'Qu' and lower hull)
922
facet->visitid >= qh num_facets
925
ignores qh.ATinfinity, if defined
927
setT *qh_markvoronoi (facetT *facetlist, setT *facets, boolT printall, boolT *islowerp, int *numcentersp) {
929
facetT *facet, **facetp;
931
boolT islower= False;
934
qh_clearcenters (qh_ASvoronoi); /* in case, qh_printvdiagram2 called by user */
935
qh_vertexneighbors();
936
vertices= qh_pointvertex();
938
SETelem_(vertices, qh num_points-1)= NULL;
940
maximize_(qh visit_id, (unsigned) qh num_facets);
941
FORALLfacet_(facetlist) {
942
if (printall || !qh_skipfacet (facet)) {
943
if (!facet->upperdelaunay) {
949
FOREACHfacet_(facets) {
950
if (printall || !qh_skipfacet (facet)) {
951
if (!facet->upperdelaunay) {
958
if (facet->normal && (facet->upperdelaunay == islower))
959
facet->visitid= 0; /* facetlist or facets may overwrite */
961
facet->visitid= qh visit_id;
965
numcenters++; /* qh_INFINITE */
966
FORALLfacet_(facetlist) {
967
if (printall || !qh_skipfacet (facet))
968
facet->visitid= numcenters++;
970
FOREACHfacet_(facets) {
971
if (printall || !qh_skipfacet (facet))
972
facet->visitid= numcenters++;
975
*numcentersp= numcenters;
976
trace2((qh ferr, "qh_markvoronoi: islower %d numcenters %d\n", islower, numcenters));
980
/*-<a href="qh-io.htm#TOC"
981
>-------------------------------</a><a name="order_vertexneighbors">-</a>
983
qh_order_vertexneighbors( vertex )
984
order facet neighbors of a 2-d or 3-d vertex by adjacency
987
does not orient the neighbors
990
initialize a new neighbor set with the first facet in vertex->neighbors
991
while vertex->neighbors non-empty
992
select next neighbor in the previous facet's neighbor set
993
set vertex->neighbors to the new neighbor set
995
void qh_order_vertexneighbors(vertexT *vertex) {
997
facetT *facet, *neighbor, **neighborp;
999
trace4((qh ferr, "qh_order_vertexneighbors: order neighbors of v%d for 3-d\n", vertex->id));
1000
newset= qh_settemp (qh_setsize (vertex->neighbors));
1001
facet= (facetT*)qh_setdellast (vertex->neighbors);
1002
qh_setappend (&newset, facet);
1003
while (qh_setsize (vertex->neighbors)) {
1004
FOREACHneighbor_(vertex) {
1005
if (qh_setin (facet->neighbors, neighbor)) {
1006
qh_setdel(vertex->neighbors, neighbor);
1007
qh_setappend (&newset, neighbor);
1013
fprintf (qh ferr, "qhull internal error (qh_order_vertexneighbors): no neighbor of v%d for f%d\n",
1014
vertex->id, facet->id);
1015
qh_errexit (qh_ERRqhull, facet, NULL);
1018
qh_setfree (&vertex->neighbors);
1020
vertex->neighbors= newset;
1021
} /* order_vertexneighbors */
1023
/*-<a href="qh-io.htm#TOC"
1024
>-------------------------------</a><a name="printafacet">-</a>
1026
qh_printafacet( fp, format, facet, printall )
1027
print facet to fp in given output format (see qh.PRINTout)
1030
nop if !printall and qh_skipfacet()
1031
nop if visible facet and NEWfacets and format != PRINTfacets
1032
must match qh_countfacets
1035
preserves qh.visit_id
1036
facet->normal may be null if PREmerge/MERGEexact and STOPcone before merge
1039
qh_printbegin() and qh_printend()
1042
test for printing facet
1043
call appropriate routine for format
1044
or output results directly
1046
void qh_printafacet(FILE *fp, int format, facetT *facet, boolT printall) {
1047
realT color[4], offset, dist, outerplane, innerplane;
1049
coordT *point, *normp, *coordp, **pointp, *feasiblep;
1051
vertexT *vertex, **vertexp;
1052
facetT *neighbor, **neighborp;
1054
if (!printall && qh_skipfacet (facet))
1056
if (facet->visible && qh NEWfacets && format != qh_PRINTfacets)
1061
if (facet->isarea) {
1062
fprintf (fp, qh_REAL_1, facet->f.area);
1065
fprintf (fp, "0\n");
1067
case qh_PRINTcoplanars:
1068
fprintf (fp, "%d", qh_setsize (facet->coplanarset));
1069
FOREACHpoint_(facet->coplanarset)
1070
fprintf (fp, " %d", qh_pointid (point));
1073
case qh_PRINTcentrums:
1074
qh_printcenter (fp, format, NULL, facet);
1076
case qh_PRINTfacets:
1077
qh_printfacet (fp, facet);
1079
case qh_PRINTfacets_xridge:
1080
qh_printfacetheader (fp, facet);
1082
case qh_PRINTgeom: /* either 2 , 3, or 4-d by qh_printbegin */
1085
for (k= qh hull_dim; k--; ) {
1086
color[k]= (facet->normal[k]+1.0)/2.0;
1087
maximize_(color[k], -1.0);
1088
minimize_(color[k], +1.0);
1090
qh_projectdim3 (color, color);
1091
if (qh PRINTdim != qh hull_dim)
1092
qh_normalize2 (color, 3, True, NULL, NULL);
1093
if (qh hull_dim <= 2)
1094
qh_printfacet2geom (fp, facet, color);
1095
else if (qh hull_dim == 3) {
1096
if (facet->simplicial)
1097
qh_printfacet3geom_simplicial (fp, facet, color);
1099
qh_printfacet3geom_nonsimplicial (fp, facet, color);
1101
if (facet->simplicial)
1102
qh_printfacet4geom_simplicial (fp, facet, color);
1104
qh_printfacet4geom_nonsimplicial (fp, facet, color);
1108
fprintf (fp, "%d\n", facet->id);
1110
case qh_PRINTincidences:
1112
case qh_PRINTtriangles:
1113
if (qh hull_dim == 3 && format != qh_PRINTtriangles)
1114
qh_printfacet3vertex (fp, facet, format);
1115
else if (facet->simplicial || qh hull_dim == 2 || format == qh_PRINToff)
1116
qh_printfacetNvertex_simplicial (fp, facet, format);
1118
qh_printfacetNvertex_nonsimplicial (fp, facet, qh printoutvar++, format);
1121
qh_outerinner (facet, NULL, &innerplane);
1122
offset= facet->offset - innerplane;
1123
goto LABELprintnorm;
1124
break; /* prevent warning */
1125
case qh_PRINTmerges:
1126
fprintf (fp, "%d\n", facet->nummerge);
1128
case qh_PRINTnormals:
1129
offset= facet->offset;
1130
goto LABELprintnorm;
1131
break; /* prevent warning */
1133
qh_outerinner (facet, &outerplane, NULL);
1134
offset= facet->offset - outerplane;
1136
if (!facet->normal) {
1137
fprintf (fp, "no normal for facet f%d\n", facet->id);
1141
fprintf (fp, qh_REAL_1, -offset);
1142
for (k=0; k < qh hull_dim; k++)
1143
fprintf (fp, qh_REAL_1, -facet->normal[k]);
1145
for (k=0; k < qh hull_dim; k++)
1146
fprintf (fp, qh_REAL_1, facet->normal[k]);
1147
fprintf (fp, qh_REAL_1, offset);
1151
case qh_PRINTmathematica: /* either 2 or 3-d by qh_printbegin */
1153
if (qh hull_dim == 2)
1154
qh_printfacet2math (fp, facet, format, qh printoutvar++);
1156
qh_printfacet3math (fp, facet, format, qh printoutvar++);
1158
case qh_PRINTneighbors:
1159
fprintf (fp, "%d", qh_setsize (facet->neighbors));
1160
FOREACHneighbor_(facet)
1162
neighbor->visitid ? neighbor->visitid - 1: - neighbor->id);
1165
case qh_PRINTpointintersect:
1166
if (!qh feasible_point) {
1167
fprintf (fp, "qhull input error (qh_printafacet): option 'Fp' needs qh feasible_point\n");
1168
qh_errexit( qh_ERRinput, NULL, NULL);
1170
if (facet->offset > 0)
1171
goto LABELprintinfinite;
1172
point= coordp= (coordT*)qh_memalloc (qh normal_size);
1173
normp= facet->normal;
1174
feasiblep= qh feasible_point;
1175
if (facet->offset < -qh MINdenom) {
1176
for (k= qh hull_dim; k--; )
1177
*(coordp++)= (*(normp++) / - facet->offset) + *(feasiblep++);
1179
for (k= qh hull_dim; k--; ) {
1180
*(coordp++)= qh_divzero (*(normp++), facet->offset, qh MINdenom_1,
1181
&zerodiv) + *(feasiblep++);
1183
qh_memfree (point, qh normal_size);
1184
goto LABELprintinfinite;
1188
qh_printpoint (fp, NULL, point);
1189
qh_memfree (point, qh normal_size);
1192
for (k= qh hull_dim; k--; )
1193
fprintf (fp, qh_REAL_1, qh_INFINITE);
1196
case qh_PRINTpointnearest:
1197
FOREACHpoint_(facet->coplanarset) {
1199
vertex= qh_nearvertex (facet, point, &dist);
1200
id= qh_pointid (vertex->point);
1201
id2= qh_pointid (point);
1202
fprintf (fp, "%d %d %d " qh_REAL_1 "\n", id, id2, facet->id, dist);
1205
case qh_PRINTpoints: /* VORONOI only by qh_printbegin */
1208
qh_printcenter (fp, format, NULL, facet);
1210
case qh_PRINTvertices:
1211
fprintf (fp, "%d", qh_setsize (facet->vertices));
1212
FOREACHvertex_(facet->vertices)
1213
fprintf (fp, " %d", qh_pointid (vertex->point));
1219
/*-<a href="qh-io.htm#TOC"
1220
>-------------------------------</a><a name="printbegin">-</a>
1223
prints header for all output formats
1226
checks for valid format
1229
uses qh.visit_id for 3/4off
1230
changes qh.interior_point if printing centrums
1231
qh_countfacets clears facet->visitid for non-good facets
1234
qh_printend() and qh_printafacet()
1237
count facets and related statistics
1238
print header for format
1240
void qh_printbegin (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
1241
int numfacets, numsimplicial, numridges, totneighbors, numcoplanars, numtricoplanars;
1243
facetT *facet, **facetp;
1244
vertexT *vertex, **vertexp;
1246
pointT *point, **pointp, *pointtemp;
1249
qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial,
1250
&totneighbors, &numridges, &numcoplanars, &numtricoplanars);
1255
fprintf (fp, "%d\n", numfacets);
1257
case qh_PRINTcoplanars:
1258
fprintf (fp, "%d\n", numfacets);
1260
case qh_PRINTcentrums:
1261
if (qh CENTERtype == qh_ASnone)
1262
qh_clearcenters (qh_AScentrum);
1263
fprintf (fp, "%d\n%d\n", qh hull_dim, numfacets);
1265
case qh_PRINTfacets:
1266
case qh_PRINTfacets_xridge:
1268
qh_printvertexlist (fp, "Vertices and facets:\n", facetlist, facets, printall);
1271
if (qh hull_dim > 4) /* qh_initqhull_globals also checks */
1273
if (qh VORONOI && qh hull_dim > 3) /* PRINTdim == DROPdim == hull_dim-1 */
1275
if (qh hull_dim == 2 && (qh PRINTridges || qh DOintersections))
1276
fprintf (qh ferr, "qhull warning: output for ridges and intersections not implemented in 2-d\n");
1277
if (qh hull_dim == 4 && (qh PRINTinner || qh PRINTouter ||
1278
(qh PRINTdim == 4 && qh PRINTcentrums)))
1279
fprintf (qh ferr, "qhull warning: output for outer/inner planes and centrums not implemented in 4-d\n");
1280
if (qh PRINTdim == 4 && (qh PRINTspheres))
1281
fprintf (qh ferr, "qhull warning: output for vertices not implemented in 4-d\n");
1282
if (qh PRINTdim == 4 && qh DOintersections && qh PRINTnoplanes)
1283
fprintf (qh ferr, "qhull warning: 'Gnh' generates no output in 4-d\n");
1284
if (qh PRINTdim == 2) {
1285
fprintf(fp, "{appearance {linewidth 3} LIST # %s | %s\n",
1286
qh rbox_command, qh qhull_command);
1287
}else if (qh PRINTdim == 3) {
1288
fprintf(fp, "{appearance {+edge -evert linewidth 2} LIST # %s | %s\n",
1289
qh rbox_command, qh qhull_command);
1290
}else if (qh PRINTdim == 4) {
1293
FORALLfacet_(facetlist) /* get number of ridges to be printed */
1294
qh_printend4geom (NULL, facet, &num, printall);
1295
FOREACHfacet_(facets)
1296
qh_printend4geom (NULL, facet, &num, printall);
1297
qh ridgeoutnum= num;
1298
qh printoutvar= 0; /* counts number of ridges in output */
1299
fprintf (fp, "LIST # %s | %s\n", qh rbox_command, qh qhull_command);
1303
num= qh num_points + qh_setsize (qh other_points);
1304
if (qh DELAUNAY && qh ATinfinity)
1306
if (qh PRINTdim == 4)
1307
fprintf (fp, "4VECT %d %d 1\n", num, num);
1309
fprintf (fp, "VECT %d %d 1\n", num, num);
1310
for (i= num; i--; ) {
1315
fprintf (fp, "# 1 point per line\n1 ");
1316
for (i= num-1; i--; ) {
1321
fprintf (fp, "# 1 color for all\n");
1323
if (!qh DELAUNAY || !qh ATinfinity || qh_pointid(point) != qh num_points-1) {
1324
if (qh PRINTdim == 4)
1325
qh_printpoint (fp, NULL, point);
1327
qh_printpoint3 (fp, point);
1330
FOREACHpoint_(qh other_points) {
1331
if (qh PRINTdim == 4)
1332
qh_printpoint (fp, NULL, point);
1334
qh_printpoint3 (fp, point);
1336
fprintf (fp, "0 1 1 1 # color of points\n");
1338
if (qh PRINTdim == 4 && !qh PRINTnoplanes)
1339
/* 4dview loads up multiple 4OFF objects slowly */
1340
fprintf(fp, "4OFF %d %d 1\n", 3*qh ridgeoutnum, qh ridgeoutnum);
1341
qh PRINTcradius= 2 * qh DISTround; /* include test DISTround */
1343
maximize_(qh PRINTcradius, qh premerge_centrum + qh DISTround);
1344
}else if (qh POSTmerge)
1345
maximize_(qh PRINTcradius, qh postmerge_centrum + qh DISTround);
1346
qh PRINTradius= qh PRINTcradius;
1347
if (qh PRINTspheres + qh PRINTcoplanar)
1348
maximize_(qh PRINTradius, qh MAXabs_coord * qh_MINradius);
1349
if (qh premerge_cos < REALmax/2) {
1350
maximize_(qh PRINTradius, (1- qh premerge_cos) * qh MAXabs_coord);
1351
}else if (!qh PREmerge && qh POSTmerge && qh postmerge_cos < REALmax/2) {
1352
maximize_(qh PRINTradius, (1- qh postmerge_cos) * qh MAXabs_coord);
1354
maximize_(qh PRINTradius, qh MINvisible);
1355
if (qh JOGGLEmax < REALmax/2)
1356
qh PRINTradius += qh JOGGLEmax * sqrt (qh hull_dim);
1357
if (qh PRINTdim != 4 &&
1358
(qh PRINTcoplanar || qh PRINTspheres || qh PRINTcentrums)) {
1359
vertices= qh_facetvertices (facetlist, facets, printall);
1360
if (qh PRINTspheres && qh PRINTdim <= 3)
1361
qh_printspheres (fp, vertices, qh PRINTradius);
1362
if (qh PRINTcoplanar || qh PRINTcentrums) {
1363
qh firstcentrum= True;
1364
if (qh PRINTcoplanar&& !qh PRINTspheres) {
1365
FOREACHvertex_(vertices)
1366
qh_printpointvect2 (fp, vertex->point, NULL,
1367
qh interior_point, qh PRINTradius);
1369
FORALLfacet_(facetlist) {
1370
if (!printall && qh_skipfacet(facet))
1374
if (qh PRINTcentrums && qh PRINTdim <= 3)
1375
qh_printcentrum (fp, facet, qh PRINTcradius);
1376
if (!qh PRINTcoplanar)
1378
FOREACHpoint_(facet->coplanarset)
1379
qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
1380
FOREACHpoint_(facet->outsideset)
1381
qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
1383
FOREACHfacet_(facets) {
1384
if (!printall && qh_skipfacet(facet))
1388
if (qh PRINTcentrums && qh PRINTdim <= 3)
1389
qh_printcentrum (fp, facet, qh PRINTcradius);
1390
if (!qh PRINTcoplanar)
1392
FOREACHpoint_(facet->coplanarset)
1393
qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
1394
FOREACHpoint_(facet->outsideset)
1395
qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
1398
qh_settempfree (&vertices);
1400
qh visit_id++; /* for printing hyperplane intersections */
1403
fprintf (fp, "%d\n", numfacets);
1405
case qh_PRINTincidences:
1406
if (qh VORONOI && qh PRINTprecision)
1407
fprintf (qh ferr, "qhull warning: writing Delaunay. Use 'p' or 'o' for Voronoi centers\n");
1408
qh printoutvar= qh vertex_id; /* centrum id for non-simplicial facets */
1409
if (qh hull_dim <= 3)
1410
fprintf(fp, "%d\n", numfacets);
1412
fprintf(fp, "%d\n", numsimplicial+numridges);
1415
case qh_PRINTnormals:
1418
fprintf (fp, "%s | %s\nbegin\n %d %d real\n", qh rbox_command,
1419
qh qhull_command, numfacets, qh hull_dim+1);
1421
fprintf (fp, "%d\n%d\n", qh hull_dim+1, numfacets);
1423
case qh_PRINTmathematica:
1425
if (qh hull_dim > 3) /* qh_initbuffers also checks */
1428
fprintf (qh ferr, "qhull warning: output is the Delaunay triangulation\n");
1429
if (format == qh_PRINTmaple) {
1430
if (qh hull_dim == 2)
1431
fprintf(fp, "PLOT(CURVES(\n");
1433
fprintf(fp, "PLOT3D(POLYGONS(\n");
1436
qh printoutvar= 0; /* counts number of facets for notfirst */
1438
case qh_PRINTmerges:
1439
fprintf (fp, "%d\n", numfacets);
1441
case qh_PRINTpointintersect:
1442
fprintf (fp, "%d\n%d\n", qh hull_dim, numfacets);
1444
case qh_PRINTneighbors:
1445
fprintf (fp, "%d\n", numfacets);
1448
case qh_PRINTtriangles:
1452
if (format == qh_PRINToff || qh hull_dim == 2)
1453
fprintf (fp, "%d\n%d %d %d\n", num,
1454
qh num_points+qh_setsize (qh other_points), numfacets, totneighbors/2);
1455
else { /* qh_PRINTtriangles */
1456
qh printoutvar= qh num_points+qh_setsize (qh other_points); /* first centrum */
1458
num--; /* drop last dimension */
1459
fprintf (fp, "%d\n%d %d %d\n", num, qh printoutvar
1460
+ numfacets - numsimplicial, numsimplicial + numridges, totneighbors/2);
1463
qh_printpointid (qh fout, NULL, num, point, -1);
1464
FOREACHpoint_(qh other_points)
1465
qh_printpointid (qh fout, NULL, num, point, -1);
1466
if (format == qh_PRINTtriangles && qh hull_dim > 2) {
1468
if (!facet->simplicial && facet->visitid)
1469
qh_printcenter (qh fout, format, NULL, facet);
1473
case qh_PRINTpointnearest:
1474
fprintf (fp, "%d\n", numcoplanars);
1476
case qh_PRINTpoints:
1480
fprintf (fp, "%s | %s\nbegin\n%d %d real\n", qh rbox_command,
1481
qh qhull_command, numfacets, qh hull_dim);
1483
fprintf (fp, "%d\n%d\n", qh hull_dim-1, numfacets);
1485
case qh_PRINTvertices:
1486
fprintf (fp, "%d\n", numfacets);
1488
case qh_PRINTsummary:
1491
fprintf (qh ferr, "qhull internal error (qh_printbegin): can not use this format for dimension %d\n",
1493
qh_errexit (qh_ERRqhull, NULL, NULL);
1497
/*-<a href="qh-io.htm#TOC"
1498
>-------------------------------</a><a name="printcenter">-</a>
1500
qh_printcenter( fp, string, facet )
1501
print facet->center as centrum or Voronoi center
1502
string may be NULL. Don't include '%' codes.
1503
nop if qh CENTERtype neither CENTERvoronoi nor CENTERcentrum
1504
if upper envelope of Delaunay triangulation and point at-infinity
1505
prints qh_INFINITE instead;
1508
defines facet->center if needed
1509
if format=PRINTgeom, adds a 0 if would otherwise be 2-d
1511
void qh_printcenter (FILE *fp, int format, char *string, facetT *facet) {
1514
if (qh CENTERtype != qh_ASvoronoi && qh CENTERtype != qh_AScentrum)
1517
fprintf (fp, string, facet->id);
1518
if (qh CENTERtype == qh_ASvoronoi) {
1520
if (!facet->normal || !facet->upperdelaunay || !qh ATinfinity) {
1522
facet->center= qh_facetcenter (facet->vertices);
1523
for (k=0; k < num; k++)
1524
fprintf (fp, qh_REAL_1, facet->center[k]);
1526
for (k=0; k < num; k++)
1527
fprintf (fp, qh_REAL_1, qh_INFINITE);
1529
}else /* qh CENTERtype == qh_AScentrum */ {
1531
if (format == qh_PRINTtriangles && qh DELAUNAY)
1534
facet->center= qh_getcentrum (facet);
1535
for (k=0; k < num; k++)
1536
fprintf (fp, qh_REAL_1, facet->center[k]);
1538
if (format == qh_PRINTgeom && num == 2)
1539
fprintf (fp, " 0\n");
1544
/*-<a href="qh-io.htm#TOC"
1545
>-------------------------------</a><a name="printcentrum">-</a>
1547
qh_printcentrum( fp, facet, radius )
1548
print centrum for a facet in OOGL format
1549
radius defines size of centrum
1553
defines facet->center if needed
1555
void qh_printcentrum (FILE *fp, facetT *facet, realT radius) {
1556
pointT *centrum, *projpt;
1557
boolT tempcentrum= False;
1558
realT xaxis[4], yaxis[4], normal[4], dist;
1559
realT green[3]={0, 1, 0};
1563
if (qh CENTERtype == qh_AScentrum) {
1565
facet->center= qh_getcentrum (facet);
1566
centrum= facet->center;
1568
centrum= qh_getcentrum (facet);
1571
fprintf (fp, "{appearance {-normal -edge normscale 0} ");
1572
if (qh firstcentrum) {
1573
qh firstcentrum= False;
1574
fprintf (fp, "{INST geom { define centrum CQUAD # f%d\n\
1575
-0.3 -0.3 0.0001 0 0 1 1\n\
1576
0.3 -0.3 0.0001 0 0 1 1\n\
1577
0.3 0.3 0.0001 0 0 1 1\n\
1578
-0.3 0.3 0.0001 0 0 1 1 } transform { \n", facet->id);
1580
fprintf (fp, "{INST geom { : centrum } transform { # f%d\n", facet->id);
1581
apex= SETfirstt_(facet->vertices, vertexT);
1582
qh_distplane(apex->point, facet, &dist);
1583
projpt= qh_projectpoint(apex->point, facet, dist);
1584
for (k= qh hull_dim; k--; ) {
1585
xaxis[k]= projpt[k] - centrum[k];
1586
normal[k]= facet->normal[k];
1588
if (qh hull_dim == 2) {
1591
}else if (qh hull_dim == 4) {
1592
qh_projectdim3 (xaxis, xaxis);
1593
qh_projectdim3 (normal, normal);
1594
qh_normalize2 (normal, qh PRINTdim, True, NULL, NULL);
1596
qh_crossproduct (3, xaxis, normal, yaxis);
1597
fprintf (fp, "%8.4g %8.4g %8.4g 0\n", xaxis[0], xaxis[1], xaxis[2]);
1598
fprintf (fp, "%8.4g %8.4g %8.4g 0\n", yaxis[0], yaxis[1], yaxis[2]);
1599
fprintf (fp, "%8.4g %8.4g %8.4g 0\n", normal[0], normal[1], normal[2]);
1600
qh_printpoint3 (fp, centrum);
1601
fprintf (fp, "1 }}}\n");
1602
qh_memfree (projpt, qh normal_size);
1603
qh_printpointvect (fp, centrum, facet->normal, NULL, radius, green);
1605
qh_memfree (centrum, qh normal_size);
1606
} /* printcentrum */
1608
/*-<a href="qh-io.htm#TOC"
1609
>-------------------------------</a><a name="printend">-</a>
1611
qh_printend( fp, format )
1612
prints trailer for all output formats
1615
qh_printbegin() and qh_printafacet()
1618
void qh_printend (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
1620
facetT *facet, **facetp;
1622
if (!qh printoutnum)
1623
fprintf (qh ferr, "qhull warning: no facets printed\n");
1626
if (qh hull_dim == 4 && qh DROPdim < 0 && !qh PRINTnoplanes) {
1629
FORALLfacet_(facetlist)
1630
qh_printend4geom (fp, facet,&num, printall);
1631
FOREACHfacet_(facets)
1632
qh_printend4geom (fp, facet, &num, printall);
1633
if (num != qh ridgeoutnum || qh printoutvar != qh ridgeoutnum) {
1634
fprintf (qh ferr, "qhull internal error (qh_printend): number of ridges %d != number printed %d and at end %d\n", qh ridgeoutnum, qh printoutvar, num);
1635
qh_errexit (qh_ERRqhull, NULL, NULL);
1641
case qh_PRINTnormals:
1644
fprintf (fp, "end\n");
1647
fprintf(fp, "));\n");
1649
case qh_PRINTmathematica:
1652
case qh_PRINTpoints:
1654
fprintf (fp, "end\n");
1659
/*-<a href="qh-io.htm#TOC"
1660
>-------------------------------</a><a name="printend4geom">-</a>
1662
qh_printend4geom( fp, facet, numridges, printall )
1663
helper function for qh_printbegin/printend
1666
number of printed ridges
1669
just counts printed ridges if fp=NULL
1671
must agree with qh_printfacet4geom...
1674
computes color for facet from its normal
1675
prints each ridge of facet
1677
void qh_printend4geom (FILE *fp, facetT *facet, int *nump, boolT printall) {
1680
facetT *neighbor, **neighborp;
1681
ridgeT *ridge, **ridgep;
1683
if (!printall && qh_skipfacet(facet))
1685
if (qh PRINTnoplanes || (facet->visible && qh NEWfacets))
1690
for (i=0; i < 3; i++) {
1691
color[i]= (facet->normal[i]+1.0)/2.0;
1692
maximize_(color[i], -1.0);
1693
minimize_(color[i], +1.0);
1696
facet->visitid= qh visit_id;
1697
if (facet->simplicial) {
1698
FOREACHneighbor_(facet) {
1699
if (neighbor->visitid != qh visit_id) {
1701
fprintf (fp, "3 %d %d %d %8.4g %8.4g %8.4g 1 # f%d f%d\n",
1702
3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],
1703
facet->id, neighbor->id);
1708
FOREACHridge_(facet->ridges) {
1709
neighbor= otherfacet_(ridge, facet);
1710
if (neighbor->visitid != qh visit_id) {
1712
fprintf (fp, "3 %d %d %d %8.4g %8.4g %8.4g 1 #r%d f%d f%d\n",
1713
3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],
1714
ridge->id, facet->id, neighbor->id);
1720
} /* printend4geom */
1722
/*-<a href="qh-io.htm#TOC"
1723
>-------------------------------</a><a name="printextremes">-</a>
1725
qh_printextremes( fp, facetlist, facets, printall )
1726
print extreme points for convex hulls or halfspace intersections
1729
#points, followed by ids, one per line
1732
same order as qh_printpoints_out if no coplanar/interior points
1734
void qh_printextremes (FILE *fp, facetT *facetlist, setT *facets, int printall) {
1735
setT *vertices, *points;
1737
vertexT *vertex, **vertexp;
1739
int numpoints=0, point_i, point_n;
1740
int allpoints= qh num_points + qh_setsize (qh other_points);
1742
points= qh_settemp (allpoints);
1743
qh_setzero (points, 0, allpoints);
1744
vertices= qh_facetvertices (facetlist, facets, printall);
1745
FOREACHvertex_(vertices) {
1746
id= qh_pointid (vertex->point);
1748
SETelem_(points, id)= vertex->point;
1752
qh_settempfree (&vertices);
1753
fprintf (fp, "%d\n", numpoints);
1754
FOREACHpoint_i_(points) {
1756
fprintf (fp, "%d\n", point_i);
1758
qh_settempfree (&points);
1759
} /* printextremes */
1761
/*-<a href="qh-io.htm#TOC"
1762
>-------------------------------</a><a name="printextremes_2d">-</a>
1764
qh_printextremes_2d( fp, facetlist, facets, printall )
1765
prints point ids for facets in qh_ORIENTclock order
1768
#points, followed by ids, one per line
1769
if facetlist/facets are disjoint than the output includes skips
1770
errors if facets form a loop
1771
does not print coplanar points
1773
void qh_printextremes_2d (FILE *fp, facetT *facetlist, setT *facets, int printall) {
1774
int numfacets, numridges, totneighbors, numcoplanars, numsimplicial, numtricoplanars;
1776
facetT *facet, *startfacet, *nextfacet;
1777
vertexT *vertexA, *vertexB;
1779
qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial,
1780
&totneighbors, &numridges, &numcoplanars, &numtricoplanars); /* marks qh visit_id */
1781
vertices= qh_facetvertices (facetlist, facets, printall);
1782
fprintf(fp, "%d\n", qh_setsize (vertices));
1783
qh_settempfree (&vertices);
1786
facet= startfacet= facetlist ? facetlist : SETfirstt_(facets, facetT);
1790
if (facet->toporient ^ qh_ORIENTclock) {
1791
vertexA= SETfirstt_(facet->vertices, vertexT);
1792
vertexB= SETsecondt_(facet->vertices, vertexT);
1793
nextfacet= SETfirstt_(facet->neighbors, facetT);
1795
vertexA= SETsecondt_(facet->vertices, vertexT);
1796
vertexB= SETfirstt_(facet->vertices, vertexT);
1797
nextfacet= SETsecondt_(facet->neighbors, facetT);
1799
if (facet->visitid == qh visit_id) {
1800
fprintf(qh ferr, "qh_printextremes_2d: loop in facet list. facet %d nextfacet %d\n",
1801
facet->id, nextfacet->id);
1802
qh_errexit2 (qh_ERRqhull, facet, nextfacet);
1804
if (facet->visitid) {
1805
if (vertexA->visitid != qh vertex_visit) {
1806
vertexA->visitid= qh vertex_visit;
1807
fprintf(fp, "%d\n", qh_pointid (vertexA->point));
1809
if (vertexB->visitid != qh vertex_visit) {
1810
vertexB->visitid= qh vertex_visit;
1811
fprintf(fp, "%d\n", qh_pointid (vertexB->point));
1814
facet->visitid= qh visit_id;
1816
}while (facet && facet != startfacet);
1817
} /* printextremes_2d */
1819
/*-<a href="qh-io.htm#TOC"
1820
>-------------------------------</a><a name="printextremes_d">-</a>
1822
qh_printextremes_d( fp, facetlist, facets, printall )
1823
print extreme points of input sites for Delaunay triangulations
1826
#points, followed by ids, one per line
1830
void qh_printextremes_d (FILE *fp, facetT *facetlist, setT *facets, int printall) {
1832
vertexT *vertex, **vertexp;
1833
boolT upperseen, lowerseen;
1834
facetT *neighbor, **neighborp;
1837
vertices= qh_facetvertices (facetlist, facets, printall);
1838
qh_vertexneighbors();
1839
FOREACHvertex_(vertices) {
1840
upperseen= lowerseen= False;
1841
FOREACHneighbor_(vertex) {
1842
if (neighbor->upperdelaunay)
1847
if (upperseen && lowerseen) {
1851
vertex->seen= False;
1853
fprintf (fp, "%d\n", numpoints);
1854
FOREACHvertex_(vertices) {
1856
fprintf (fp, "%d\n", qh_pointid (vertex->point));
1858
qh_settempfree (&vertices);
1859
} /* printextremes_d */
1861
/*-<a href="qh-io.htm#TOC"
1862
>-------------------------------</a><a name="printfacet">-</a>
1864
qh_printfacet( fp, facet )
1865
prints all fields of a facet to fp
1868
ridges printed in neighbor order
1870
void qh_printfacet(FILE *fp, facetT *facet) {
1872
qh_printfacetheader (fp, facet);
1874
qh_printfacetridges (fp, facet);
1878
/*-<a href="qh-io.htm#TOC"
1879
>-------------------------------</a><a name="printfacet2geom">-</a>
1881
qh_printfacet2geom( fp, facet, color )
1882
print facet as part of a 2-d VECT for Geomview
1885
assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
1886
mindist is calculated within io.c. maxoutside is calculated elsewhere
1887
so a DISTround error may have occured.
1889
void qh_printfacet2geom(FILE *fp, facetT *facet, realT color[3]) {
1890
pointT *point0, *point1;
1891
realT mindist, innerplane, outerplane;
1894
qh_facet2point (facet, &point0, &point1, &mindist);
1895
qh_geomplanes (facet, &outerplane, &innerplane);
1896
if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner))
1897
qh_printfacet2geom_points(fp, point0, point1, facet, outerplane, color);
1898
if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter &&
1899
outerplane - innerplane > 2 * qh MAXabs_coord * qh_GEOMepsilon)) {
1901
color[k]= 1.0 - color[k];
1902
qh_printfacet2geom_points(fp, point0, point1, facet, innerplane, color);
1904
qh_memfree (point1, qh normal_size);
1905
qh_memfree (point0, qh normal_size);
1906
} /* printfacet2geom */
1908
/*-<a href="qh-io.htm#TOC"
1909
>-------------------------------</a><a name="printfacet2geom_points">-</a>
1911
qh_printfacet2geom_points( fp, point1, point2, facet, offset, color )
1912
prints a 2-d facet as a VECT with 2 points at some offset.
1913
The points are on the facet's plane.
1915
void qh_printfacet2geom_points(FILE *fp, pointT *point1, pointT *point2,
1916
facetT *facet, realT offset, realT color[3]) {
1917
pointT *p1= point1, *p2= point2;
1919
fprintf(fp, "VECT 1 2 1 2 1 # f%d\n", facet->id);
1920
if (offset != 0.0) {
1921
p1= qh_projectpoint (p1, facet, -offset);
1922
p2= qh_projectpoint (p2, facet, -offset);
1924
fprintf(fp, "%8.4g %8.4g %8.4g\n%8.4g %8.4g %8.4g\n",
1925
p1[0], p1[1], 0.0, p2[0], p2[1], 0.0);
1926
if (offset != 0.0) {
1927
qh_memfree (p1, qh normal_size);
1928
qh_memfree (p2, qh normal_size);
1930
fprintf(fp, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
1931
} /* printfacet2geom_points */
1934
/*-<a href="qh-io.htm#TOC"
1935
>-------------------------------</a><a name="printfacet2math">-</a>
1937
qh_printfacet2math( fp, facet, format, notfirst )
1938
print 2-d Maple or Mathematica output for a facet
1939
may be non-simplicial
1942
use %16.8f since Mathematica 2.2 does not handle exponential format
1943
see qh_printfacet3math
1945
void qh_printfacet2math(FILE *fp, facetT *facet, int format, int notfirst) {
1946
pointT *point0, *point1;
1950
qh_facet2point (facet, &point0, &point1, &mindist);
1953
if (format == qh_PRINTmaple)
1954
pointfmt= "[[%16.8f, %16.8f], [%16.8f, %16.8f]]\n";
1956
pointfmt= "Line[{{%16.8f, %16.8f}, {%16.8f, %16.8f}}]\n";
1957
fprintf(fp, pointfmt, point0[0], point0[1], point1[0], point1[1]);
1958
qh_memfree (point1, qh normal_size);
1959
qh_memfree (point0, qh normal_size);
1960
} /* printfacet2math */
1963
/*-<a href="qh-io.htm#TOC"
1964
>-------------------------------</a><a name="printfacet3geom_nonsimplicial">-</a>
1966
qh_printfacet3geom_nonsimplicial( fp, facet, color )
1967
print Geomview OFF for a 3-d nonsimplicial facet.
1968
if DOintersections, prints ridges to unvisited neighbors (qh visit_id)
1971
uses facet->visitid for intersections and ridges
1973
void qh_printfacet3geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]) {
1974
ridgeT *ridge, **ridgep;
1975
setT *projectedpoints, *vertices;
1976
vertexT *vertex, **vertexp, *vertexA, *vertexB;
1977
pointT *projpt, *point, **pointp;
1979
realT dist, outerplane, innerplane;
1981
realT black[3]={0, 0, 0}, green[3]={0, 1, 0};
1983
qh_geomplanes (facet, &outerplane, &innerplane);
1984
vertices= qh_facet3vertex (facet); /* oriented */
1985
cntvertices= qh_setsize(vertices);
1986
projectedpoints= qh_settemp(cntvertices);
1987
FOREACHvertex_(vertices) {
1989
qh_distplane(vertex->point, facet, &dist);
1990
projpt= qh_projectpoint(vertex->point, facet, dist);
1991
qh_setappend (&projectedpoints, projpt);
1993
if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner))
1994
qh_printfacet3geom_points(fp, projectedpoints, facet, outerplane, color);
1995
if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter &&
1996
outerplane - innerplane > 2 * qh MAXabs_coord * qh_GEOMepsilon)) {
1998
color[k]= 1.0 - color[k];
1999
qh_printfacet3geom_points(fp, projectedpoints, facet, innerplane, color);
2001
FOREACHpoint_(projectedpoints)
2002
qh_memfree (point, qh normal_size);
2003
qh_settempfree(&projectedpoints);
2004
qh_settempfree(&vertices);
2005
if ((qh DOintersections || qh PRINTridges)
2006
&& (!facet->visible || !qh NEWfacets)) {
2007
facet->visitid= qh visit_id;
2008
FOREACHridge_(facet->ridges) {
2009
neighbor= otherfacet_(ridge, facet);
2010
if (neighbor->visitid != qh visit_id) {
2011
if (qh DOintersections)
2012
qh_printhyperplaneintersection(fp, facet, neighbor, ridge->vertices, black);
2013
if (qh PRINTridges) {
2014
vertexA= SETfirstt_(ridge->vertices, vertexT);
2015
vertexB= SETsecondt_(ridge->vertices, vertexT);
2016
qh_printline3geom (fp, vertexA->point, vertexB->point, green);
2021
} /* printfacet3geom_nonsimplicial */
2023
/*-<a href="qh-io.htm#TOC"
2024
>-------------------------------</a><a name="printfacet3geom_points">-</a>
2026
qh_printfacet3geom_points( fp, points, facet, offset )
2027
prints a 3-d facet as OFF Geomview object.
2028
offset is relative to the facet's hyperplane
2029
Facet is determined as a list of points
2031
void qh_printfacet3geom_points(FILE *fp, setT *points, facetT *facet, realT offset, realT color[3]) {
2032
int k, n= qh_setsize(points), i;
2033
pointT *point, **pointp;
2036
fprintf(fp, "{ OFF %d 1 1 # f%d\n", n, facet->id);
2037
if (offset != 0.0) {
2038
printpoints= qh_settemp (n);
2039
FOREACHpoint_(points)
2040
qh_setappend (&printpoints, qh_projectpoint(point, facet, -offset));
2042
printpoints= points;
2043
FOREACHpoint_(printpoints) {
2044
for (k=0; k < qh hull_dim; k++) {
2045
if (k == qh DROPdim)
2048
fprintf(fp, "%8.4g ", point[k]);
2050
if (printpoints != points)
2051
qh_memfree (point, qh normal_size);
2054
if (printpoints != points)
2055
qh_settempfree (&printpoints);
2056
fprintf(fp, "%d ", n);
2057
for(i= 0; i < n; i++)
2058
fprintf(fp, "%d ", i);
2059
fprintf(fp, "%8.4g %8.4g %8.4g 1.0 }\n", color[0], color[1], color[2]);
2060
} /* printfacet3geom_points */
2063
/*-<a href="qh-io.htm#TOC"
2064
>-------------------------------</a><a name="printfacet3geom_simplicial">-</a>
2066
qh_printfacet3geom_simplicial( )
2067
print Geomview OFF for a 3-d simplicial facet.
2071
uses facet->visitid for intersections and ridges
2073
assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
2074
innerplane may be off by qh DISTround. Maxoutside is calculated elsewhere
2075
so a DISTround error may have occured.
2077
void qh_printfacet3geom_simplicial(FILE *fp, facetT *facet, realT color[3]) {
2078
setT *points, *vertices;
2079
vertexT *vertex, **vertexp, *vertexA, *vertexB;
2080
facetT *neighbor, **neighborp;
2081
realT outerplane, innerplane;
2082
realT black[3]={0, 0, 0}, green[3]={0, 1, 0};
2085
qh_geomplanes (facet, &outerplane, &innerplane);
2086
vertices= qh_facet3vertex (facet);
2087
points= qh_settemp (qh TEMPsize);
2088
FOREACHvertex_(vertices)
2089
qh_setappend(&points, vertex->point);
2090
if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner))
2091
qh_printfacet3geom_points(fp, points, facet, outerplane, color);
2092
if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter &&
2093
outerplane - innerplane > 2 * qh MAXabs_coord * qh_GEOMepsilon)) {
2095
color[k]= 1.0 - color[k];
2096
qh_printfacet3geom_points(fp, points, facet, innerplane, color);
2098
qh_settempfree(&points);
2099
qh_settempfree(&vertices);
2100
if ((qh DOintersections || qh PRINTridges)
2101
&& (!facet->visible || !qh NEWfacets)) {
2102
facet->visitid= qh visit_id;
2103
FOREACHneighbor_(facet) {
2104
if (neighbor->visitid != qh visit_id) {
2105
vertices= qh_setnew_delnthsorted (facet->vertices, qh hull_dim,
2106
SETindex_(facet->neighbors, neighbor), 0);
2107
if (qh DOintersections)
2108
qh_printhyperplaneintersection(fp, facet, neighbor, vertices, black);
2109
if (qh PRINTridges) {
2110
vertexA= SETfirstt_(vertices, vertexT);
2111
vertexB= SETsecondt_(vertices, vertexT);
2112
qh_printline3geom (fp, vertexA->point, vertexB->point, green);
2114
qh_setfree(&vertices);
2118
} /* printfacet3geom_simplicial */
2120
/*-<a href="qh-io.htm#TOC"
2121
>-------------------------------</a><a name="printfacet3math">-</a>
2123
qh_printfacet3math( fp, facet, notfirst )
2124
print 3-d Maple or Mathematica output for a facet
2127
may be non-simplicial
2128
use %16.8f since Mathematica 2.2 does not handle exponential format
2129
see qh_printfacet2math
2131
void qh_printfacet3math (FILE *fp, facetT *facet, int format, int notfirst) {
2132
vertexT *vertex, **vertexp;
2133
setT *points, *vertices;
2134
pointT *point, **pointp;
2135
boolT firstpoint= True;
2137
char *pointfmt, *endfmt;
2141
vertices= qh_facet3vertex (facet);
2142
points= qh_settemp (qh_setsize (vertices));
2143
FOREACHvertex_(vertices) {
2145
qh_distplane(vertex->point, facet, &dist);
2146
point= qh_projectpoint(vertex->point, facet, dist);
2147
qh_setappend (&points, point);
2149
if (format == qh_PRINTmaple) {
2151
pointfmt= "[%16.8f, %16.8f, %16.8f]";
2154
fprintf(fp, "Polygon[{");
2155
pointfmt= "{%16.8f, %16.8f, %16.8f}";
2158
FOREACHpoint_(points) {
2163
fprintf(fp, pointfmt, point[0], point[1], point[2]);
2165
FOREACHpoint_(points)
2166
qh_memfree (point, qh normal_size);
2167
qh_settempfree(&points);
2168
qh_settempfree(&vertices);
2169
fprintf(fp, endfmt);
2170
} /* printfacet3math */
2173
/*-<a href="qh-io.htm#TOC"
2174
>-------------------------------</a><a name="printfacet3vertex">-</a>
2176
qh_printfacet3vertex( fp, facet, format )
2177
print vertices in a 3-d facet as point ids
2180
prints number of vertices first if format == qh_PRINToff
2181
the facet may be non-simplicial
2183
void qh_printfacet3vertex(FILE *fp, facetT *facet, int format) {
2184
vertexT *vertex, **vertexp;
2187
vertices= qh_facet3vertex (facet);
2188
if (format == qh_PRINToff)
2189
fprintf (fp, "%d ", qh_setsize (vertices));
2190
FOREACHvertex_(vertices)
2191
fprintf (fp, "%d ", qh_pointid(vertex->point));
2193
qh_settempfree(&vertices);
2194
} /* printfacet3vertex */
2197
/*-<a href="qh-io.htm#TOC"
2198
>-------------------------------</a><a name="printfacet4geom_nonsimplicial">-</a>
2200
qh_printfacet4geom_nonsimplicial( )
2201
print Geomview 4OFF file for a 4d nonsimplicial facet
2202
prints all ridges to unvisited neighbors (qh.visit_id)
2204
prints in OFF format
2207
must agree with printend4geom()
2209
void qh_printfacet4geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]) {
2211
ridgeT *ridge, **ridgep;
2212
vertexT *vertex, **vertexp;
2217
facet->visitid= qh visit_id;
2218
if (qh PRINTnoplanes || (facet->visible && qh NEWfacets))
2220
FOREACHridge_(facet->ridges) {
2221
neighbor= otherfacet_(ridge, facet);
2222
if (neighbor->visitid == qh visit_id)
2224
if (qh PRINTtransparent && !neighbor->good)
2226
if (qh DOintersections)
2227
qh_printhyperplaneintersection(fp, facet, neighbor, ridge->vertices, color);
2229
if (qh DROPdim >= 0)
2230
fprintf(fp, "OFF 3 1 1 # f%d\n", facet->id);
2233
fprintf (fp, "# r%d between f%d f%d\n", ridge->id, facet->id, neighbor->id);
2235
FOREACHvertex_(ridge->vertices) {
2237
qh_distplane(vertex->point,facet, &dist);
2238
point=qh_projectpoint(vertex->point,facet, dist);
2239
for(k= 0; k < qh hull_dim; k++) {
2240
if (k != qh DROPdim)
2241
fprintf(fp, "%8.4g ", point[k]);
2244
qh_memfree (point, qh normal_size);
2246
if (qh DROPdim >= 0)
2247
fprintf(fp, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);
2250
} /* printfacet4geom_nonsimplicial */
2253
/*-<a href="qh-io.htm#TOC"
2254
>-------------------------------</a><a name="printfacet4geom_simplicial">-</a>
2256
qh_printfacet4geom_simplicial( fp, facet, color )
2257
print Geomview 4OFF file for a 4d simplicial facet
2258
prints triangles for unvisited neighbors (qh.visit_id)
2261
must agree with printend4geom()
2263
void qh_printfacet4geom_simplicial(FILE *fp, facetT *facet, realT color[3]) {
2265
facetT *neighbor, **neighborp;
2266
vertexT *vertex, **vertexp;
2269
facet->visitid= qh visit_id;
2270
if (qh PRINTnoplanes || (facet->visible && qh NEWfacets))
2272
FOREACHneighbor_(facet) {
2273
if (neighbor->visitid == qh visit_id)
2275
if (qh PRINTtransparent && !neighbor->good)
2277
vertices= qh_setnew_delnthsorted (facet->vertices, qh hull_dim,
2278
SETindex_(facet->neighbors, neighbor), 0);
2279
if (qh DOintersections)
2280
qh_printhyperplaneintersection(fp, facet, neighbor, vertices, color);
2282
if (qh DROPdim >= 0)
2283
fprintf(fp, "OFF 3 1 1 # ridge between f%d f%d\n",
2284
facet->id, neighbor->id);
2287
fprintf (fp, "# ridge between f%d f%d\n", facet->id, neighbor->id);
2289
FOREACHvertex_(vertices) {
2290
for(k= 0; k < qh hull_dim; k++) {
2291
if (k != qh DROPdim)
2292
fprintf(fp, "%8.4g ", vertex->point[k]);
2296
if (qh DROPdim >= 0)
2297
fprintf(fp, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);
2299
qh_setfree(&vertices);
2301
} /* printfacet4geom_simplicial */
2304
/*-<a href="qh-io.htm#TOC"
2305
>-------------------------------</a><a name="printfacetNvertex_nonsimplicial">-</a>
2307
qh_printfacetNvertex_nonsimplicial( fp, facet, id, format )
2308
print vertices for an N-d non-simplicial facet
2309
triangulates each ridge to the id
2311
void qh_printfacetNvertex_nonsimplicial(FILE *fp, facetT *facet, int id, int format) {
2312
vertexT *vertex, **vertexp;
2313
ridgeT *ridge, **ridgep;
2315
if (facet->visible && qh NEWfacets)
2317
FOREACHridge_(facet->ridges) {
2318
if (format == qh_PRINTtriangles)
2319
fprintf(fp, "%d ", qh hull_dim);
2320
fprintf(fp, "%d ", id);
2321
if ((ridge->top == facet) ^ qh_ORIENTclock) {
2322
FOREACHvertex_(ridge->vertices)
2323
fprintf(fp, "%d ", qh_pointid(vertex->point));
2325
FOREACHvertexreverse12_(ridge->vertices)
2326
fprintf(fp, "%d ", qh_pointid(vertex->point));
2330
} /* printfacetNvertex_nonsimplicial */
2333
/*-<a href="qh-io.htm#TOC"
2334
>-------------------------------</a><a name="printfacetNvertex_simplicial">-</a>
2336
qh_printfacetNvertex_simplicial( fp, facet, format )
2337
print vertices for an N-d simplicial facet
2338
prints vertices for non-simplicial facets
2339
2-d facets (orientation preserved by qh_mergefacet2d)
2340
PRINToff ('o') for 4-d and higher
2342
void qh_printfacetNvertex_simplicial(FILE *fp, facetT *facet, int format) {
2343
vertexT *vertex, **vertexp;
2345
if (format == qh_PRINToff || format == qh_PRINTtriangles)
2346
fprintf (fp, "%d ", qh_setsize (facet->vertices));
2347
if ((facet->toporient ^ qh_ORIENTclock)
2348
|| (qh hull_dim > 2 && !facet->simplicial)) {
2349
FOREACHvertex_(facet->vertices)
2350
fprintf(fp, "%d ", qh_pointid(vertex->point));
2352
FOREACHvertexreverse12_(facet->vertices)
2353
fprintf(fp, "%d ", qh_pointid(vertex->point));
2356
} /* printfacetNvertex_simplicial */
2359
/*-<a href="qh-io.htm#TOC"
2360
>-------------------------------</a><a name="printfacetheader">-</a>
2362
qh_printfacetheader( fp, facet )
2363
prints header fields of a facet to fp
2366
for 'f' output and debugging
2368
void qh_printfacetheader(FILE *fp, facetT *facet) {
2369
pointT *point, **pointp, *furthest;
2370
facetT *neighbor, **neighborp;
2373
if (facet == qh_MERGEridge) {
2374
fprintf (fp, " MERGEridge\n");
2376
}else if (facet == qh_DUPLICATEridge) {
2377
fprintf (fp, " DUPLICATEridge\n");
2380
fprintf (fp, " NULLfacet\n");
2383
qh old_randomdist= qh RANDOMdist;
2384
qh RANDOMdist= False;
2385
fprintf(fp, "- f%d\n", facet->id);
2386
fprintf(fp, " - flags:");
2387
if (facet->toporient)
2388
fprintf(fp, " top");
2390
fprintf(fp, " bottom");
2391
if (facet->simplicial)
2392
fprintf(fp, " simplicial");
2393
if (facet->tricoplanar)
2394
fprintf(fp, " tricoplanar");
2395
if (facet->upperdelaunay)
2396
fprintf(fp, " upperDelaunay");
2398
fprintf(fp, " visible");
2399
if (facet->newfacet)
2400
fprintf(fp, " new");
2402
fprintf(fp, " tested");
2404
fprintf(fp, " notG");
2406
fprintf(fp, " seen");
2407
if (facet->coplanar)
2408
fprintf(fp, " coplanar");
2409
if (facet->mergehorizon)
2410
fprintf(fp, " mergehorizon");
2411
if (facet->keepcentrum)
2412
fprintf(fp, " keepcentrum");
2413
if (facet->dupridge)
2414
fprintf(fp, " dupridge");
2415
if (facet->mergeridge && !facet->mergeridge2)
2416
fprintf(fp, " mergeridge1");
2417
if (facet->mergeridge2)
2418
fprintf(fp, " mergeridge2");
2419
if (facet->newmerge)
2420
fprintf(fp, " newmerge");
2422
fprintf(fp, " flipped");
2423
if (facet->notfurthest)
2424
fprintf(fp, " notfurthest");
2425
if (facet->degenerate)
2426
fprintf(fp, " degenerate");
2427
if (facet->redundant)
2428
fprintf(fp, " redundant");
2431
fprintf(fp, " - area: %2.2g\n", facet->f.area);
2432
else if (qh NEWfacets && facet->visible && facet->f.replace)
2433
fprintf(fp, " - replacement: f%d\n", facet->f.replace->id);
2434
else if (facet->newfacet) {
2435
if (facet->f.samecycle && facet->f.samecycle != facet)
2436
fprintf(fp, " - shares same visible/horizon as f%d\n", facet->f.samecycle->id);
2437
}else if (facet->tricoplanar /* !isarea */) {
2438
if (facet->f.triowner)
2439
fprintf(fp, " - owner of normal & centrum is facet f%d\n", facet->f.triowner->id);
2440
}else if (facet->f.newcycle)
2441
fprintf(fp, " - was horizon to f%d\n", facet->f.newcycle->id);
2442
if (facet->nummerge)
2443
fprintf(fp, " - merges: %d\n", facet->nummerge);
2444
qh_printpointid(fp, " - normal: ", qh hull_dim, facet->normal, -1);
2445
fprintf(fp, " - offset: %10.7g\n", facet->offset);
2446
if (qh CENTERtype == qh_ASvoronoi || facet->center)
2447
qh_printcenter (fp, qh_PRINTfacets, " - center: ", facet);
2449
if (facet->maxoutside > qh DISTround)
2450
fprintf(fp, " - maxoutside: %10.7g\n", facet->maxoutside);
2452
if (!SETempty_(facet->outsideset)) {
2453
furthest= (pointT*)qh_setlast(facet->outsideset);
2454
if (qh_setsize (facet->outsideset) < 6) {
2455
fprintf(fp, " - outside set (furthest p%d):\n", qh_pointid(furthest));
2456
FOREACHpoint_(facet->outsideset)
2457
qh_printpoint(fp, " ", point);
2458
}else if (qh_setsize (facet->outsideset) < 21) {
2459
qh_printpoints(fp, " - outside set:", facet->outsideset);
2461
fprintf(fp, " - outside set: %d points.", qh_setsize(facet->outsideset));
2462
qh_printpoint(fp, " Furthest", furthest);
2464
#if !qh_COMPUTEfurthest
2465
fprintf(fp, " - furthest distance= %2.2g\n", facet->furthestdist);
2468
if (!SETempty_(facet->coplanarset)) {
2469
furthest= (pointT*)qh_setlast(facet->coplanarset);
2470
if (qh_setsize (facet->coplanarset) < 6) {
2471
fprintf(fp, " - coplanar set (furthest p%d):\n", qh_pointid(furthest));
2472
FOREACHpoint_(facet->coplanarset)
2473
qh_printpoint(fp, " ", point);
2474
}else if (qh_setsize (facet->coplanarset) < 21) {
2475
qh_printpoints(fp, " - coplanar set:", facet->coplanarset);
2477
fprintf(fp, " - coplanar set: %d points.", qh_setsize(facet->coplanarset));
2478
qh_printpoint(fp, " Furthest", furthest);
2481
qh_distplane (furthest, facet, &dist);
2482
fprintf(fp, " furthest distance= %2.2g\n", dist);
2484
qh_printvertices (fp, " - vertices:", facet->vertices);
2485
fprintf(fp, " - neighboring facets: ");
2486
FOREACHneighbor_(facet) {
2487
if (neighbor == qh_MERGEridge)
2488
fprintf(fp, " MERGE");
2489
else if (neighbor == qh_DUPLICATEridge)
2490
fprintf(fp, " DUP");
2492
fprintf(fp, " f%d", neighbor->id);
2495
qh RANDOMdist= qh old_randomdist;
2496
} /* printfacetheader */
2499
/*-<a href="qh-io.htm#TOC"
2500
>-------------------------------</a><a name="printfacetridges">-</a>
2502
qh_printfacetridges( fp, facet )
2503
prints ridges of a facet to fp
2506
ridges printed in neighbor order
2507
assumes the ridges exist
2510
void qh_printfacetridges(FILE *fp, facetT *facet) {
2511
facetT *neighbor, **neighborp;
2512
ridgeT *ridge, **ridgep;
2516
if (facet->visible && qh NEWfacets) {
2517
fprintf(fp, " - ridges (ids may be garbage):");
2518
FOREACHridge_(facet->ridges)
2519
fprintf(fp, " r%d", ridge->id);
2522
fprintf(fp, " - ridges:\n");
2523
FOREACHridge_(facet->ridges)
2525
if (qh hull_dim == 3) {
2526
ridge= SETfirstt_(facet->ridges, ridgeT);
2527
while (ridge && !ridge->seen) {
2529
qh_printridge(fp, ridge);
2531
ridge= qh_nextridge3d (ridge, facet, NULL);
2534
FOREACHneighbor_(facet) {
2535
FOREACHridge_(facet->ridges) {
2536
if (otherfacet_(ridge,facet) == neighbor) {
2538
qh_printridge(fp, ridge);
2544
if (numridges != qh_setsize (facet->ridges)) {
2545
fprintf (fp, " - all ridges:");
2546
FOREACHridge_(facet->ridges)
2547
fprintf (fp, " r%d", ridge->id);
2550
FOREACHridge_(facet->ridges) {
2552
qh_printridge(fp, ridge);
2555
} /* printfacetridges */
2557
/*-<a href="qh-io.htm#TOC"
2558
>-------------------------------</a><a name="printfacets">-</a>
2560
qh_printfacets( fp, format, facetlist, facets, printall )
2561
prints facetlist and/or facet set in output format
2564
also used for specialized formats ('FO' and summary)
2565
turns off 'Rn' option since want actual numbers
2567
void qh_printfacets(FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
2568
int numfacets, numsimplicial, numridges, totneighbors, numcoplanars, numtricoplanars;
2569
facetT *facet, **facetp;
2572
realT outerplane, innerplane;
2574
qh old_randomdist= qh RANDOMdist;
2575
qh RANDOMdist= False;
2576
if (qh CDDoutput && (format == qh_PRINTcentrums || format == qh_PRINTpointintersect || format == qh_PRINToff))
2577
fprintf (qh ferr, "qhull warning: CDD format is not available for centrums, halfspace\nintersections, and OFF file format.\n");
2578
if (format == qh_PRINTnone)
2579
; /* print nothing */
2580
else if (format == qh_PRINTaverage) {
2581
vertices= qh_facetvertices (facetlist, facets, printall);
2582
center= qh_getcenter (vertices);
2583
fprintf (fp, "%d 1\n", qh hull_dim);
2584
qh_printpointid (fp, NULL, qh hull_dim, center, -1);
2585
qh_memfree (center, qh normal_size);
2586
qh_settempfree (&vertices);
2587
}else if (format == qh_PRINTextremes) {
2589
qh_printextremes_d (fp, facetlist, facets, printall);
2590
else if (qh hull_dim == 2)
2591
qh_printextremes_2d (fp, facetlist, facets, printall);
2593
qh_printextremes (fp, facetlist, facets, printall);
2594
}else if (format == qh_PRINToptions)
2595
fprintf(fp, "Options selected for Qhull %s:\n%s\n", qh_version, qh qhull_options);
2596
else if (format == qh_PRINTpoints && !qh VORONOI)
2597
qh_printpoints_out (fp, facetlist, facets, printall);
2598
else if (format == qh_PRINTqhull)
2599
fprintf (fp, "%s | %s\n", qh rbox_command, qh qhull_command);
2600
else if (format == qh_PRINTsize) {
2601
fprintf (fp, "0\n2 ");
2602
fprintf (fp, qh_REAL_1, qh totarea);
2603
fprintf (fp, qh_REAL_1, qh totvol);
2605
}else if (format == qh_PRINTsummary) {
2606
qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial,
2607
&totneighbors, &numridges, &numcoplanars, &numtricoplanars);
2608
vertices= qh_facetvertices (facetlist, facets, printall);
2609
fprintf (fp, "10 %d %d %d %d %d %d %d %d %d %d\n2 ", qh hull_dim,
2610
qh num_points + qh_setsize (qh other_points),
2611
qh num_vertices, qh num_facets - qh num_visible,
2612
qh_setsize (vertices), numfacets, numcoplanars,
2613
numfacets - numsimplicial, zzval_(Zdelvertextot),
2615
qh_settempfree (&vertices);
2616
qh_outerinner (NULL, &outerplane, &innerplane);
2617
fprintf (fp, qh_REAL_2n, outerplane, innerplane);
2618
}else if (format == qh_PRINTvneighbors)
2619
qh_printvneighbors (fp, facetlist, facets, printall);
2620
else if (qh VORONOI && format == qh_PRINToff)
2621
qh_printvoronoi (fp, format, facetlist, facets, printall);
2622
else if (qh VORONOI && format == qh_PRINTgeom) {
2623
qh_printbegin (fp, format, facetlist, facets, printall);
2624
qh_printvoronoi (fp, format, facetlist, facets, printall);
2625
qh_printend (fp, format, facetlist, facets, printall);
2626
}else if (qh VORONOI
2627
&& (format == qh_PRINTvertices || format == qh_PRINTinner || format == qh_PRINTouter))
2628
qh_printvdiagram (fp, format, facetlist, facets, printall);
2630
qh_printbegin (fp, format, facetlist, facets, printall);
2631
FORALLfacet_(facetlist)
2632
qh_printafacet (fp, format, facet, printall);
2633
FOREACHfacet_(facets)
2634
qh_printafacet (fp, format, facet, printall);
2635
qh_printend (fp, format, facetlist, facets, printall);
2637
qh RANDOMdist= qh old_randomdist;
2641
/*-<a href="qh-io.htm#TOC"
2642
>-------------------------------</a><a name="printhelp_degenerate">-</a>
2644
qh_printhelp_degenerate( fp )
2645
prints descriptive message for precision error
2648
no message if qh_QUICKhelp
2650
void qh_printhelp_degenerate(FILE *fp) {
2652
if (qh MERGEexact || qh PREmerge || qh JOGGLEmax < REALmax/2)
2654
A Qhull error has occurred. Qhull should have corrected the above\n\
2655
precision error. Please send the input and all of the output to\n\
2656
qhull_bug@qhull.org\n");
2657
else if (!qh_QUICKhelp) {
2659
Precision problems were detected during construction of the convex hull.\n\
2660
This occurs because convex hull algorithms assume that calculations are\n\
2661
exact, but floating-point arithmetic has roundoff errors.\n\
2663
To correct for precision problems, do not use 'Q0'. By default, Qhull\n\
2664
selects 'C-0' or 'Qx' and merges non-convex facets. With option 'QJ',\n\
2665
Qhull joggles the input to prevent precision problems. See \"Imprecision\n\
2666
in Qhull\" (qh-impre.htm).\n\
2668
If you use 'Q0', the output may include\n\
2669
coplanar ridges, concave ridges, and flipped facets. In 4-d and higher,\n\
2670
Qhull may produce a ridge with four neighbors or two facets with the same \n\
2671
vertices. Qhull reports these events when they occur. It stops when a\n\
2672
concave ridge, flipped facet, or duplicate facet occurs.\n");
2676
Qhull is currently using single precision arithmetic. The following\n\
2677
will probably remove the precision problems:\n\
2678
- recompile qhull for double precision (#define REALfloat 0 in user.h).\n");
2680
if (qh DELAUNAY && !qh SCALElast && qh MAXabs_coord > 1e4)
2683
When computing the Delaunay triangulation of coordinates > 1.0,\n\
2684
- use 'Qbb' to scale the last coordinate to [0,m] (max previous coordinate)\n");
2685
if (qh DELAUNAY && !qh ATinfinity)
2687
When computing the Delaunay triangulation:\n\
2688
- use 'Qz' to add a point at-infinity. This reduces precision problems.\n");
2692
If you need triangular output:\n\
2693
- use option 'Qt' to triangulate the output\n\
2694
- use option 'QJ' to joggle the input points and remove precision errors\n\
2695
- use option 'Ft'. It triangulates non-simplicial facets with added points.\n\
2697
If you must use 'Q0',\n\
2698
try one or more of the following options. They can not guarantee an output.\n\
2699
- use 'QbB' to scale the input to a cube.\n\
2700
- use 'Po' to produce output and prevent partitioning for flipped facets\n\
2701
- use 'V0' to set min. distance to visible facet as 0 instead of roundoff\n\
2702
- use 'En' to specify a maximum roundoff error less than %2.2g.\n\
2703
- options 'Qf', 'Qbb', and 'QR0' may also help\n",
2707
To guarantee simplicial output:\n\
2708
- use option 'Qt' to triangulate the output\n\
2709
- use option 'QJ' to joggle the input points and remove precision errors\n\
2710
- use option 'Ft' to triangulate the output by adding points\n\
2711
- use exact arithmetic (see \"Imprecision in Qhull\", qh-impre.htm)\n\
2714
} /* printhelp_degenerate */
2717
/*-<a href="qh-io.htm#TOC"
2718
>-------------------------------</a><a name="printhelp_singular">-</a>
2720
qh_printhelp_singular( fp )
2721
prints descriptive message for singular input
2723
void qh_printhelp_singular(FILE *fp) {
2725
vertexT *vertex, **vertexp;
2726
realT min, max, *coord, dist;
2730
The input to qhull appears to be less than %d dimensional, or a\n\
2731
computation has overflowed.\n\n\
2732
Qhull could not construct a clearly convex simplex from points:\n",
2734
qh_printvertexlist (fp, "", qh facet_list, NULL, qh_ALL);
2737
The center point is coplanar with a facet, or a vertex is coplanar\n\
2738
with a neighboring facet. The maximum round off error for\n\
2739
computing distances is %2.2g. The center point, facets and distances\n\
2740
to the center point are as follows:\n\n", qh DISTround);
2741
qh_printpointid (fp, "center point", qh hull_dim, qh interior_point, -1);
2744
fprintf (fp, "facet");
2745
FOREACHvertex_(facet->vertices)
2746
fprintf (fp, " p%d", qh_pointid(vertex->point));
2748
qh_distplane(qh interior_point, facet, &dist);
2749
fprintf (fp, " distance= %4.2g\n", dist);
2751
if (!qh_QUICKhelp) {
2754
These points are the dual of the given halfspaces. They indicate that\n\
2755
the intersection is degenerate.\n");
2757
These points either have a maximum or minimum x-coordinate, or\n\
2758
they maximize the determinant for k coordinates. Trial points\n\
2759
are first selected from points that maximize a coordinate.\n");
2760
if (qh hull_dim >= qh_INITIALmax)
2762
Because of the high dimension, the min x-coordinate and max-coordinate\n\
2763
points are used if the determinant is non-zero. Option 'Qs' will\n\
2764
do a better, though much slower, job. Instead of 'Qs', you can change\n\
2765
the points by randomly rotating the input with 'QR0'.\n");
2767
fprintf (fp, "\nThe min and max coordinates for each dimension are:\n");
2768
for (k=0; k < qh hull_dim; k++) {
2771
for (i=qh num_points, coord= qh first_point+k; i--; coord += qh hull_dim) {
2772
maximize_(max, *coord);
2773
minimize_(min, *coord);
2775
fprintf (fp, " %d: %8.4g %8.4g difference= %4.4g\n", k, min, max, max-min);
2777
if (!qh_QUICKhelp) {
2779
If the input should be full dimensional, you have several options that\n\
2780
may determine an initial simplex:\n\
2781
- use 'QJ' to joggle the input and make it full dimensional\n\
2782
- use 'QbB' to scale the points to the unit cube\n\
2783
- use 'QR0' to randomly rotate the input for different maximum points\n\
2784
- use 'Qs' to search all points for the initial simplex\n\
2785
- use 'En' to specify a maximum roundoff error less than %2.2g.\n\
2786
- trace execution with 'T3' to see the determinant for each point.\n",
2790
- recompile qhull for double precision (#define REALfloat 0 in qhull.h).\n");
2793
If the input is lower dimensional:\n\
2794
- use 'QJ' to joggle the input and make it full dimensional\n\
2795
- use 'Qbk:0Bk:0' to delete coordinate k from the input. You should\n\
2796
pick the coordinate with the least range. The hull will have the\n\
2797
correct topology.\n\
2798
- determine the flat containing the points, rotate the points\n\
2799
into a coordinate plane, and delete the other coordinates.\n\
2800
- add one or more points to make the input full dimensional.\n\
2802
if (qh DELAUNAY && !qh ATinfinity)
2804
This is a Delaunay triangulation and the input is co-circular or co-spherical:\n\
2805
- use 'Qz' to add a point \"at infinity\" (i.e., above the paraboloid)\n\
2806
- or use 'QJ' to joggle the input and avoid co-circular data\n");
2808
} /* printhelp_singular */
2810
/*-<a href="qh-io.htm#TOC"
2811
>-------------------------------</a><a name="printhyperplaneintersection">-</a>
2813
qh_printhyperplaneintersection( fp, facet1, facet2, vertices, color )
2814
print Geomview OFF or 4OFF for the intersection of two hyperplanes in 3-d or 4-d
2816
void qh_printhyperplaneintersection(FILE *fp, facetT *facet1, facetT *facet2,
2817
setT *vertices, realT color[3]) {
2818
realT costheta, denominator, dist1, dist2, s, t, mindenom, p[4];
2819
vertexT *vertex, **vertexp;
2821
boolT nearzero1, nearzero2;
2823
costheta= qh_getangle(facet1->normal, facet2->normal);
2824
denominator= 1 - costheta * costheta;
2825
i= qh_setsize(vertices);
2826
if (qh hull_dim == 3)
2827
fprintf(fp, "VECT 1 %d 1 %d 1 ", i, i);
2828
else if (qh hull_dim == 4 && qh DROPdim >= 0)
2829
fprintf(fp, "OFF 3 1 1 ");
2832
fprintf (fp, "# intersect f%d f%d\n", facet1->id, facet2->id);
2833
mindenom= 1 / (10.0 * qh MAXabs_coord);
2834
FOREACHvertex_(vertices) {
2836
qh_distplane(vertex->point, facet1, &dist1);
2837
qh_distplane(vertex->point, facet2, &dist2);
2838
s= qh_divzero (-dist1 + costheta * dist2, denominator,mindenom,&nearzero1);
2839
t= qh_divzero (-dist2 + costheta * dist1, denominator,mindenom,&nearzero2);
2840
if (nearzero1 || nearzero2)
2842
for(k= qh hull_dim; k--; )
2843
p[k]= vertex->point[k] + facet1->normal[k] * s + facet2->normal[k] * t;
2844
if (qh PRINTdim <= 3) {
2845
qh_projectdim3 (p, p);
2846
fprintf(fp, "%8.4g %8.4g %8.4g # ", p[0], p[1], p[2]);
2848
fprintf(fp, "%8.4g %8.4g %8.4g %8.4g # ", p[0], p[1], p[2], p[3]);
2849
if (nearzero1+nearzero2)
2850
fprintf (fp, "p%d (coplanar facets)\n", qh_pointid (vertex->point));
2852
fprintf (fp, "projected p%d\n", qh_pointid (vertex->point));
2854
if (qh hull_dim == 3)
2855
fprintf(fp, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
2856
else if (qh hull_dim == 4 && qh DROPdim >= 0)
2857
fprintf(fp, "3 0 1 2 %8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
2858
} /* printhyperplaneintersection */
2860
/*-<a href="qh-io.htm#TOC"
2861
>-------------------------------</a><a name="printline3geom">-</a>
2863
qh_printline3geom( fp, pointA, pointB, color )
2864
prints a line as a VECT
2865
prints 0's for qh.DROPdim
2868
if pointA == pointB,
2871
void qh_printline3geom (FILE *fp, pointT *pointA, pointT *pointB, realT color[3]) {
2875
qh_projectdim3(pointA, pA);
2876
qh_projectdim3(pointB, pB);
2877
if ((fabs(pA[0] - pB[0]) > 1e-3) ||
2878
(fabs(pA[1] - pB[1]) > 1e-3) ||
2879
(fabs(pA[2] - pB[2]) > 1e-3)) {
2880
fprintf (fp, "VECT 1 2 1 2 1\n");
2881
for (k= 0; k < 3; k++)
2882
fprintf (fp, "%8.4g ", pB[k]);
2883
fprintf (fp, " # p%d\n", qh_pointid (pointB));
2885
fprintf (fp, "VECT 1 1 1 1 1\n");
2886
for (k=0; k < 3; k++)
2887
fprintf (fp, "%8.4g ", pA[k]);
2888
fprintf (fp, " # p%d\n", qh_pointid (pointA));
2889
fprintf (fp, "%8.4g %8.4g %8.4g 1\n", color[0], color[1], color[2]);
2892
/*-<a href="qh-io.htm#TOC"
2893
>-------------------------------</a><a name="printneighborhood">-</a>
2895
qh_printneighborhood( fp, format, facetA, facetB, printall )
2896
print neighborhood of one or two facets
2899
calls qh_findgood_all()
2902
void qh_printneighborhood (FILE *fp, int format, facetT *facetA, facetT *facetB, boolT printall) {
2903
facetT *neighbor, **neighborp, *facet;
2906
if (format == qh_PRINTnone)
2908
qh_findgood_all (qh facet_list);
2909
if (facetA == facetB)
2911
facets= qh_settemp (2*(qh_setsize (facetA->neighbors)+1));
2913
for (facet= facetA; facet; facet= ((facet == facetA) ? facetB : NULL)) {
2914
if (facet->visitid != qh visit_id) {
2915
facet->visitid= qh visit_id;
2916
qh_setappend (&facets, facet);
2918
FOREACHneighbor_(facet) {
2919
if (neighbor->visitid == qh visit_id)
2921
neighbor->visitid= qh visit_id;
2922
if (printall || !qh_skipfacet (neighbor))
2923
qh_setappend (&facets, neighbor);
2926
qh_printfacets (fp, format, NULL, facets, printall);
2927
qh_settempfree (&facets);
2928
} /* printneighborhood */
2930
/*-<a href="qh-io.htm#TOC"
2931
>-------------------------------</a><a name="printpoint">-</a>
2933
qh_printpoint( fp, string, point )
2934
qh_printpointid( fp, string, dim, point, id )
2935
prints the coordinates of a point
2938
if string is defined
2939
prints 'string p%d' (skips p%d if id=-1)
2942
nop if point is NULL
2943
prints id unless it is undefined (-1)
2945
void qh_printpoint(FILE *fp, char *string, pointT *point) {
2946
int id= qh_pointid( point);
2948
qh_printpointid( fp, string, qh hull_dim, point, id);
2951
void qh_printpointid(FILE *fp, char *string, int dim, pointT *point, int id) {
2953
realT r; /*bug fix*/
2960
fprintf(fp, " p%d: ", id);
2962
for(k= dim; k--; ) {
2965
fprintf(fp, " %8.4g", r);
2967
fprintf(fp, qh_REAL_1, r);
2970
} /* printpointid */
2972
/*-<a href="qh-io.htm#TOC"
2973
>-------------------------------</a><a name="printpoint3">-</a>
2975
qh_printpoint3( fp, point )
2976
prints 2-d, 3-d, or 4-d point as Geomview 3-d coordinates
2978
void qh_printpoint3 (FILE *fp, pointT *point) {
2982
qh_projectdim3 (point, p);
2983
for (k=0; k < 3; k++)
2984
fprintf (fp, "%8.4g ", p[k]);
2985
fprintf (fp, " # p%d\n", qh_pointid (point));
2988
/*----------------------------------------
2989
-printpoints- print pointids for a set of points starting at index
2993
/*-<a href="qh-io.htm#TOC"
2994
>-------------------------------</a><a name="printpoints_out">-</a>
2996
qh_printpoints_out( fp, facetlist, facets, printall )
2997
prints vertices, coplanar/inside points, for facets by their point coordinates
3001
same format as qhull input
3002
if no coplanar/interior points,
3003
same order as qh_printextremes
3005
void qh_printpoints_out (FILE *fp, facetT *facetlist, setT *facets, int printall) {
3006
int allpoints= qh num_points + qh_setsize (qh other_points);
3007
int numpoints=0, point_i, point_n;
3008
setT *vertices, *points;
3009
facetT *facet, **facetp;
3010
pointT *point, **pointp;
3011
vertexT *vertex, **vertexp;
3014
points= qh_settemp (allpoints);
3015
qh_setzero (points, 0, allpoints);
3016
vertices= qh_facetvertices (facetlist, facets, printall);
3017
FOREACHvertex_(vertices) {
3018
id= qh_pointid (vertex->point);
3020
SETelem_(points, id)= vertex->point;
3022
if (qh KEEPinside || qh KEEPcoplanar || qh KEEPnearinside) {
3023
FORALLfacet_(facetlist) {
3024
if (!printall && qh_skipfacet(facet))
3026
FOREACHpoint_(facet->coplanarset) {
3027
id= qh_pointid (point);
3029
SETelem_(points, id)= point;
3032
FOREACHfacet_(facets) {
3033
if (!printall && qh_skipfacet(facet))
3035
FOREACHpoint_(facet->coplanarset) {
3036
id= qh_pointid (point);
3038
SETelem_(points, id)= point;
3042
qh_settempfree (&vertices);
3043
FOREACHpoint_i_(points) {
3048
fprintf (fp, "%s | %s\nbegin\n%d %d real\n", qh rbox_command,
3049
qh qhull_command, numpoints, qh hull_dim + 1);
3051
fprintf (fp, "%d\n%d\n", qh hull_dim, numpoints);
3052
FOREACHpoint_i_(points) {
3056
qh_printpoint (fp, NULL, point);
3060
fprintf (fp, "end\n");
3061
qh_settempfree (&points);
3062
} /* printpoints_out */
3065
/*-<a href="qh-io.htm#TOC"
3066
>-------------------------------</a><a name="printpointvect">-</a>
3068
qh_printpointvect( fp, point, normal, center, radius, color )
3069
prints a 2-d, 3-d, or 4-d point as 3-d VECT's relative to normal or to center point
3071
void qh_printpointvect (FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius, realT color[3]) {
3072
realT diff[4], pointA[4];
3075
for (k= qh hull_dim; k--; ) {
3077
diff[k]= point[k]-center[k];
3084
qh_normalize2 (diff, qh hull_dim, True, NULL, NULL);
3085
for (k= qh hull_dim; k--; )
3086
pointA[k]= point[k]+diff[k] * radius;
3087
qh_printline3geom (fp, point, pointA, color);
3088
} /* printpointvect */
3090
/*-<a href="qh-io.htm#TOC"
3091
>-------------------------------</a><a name="printpointvect2">-</a>
3093
qh_printpointvect2( fp, point, normal, center, radius )
3094
prints a 2-d, 3-d, or 4-d point as 2 3-d VECT's for an imprecise point
3096
void qh_printpointvect2 (FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius) {
3097
realT red[3]={1, 0, 0}, yellow[3]={1, 1, 0};
3099
qh_printpointvect (fp, point, normal, center, radius, red);
3100
qh_printpointvect (fp, point, normal, center, -radius, yellow);
3101
} /* printpointvect2 */
3103
/*-<a href="qh-io.htm#TOC"
3104
>-------------------------------</a><a name="printridge">-</a>
3106
qh_printridge( fp, ridge )
3107
prints the information in a ridge
3110
for qh_printfacetridges()
3112
void qh_printridge(FILE *fp, ridgeT *ridge) {
3114
fprintf(fp, " - r%d", ridge->id);
3116
fprintf (fp, " tested");
3117
if (ridge->nonconvex)
3118
fprintf (fp, " nonconvex");
3120
qh_printvertices (fp, " vertices:", ridge->vertices);
3121
if (ridge->top && ridge->bottom)
3122
fprintf(fp, " between f%d and f%d\n",
3123
ridge->top->id, ridge->bottom->id);
3126
/*-<a href="qh-io.htm#TOC"
3127
>-------------------------------</a><a name="printspheres">-</a>
3129
qh_printspheres( fp, vertices, radius )
3130
prints 3-d vertices as OFF spheres
3133
inflated octahedron from Stuart Levy earth/mksphere2
3135
void qh_printspheres(FILE *fp, setT *vertices, realT radius) {
3136
vertexT *vertex, **vertexp;
3139
fprintf (fp, "{appearance {-edge -normal normscale 0} {\n\
3140
INST geom {define vsphere OFF\n\
3149
0.707107 0 0.707107\n\
3150
0 -0.707107 0.707107\n\
3151
0.707107 -0.707107 0\n\
3152
-0.707107 0 0.707107\n\
3153
-0.707107 -0.707107 0\n\
3154
0 0.707107 0.707107\n\
3155
-0.707107 0.707107 0\n\
3156
0.707107 0.707107 0\n\
3157
0.707107 0 -0.707107\n\
3158
0 0.707107 -0.707107\n\
3159
-0.707107 0 -0.707107\n\
3160
0 -0.707107 -0.707107\n\
3193
3 17 10 16\n} transforms { TLIST\n");
3194
FOREACHvertex_(vertices) {
3195
fprintf(fp, "%8.4g 0 0 0 # v%d\n 0 %8.4g 0 0\n0 0 %8.4g 0\n",
3196
radius, vertex->id, radius, radius);
3197
qh_printpoint3 (fp, vertex->point);
3198
fprintf (fp, "1\n");
3200
fprintf (fp, "}}}\n");
3201
} /* printspheres */
3204
/*----------------------------------------------
3209
/*-<a href="qh-io.htm#TOC"
3210
>-------------------------------</a><a name="printvdiagram">-</a>
3212
qh_printvdiagram( fp, format, facetlist, facets, printall )
3213
print voronoi diagram
3214
# of pairs of input sites
3215
#indices site1 site2 vertex1 ...
3217
sites indexed by input point id
3218
point 0 is the first input point
3219
vertices indexed by 'o' and 'p' order
3220
vertex 0 is the 'vertex-at-infinity'
3221
vertex 1 is the first Voronoi vertex
3225
qh_eachvoronoi_all()
3228
if all facets are upperdelaunay,
3229
prints upper hull (furthest-site Voronoi diagram)
3231
void qh_printvdiagram (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
3233
int totcount, numcenters;
3235
qh_RIDGE innerouter= qh_RIDGEall;
3236
printvridgeT printvridge= NULL;
3238
if (format == qh_PRINTvertices) {
3239
innerouter= qh_RIDGEall;
3240
printvridge= qh_printvridge;
3241
}else if (format == qh_PRINTinner) {
3242
innerouter= qh_RIDGEinner;
3243
printvridge= qh_printvnorm;
3244
}else if (format == qh_PRINTouter) {
3245
innerouter= qh_RIDGEouter;
3246
printvridge= qh_printvnorm;
3248
fprintf(qh ferr, "qh_printvdiagram: unknown print format %d.\n", format);
3249
qh_errexit (qh_ERRinput, NULL, NULL);
3251
vertices= qh_markvoronoi (facetlist, facets, printall, &islower, &numcenters);
3252
totcount= qh_printvdiagram2 (NULL, NULL, vertices, innerouter, False);
3253
fprintf (fp, "%d\n", totcount);
3254
totcount= qh_printvdiagram2 (fp, printvridge, vertices, innerouter, True /* inorder*/);
3255
qh_settempfree (&vertices);
3256
#if 0 /* for testing qh_eachvoronoi_all */
3258
totcount= qh_eachvoronoi_all(fp, printvridge, qh UPPERdelaunay, innerouter, True /* inorder*/);
3259
fprintf (fp, "%d\n", totcount);
3261
} /* printvdiagram */
3263
/*-<a href="qh-io.htm#TOC"
3264
>-------------------------------</a><a name="printvdiagram2">-</a>
3266
qh_printvdiagram2( fp, printvridge, vertices, innerouter, inorder )
3267
visit all pairs of input sites (vertices) for selected Voronoi vertices
3268
vertices may include NULLs
3271
qh_RIDGEall print inner ridges (bounded) and outer ridges (unbounded)
3272
qh_RIDGEinner print only inner ridges
3273
qh_RIDGEouter print only outer ridges
3276
print 3-d Voronoi vertices in order
3279
qh_markvoronoi marked facet->visitid for Voronoi vertices
3280
all facet->seen= False
3281
all facet->seen2= True
3284
total number of Voronoi ridges
3286
calls printvridge( fp, vertex, vertexA, centers) for each ridge
3287
[see qh_eachvoronoi()]
3290
qh_eachvoronoi_all()
3292
int qh_printvdiagram2 (FILE *fp, printvridgeT printvridge, setT *vertices, qh_RIDGE innerouter, boolT inorder) {
3294
int vertex_i, vertex_n;
3298
vertex->seen= False;
3299
FOREACHvertex_i_(vertices) {
3301
if (qh GOODvertex > 0 && qh_pointid(vertex->point)+1 != qh GOODvertex)
3303
totcount += qh_eachvoronoi (fp, printvridge, vertex, !qh_ALL, innerouter, inorder);
3307
} /* printvdiagram2 */
3309
/*-<a href="qh-io.htm#TOC"
3310
>-------------------------------</a><a name="printvertex">-</a>
3312
qh_printvertex( fp, vertex )
3313
prints the information in a vertex
3315
void qh_printvertex(FILE *fp, vertexT *vertex) {
3318
facetT *neighbor, **neighborp;
3319
realT r; /*bug fix*/
3322
fprintf (fp, " NULLvertex\n");
3325
fprintf(fp, "- p%d (v%d):", qh_pointid(vertex->point), vertex->id);
3326
point= vertex->point;
3328
for(k= qh hull_dim; k--; ) {
3330
fprintf(fp, " %5.2g", r);
3333
if (vertex->deleted)
3334
fprintf(fp, " deleted");
3335
if (vertex->delridge)
3336
fprintf (fp, " ridgedeleted");
3338
if (vertex->neighbors) {
3339
fprintf(fp, " neighbors:");
3340
FOREACHneighbor_(vertex) {
3341
if (++count % 100 == 0)
3342
fprintf (fp, "\n ");
3343
fprintf(fp, " f%d", neighbor->id);
3350
/*-<a href="qh-io.htm#TOC"
3351
>-------------------------------</a><a name="printvertexlist">-</a>
3353
qh_printvertexlist( fp, string, facetlist, facets, printall )
3354
prints vertices used by a facetlist or facet set
3355
tests qh_skipfacet() if !printall
3357
void qh_printvertexlist (FILE *fp, char* string, facetT *facetlist,
3358
setT *facets, boolT printall) {
3359
vertexT *vertex, **vertexp;
3362
vertices= qh_facetvertices (facetlist, facets, printall);
3364
FOREACHvertex_(vertices)
3365
qh_printvertex(fp, vertex);
3366
qh_settempfree (&vertices);
3367
} /* printvertexlist */
3370
/*-<a href="qh-io.htm#TOC"
3371
>-------------------------------</a><a name="printvertices">-</a>
3373
qh_printvertices( fp, string, vertices )
3374
prints vertices in a set
3376
void qh_printvertices(FILE *fp, char* string, setT *vertices) {
3377
vertexT *vertex, **vertexp;
3380
FOREACHvertex_(vertices)
3381
fprintf (fp, " p%d (v%d)", qh_pointid(vertex->point), vertex->id);
3383
} /* printvertices */
3385
/*-<a href="qh-io.htm#TOC"
3386
>-------------------------------</a><a name="printvneighbors">-</a>
3388
qh_printvneighbors( fp, facetlist, facets, printall )
3389
print vertex neighbors of vertices in facetlist and facets ('FN')
3392
qh_countfacets clears facet->visitid for non-printed facets
3395
collect facet count and related statistics
3396
if necessary, build neighbor sets for each vertex
3397
collect vertices in facetlist and facets
3398
build a point array for point->vertex and point->coplanar facet
3400
list vertex neighbors or coplanar facet
3402
void qh_printvneighbors (FILE *fp, facetT* facetlist, setT *facets, boolT printall) {
3403
int numfacets, numsimplicial, numridges, totneighbors, numneighbors, numcoplanars, numtricoplanars;
3404
setT *vertices, *vertex_points, *coplanar_points;
3405
int numpoints= qh num_points + qh_setsize (qh other_points);
3406
vertexT *vertex, **vertexp;
3407
int vertex_i, vertex_n;
3408
facetT *facet, **facetp, *neighbor, **neighborp;
3409
pointT *point, **pointp;
3411
qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial,
3412
&totneighbors, &numridges, &numcoplanars, &numtricoplanars); /* sets facet->visitid */
3413
fprintf (fp, "%d\n", numpoints);
3414
qh_vertexneighbors();
3415
vertices= qh_facetvertices (facetlist, facets, printall);
3416
vertex_points= qh_settemp (numpoints);
3417
coplanar_points= qh_settemp (numpoints);
3418
qh_setzero (vertex_points, 0, numpoints);
3419
qh_setzero (coplanar_points, 0, numpoints);
3420
FOREACHvertex_(vertices)
3421
qh_point_add (vertex_points, vertex->point, vertex);
3422
FORALLfacet_(facetlist) {
3423
FOREACHpoint_(facet->coplanarset)
3424
qh_point_add (coplanar_points, point, facet);
3426
FOREACHfacet_(facets) {
3427
FOREACHpoint_(facet->coplanarset)
3428
qh_point_add (coplanar_points, point, facet);
3430
FOREACHvertex_i_(vertex_points) {
3432
numneighbors= qh_setsize (vertex->neighbors);
3433
fprintf (fp, "%d", numneighbors);
3434
if (qh hull_dim == 3)
3435
qh_order_vertexneighbors (vertex);
3436
else if (qh hull_dim >= 4)
3437
qsort (SETaddr_(vertex->neighbors, facetT), numneighbors,
3438
sizeof (facetT *), qh_compare_facetvisit);
3439
FOREACHneighbor_(vertex)
3441
neighbor->visitid ? neighbor->visitid - 1 : - neighbor->id);
3443
}else if ((facet= SETelemt_(coplanar_points, vertex_i, facetT)))
3444
fprintf (fp, "1 %d\n",
3445
facet->visitid ? facet->visitid - 1 : - facet->id);
3447
fprintf (fp, "0\n");
3449
qh_settempfree (&coplanar_points);
3450
qh_settempfree (&vertex_points);
3451
qh_settempfree (&vertices);
3452
} /* printvneighbors */
3454
/*-<a href="qh-io.htm#TOC"
3455
>-------------------------------</a><a name="printvoronoi">-</a>
3457
qh_printvoronoi( fp, format, facetlist, facets, printall )
3458
print voronoi diagram in 'o' or 'G' format
3460
prints voronoi centers for each facet and for infinity
3461
for each vertex, lists ids of printed facets or infinity
3462
assumes facetlist and facets are disjoint
3464
prints an OFF object
3465
adds a 0 coordinate to center
3466
prints infinity but does not list in vertices
3473
prints a line for each point except "at-infinity"
3474
if all facets are upperdelaunay,
3475
reverses lower and upper hull
3477
void qh_printvoronoi (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
3478
int k, numcenters, numvertices= 0, numneighbors, numinf, vid=1, vertex_i, vertex_n;
3479
facetT *facet, **facetp, *neighbor, **neighborp;
3483
unsigned int numfacets= (unsigned int) qh num_facets;
3485
vertices= qh_markvoronoi (facetlist, facets, printall, &islower, &numcenters);
3486
FOREACHvertex_i_(vertices) {
3489
numneighbors = numinf = 0;
3490
FOREACHneighbor_(vertex) {
3491
if (neighbor->visitid == 0)
3493
else if (neighbor->visitid < numfacets)
3496
if (numinf && !numneighbors) {
3497
SETelem_(vertices, vertex_i)= NULL;
3502
if (format == qh_PRINTgeom)
3503
fprintf (fp, "{appearance {+edge -face} OFF %d %d 1 # Voronoi centers and cells\n",
3504
numcenters, numvertices);
3506
fprintf (fp, "%d\n%d %d 1\n", qh hull_dim-1, numcenters, qh_setsize(vertices));
3507
if (format == qh_PRINTgeom) {
3508
for (k= qh hull_dim-1; k--; )
3509
fprintf (fp, qh_REAL_1, 0.0);
3510
fprintf (fp, " 0 # infinity not used\n");
3512
for (k= qh hull_dim-1; k--; )
3513
fprintf (fp, qh_REAL_1, qh_INFINITE);
3516
FORALLfacet_(facetlist) {
3517
if (facet->visitid && facet->visitid < numfacets) {
3518
if (format == qh_PRINTgeom)
3519
fprintf (fp, "# %d f%d\n", vid++, facet->id);
3520
qh_printcenter (fp, format, NULL, facet);
3523
FOREACHfacet_(facets) {
3524
if (facet->visitid && facet->visitid < numfacets) {
3525
if (format == qh_PRINTgeom)
3526
fprintf (fp, "# %d f%d\n", vid++, facet->id);
3527
qh_printcenter (fp, format, NULL, facet);
3530
FOREACHvertex_i_(vertices) {
3534
if (qh hull_dim == 3)
3535
qh_order_vertexneighbors(vertex);
3536
else if (qh hull_dim >= 4)
3537
qsort (SETaddr_(vertex->neighbors, vertexT),
3538
qh_setsize (vertex->neighbors),
3539
sizeof (facetT *), qh_compare_facetvisit);
3540
FOREACHneighbor_(vertex) {
3541
if (neighbor->visitid == 0)
3543
else if (neighbor->visitid < numfacets)
3547
if (format == qh_PRINTgeom) {
3549
fprintf (fp, "%d", numneighbors);
3551
FOREACHneighbor_(vertex) {
3552
if (neighbor->visitid && neighbor->visitid < numfacets)
3553
fprintf (fp, " %d", neighbor->visitid);
3556
fprintf (fp, " # p%d (v%d)\n", vertex_i, vertex->id);
3558
fprintf (fp, " # p%d is coplanar or isolated\n", vertex_i);
3562
fprintf (fp, "%d", numneighbors);
3564
FOREACHneighbor_(vertex) {
3565
if (neighbor->visitid == 0) {
3568
fprintf (fp, " %d", neighbor->visitid);
3570
}else if (neighbor->visitid < numfacets)
3571
fprintf (fp, " %d", neighbor->visitid);
3577
if (format == qh_PRINTgeom)
3578
fprintf (fp, "}\n");
3579
qh_settempfree (&vertices);
3580
} /* printvoronoi */
3582
/*-<a href="qh-io.htm#TOC"
3583
>-------------------------------</a><a name="printvnorm">-</a>
3585
qh_printvnorm( fp, vertex, vertexA, centers, unbounded )
3586
print one separating plane of the Voronoi diagram for a pair of input sites
3587
unbounded==True if centers includes vertex-at-infinity
3590
qh_ASvoronoi and qh_vertexneighbors() already set
3596
void qh_printvnorm (FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {
3601
normal= qh_detvnorm (vertex, vertexA, centers, &offset);
3602
fprintf (fp, "%d %d %d ",
3603
2+qh hull_dim, qh_pointid (vertex->point), qh_pointid (vertexA->point));
3604
for (k= 0; k< qh hull_dim-1; k++)
3605
fprintf (fp, qh_REAL_1, normal[k]);
3606
fprintf (fp, qh_REAL_1, offset);
3610
/*-<a href="qh-io.htm#TOC"
3611
>-------------------------------</a><a name="printvridge">-</a>
3613
qh_printvridge( fp, vertex, vertexA, centers, unbounded )
3614
print one ridge of the Voronoi diagram for a pair of input sites
3615
unbounded==True if centers includes vertex-at-infinity
3621
the user may use a different function
3623
void qh_printvridge (FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {
3624
facetT *facet, **facetp;
3626
fprintf (fp, "%d %d %d", qh_setsize (centers)+2,
3627
qh_pointid (vertex->point), qh_pointid (vertexA->point));
3628
FOREACHfacet_(centers)
3629
fprintf (fp, " %d", facet->visitid);
3633
/*-<a href="qh-io.htm#TOC"
3634
>-------------------------------</a><a name="projectdim3">-</a>
3636
qh_projectdim3( source, destination )
3637
project 2-d 3-d or 4-d point to a 3-d point
3638
uses qh.DROPdim and qh.hull_dim
3639
source and destination may be the same
3642
allocate 4 elements to destination just in case
3644
void qh_projectdim3 (pointT *source, pointT *destination) {
3647
for (k= 0, i=0; k < qh hull_dim; k++) {
3648
if (qh hull_dim == 4) {
3649
if (k != qh DROPdim)
3650
destination[i++]= source[k];
3651
}else if (k == qh DROPdim)
3652
destination[i++]= 0;
3654
destination[i++]= source[k];
3657
destination[i++]= 0.0;
3660
/*-<a href="qh-io.htm#TOC"
3661
>-------------------------------</a><a name="readfeasible">-</a>
3663
qh_readfeasible( dim, remainder )
3664
read feasible point from remainder string and qh.fin
3667
number of lines read from qh.fin
3668
sets qh.FEASIBLEpoint with malloc'd coordinates
3671
checks for qh.HALFspace
3677
int qh_readfeasible (int dim, char *remainder) {
3678
boolT isfirst= True;
3679
int linecount= 0, tokcount= 0;
3680
char *s, *t, firstline[qh_MAXfirst+1];
3681
coordT *coords, value;
3683
if (!qh HALFspace) {
3684
fprintf (qh ferr, "qhull input error: feasible point (dim 1 coords) is only valid for halfspace intersection\n");
3685
qh_errexit (qh_ERRinput, NULL, NULL);
3687
if (qh feasible_string)
3688
fprintf (qh ferr, "qhull input warning: feasible point (dim 1 coords) overrides 'Hn,n,n' feasible point for halfspace intersection\n");
3689
if (!(qh feasible_point= (coordT*)malloc (dim* sizeof(coordT)))) {
3690
fprintf(qh ferr, "qhull error: insufficient memory for feasible point\n");
3691
qh_errexit(qh_ERRmem, NULL, NULL);
3693
coords= qh feasible_point;
3694
while ((s= (isfirst ? remainder : fgets(firstline, qh_MAXfirst, qh fin)))) {
3702
value= qh_strtod (s, &t);
3707
if (++tokcount == dim) {
3708
while (isspace (*s))
3712
fprintf (qh ferr, "qhull input error: coordinates for feasible point do not finish out the line: %s\n",
3714
qh_errexit (qh_ERRinput, NULL, NULL);
3720
fprintf (qh ferr, "qhull input error: only %d coordinates. Could not read %d-d feasible point.\n",
3722
qh_errexit (qh_ERRinput, NULL, NULL);
3724
} /* readfeasible */
3726
/*-<a href="qh-io.htm#TOC"
3727
>-------------------------------</a><a name="readpoints">-</a>
3729
qh_readpoints( numpoints, dimension, ismalloc )
3730
read points from qh.fin into qh.first_point, qh.num_points
3731
qh.fin is lines of coordinates, one per vertex, first line number of points
3735
adds point-at-infinity for Delaunay triangulations
3738
number of points, array of point coordinates, dimension, ismalloc True
3739
if qh.DELAUNAY & !qh.PROJECTinput, projects points to paraboloid
3740
and clears qh.PROJECTdelaunay
3741
if qh.HALFspace, reads optional feasible point, reads halfspaces,
3744
for feasible point in "cdd format" in 3-d:
3754
dimension will change in qh_initqhull_globals if qh.PROJECTinput
3755
uses malloc() since qh_mem not initialized
3756
FIXUP: this routine needs rewriting
3758
coordT *qh_readpoints(int *numpoints, int *dimension, boolT *ismalloc) {
3759
coordT *points, *coords, *infinity= NULL;
3760
realT paraboloid, maxboloid= -REALmax, value;
3761
realT *coordp= NULL, *offsetp= NULL, *normalp= NULL;
3762
char *s, *t, firstline[qh_MAXfirst+1];
3763
int diminput=0, numinput=0, dimfeasible= 0, newnum, k, tempi;
3764
int firsttext=0, firstshort=0, firstlong=0, firstpoint=0;
3765
int tokcount= 0, linecount=0, maxcount, coordcount=0;
3766
boolT islong, isfirst= True, wasbegin= False;
3767
boolT isdelaunay= qh DELAUNAY && !qh PROJECTinput;
3770
while ((s= fgets(firstline, qh_MAXfirst, qh fin))) {
3772
if (qh HALFspace && linecount == 1 && isdigit(*s)) {
3773
dimfeasible= qh_strtol (s, &s);
3776
if (qh_strtol (s, &s) == 1)
3777
linecount += qh_readfeasible (dimfeasible, s);
3780
}else if (!memcmp (firstline, "begin", 5) || !memcmp (firstline, "BEGIN", 5))
3782
else if (!*qh rbox_command)
3783
strncat(qh rbox_command, s, sizeof (qh rbox_command)-1);
3786
fprintf (qh ferr, "qhull input error: missing \"begin\" for cdd-formated input\n");
3787
qh_errexit (qh_ERRinput, NULL, NULL);
3790
while(!numinput && (s= fgets(firstline, qh_MAXfirst, qh fin))) {
3792
if (!memcmp (s, "begin", 5) || !memcmp (s, "BEGIN", 5))
3800
if (!*qh rbox_command) {
3801
strncat(qh rbox_command, s, sizeof (qh rbox_command)-1);
3802
firsttext= linecount;
3807
diminput= qh_strtol (s, &s);
3809
numinput= qh_strtol (s, &s);
3810
if (numinput == 1 && diminput >= 2 && qh HALFspace && !qh CDDinput) {
3811
linecount += qh_readfeasible (diminput, s); /* checks if ok */
3812
dimfeasible= diminput;
3813
diminput= numinput= 0;
3820
fprintf(qh ferr, "qhull input error: short input file. Did not find dimension and number of points\n");
3821
qh_errexit(qh_ERRinput, NULL, NULL);
3823
if (diminput > numinput) {
3824
tempi= diminput; /* exchange dim and n, e.g., for cdd input format */
3829
fprintf(qh ferr,"qhull input error: dimension %d (first number) should be at least 2\n",
3831
qh_errexit(qh_ERRinput, NULL, NULL);
3834
qh PROJECTdelaunay= False;
3836
*dimension= diminput;
3838
*dimension= diminput+1;
3839
*numpoints= numinput;
3842
}else if (qh HALFspace) {
3843
*dimension= diminput - 1;
3844
*numpoints= numinput;
3846
fprintf(qh ferr,"qhull input error: dimension %d (first number, includes offset) should be at least 3 for halfspaces\n",
3848
qh_errexit(qh_ERRinput, NULL, NULL);
3851
if (dimfeasible != *dimension) {
3852
fprintf(qh ferr,"qhull input error: dimension %d of feasible point is not one less than dimension %d for halfspaces\n",
3853
dimfeasible, diminput);
3854
qh_errexit(qh_ERRinput, NULL, NULL);
3857
qh_setfeasible (*dimension);
3860
*dimension= diminput-1;
3862
*dimension= diminput;
3863
*numpoints= numinput;
3865
qh normal_size= *dimension * sizeof(coordT); /* for tracing with qh_printpoint */
3867
qh half_space= coordp= (coordT*) malloc (qh normal_size + sizeof(coordT));
3869
offsetp= qh half_space;
3870
normalp= offsetp + 1;
3872
normalp= qh half_space;
3873
offsetp= normalp + *dimension;
3876
qh maxline= diminput * (qh_REALdigits + 5);
3877
maximize_(qh maxline, 500);
3878
qh line= (char*)malloc ((qh maxline+1) * sizeof (char));
3879
*ismalloc= True; /* use malloc since memory not setup */
3880
coords= points= qh temp_malloc=
3881
(coordT*)malloc((*numpoints)*(*dimension)*sizeof(coordT));
3882
if (!coords || !qh line || (qh HALFspace && !qh half_space)) {
3883
fprintf(qh ferr, "qhull error: insufficient memory to read %d points\n",
3885
qh_errexit(qh_ERRmem, NULL, NULL);
3887
if (isdelaunay && qh ATinfinity) {
3888
infinity= points + numinput * (*dimension);
3889
for (k= (*dimension) - 1; k--; )
3892
maxcount= numinput * diminput;
3894
while ((s= (isfirst ? s : fgets(qh line, qh maxline, qh fin)))) {
3897
if (*s == 'e' || *s == 'E') {
3898
if (!memcmp (s, "end", 3) || !memcmp (s, "END", 3)) {
3902
fprintf (qh ferr, "qhull input warning: the input appears to be in cdd format. If so, use 'Fd'\n");
3910
value= qh_strtod (s, &t);
3912
if (!*qh rbox_command)
3913
strncat(qh rbox_command, s, sizeof (qh rbox_command)-1);
3914
if (*s && !firsttext)
3915
firsttext= linecount;
3916
if (!islong && !firstshort && coordcount)
3917
firstshort= linecount;
3921
firstpoint= linecount;
3923
if (++tokcount > maxcount)
3927
*(coordp++)= -value; /* both coefficients and offset */
3932
if (qh CDDinput && !coordcount) {
3934
fprintf (qh ferr, "qhull input error: for cdd format, point at line %d does not start with '1'\n",
3936
qh_errexit (qh_ERRinput, NULL, NULL);
3939
}else if (isdelaunay) {
3940
paraboloid += value * value;
3941
if (qh ATinfinity) {
3943
infinity[coordcount-1] += value;
3945
infinity[coordcount] += value;
3949
if (++coordcount == diminput) {
3952
*(coords++)= paraboloid;
3953
maximize_(maxboloid, paraboloid);
3955
}else if (qh HALFspace) {
3956
if (!qh_sethalfspace (*dimension, coords, &coords, normalp, offsetp, qh feasible_point)) {
3957
fprintf (qh ferr, "The halfspace was on line %d\n", linecount);
3959
fprintf (qh ferr, "The input appears to be in cdd format. If so, you should use option 'Fd'\n");
3960
qh_errexit (qh_ERRinput, NULL, NULL);
3962
coordp= qh half_space;
3969
firstlong= linecount;
3973
if (!islong && !firstshort && coordcount)
3974
firstshort= linecount;
3975
if (!isfirst && s - qh line >= qh maxline) {
3976
fprintf(qh ferr, "qhull input error: line %d contained more than %d characters\n",
3977
linecount, (int) (s - qh line));
3978
qh_errexit(qh_ERRinput, NULL, NULL);
3982
if (tokcount != maxcount) {
3983
newnum= fmin_(numinput, tokcount/diminput);
3985
qhull warning: instead of %d %d-dimensional points, input contains\n\
3986
%d points and %d extra coordinates. Line %d is the first\npoint",
3987
numinput, diminput, tokcount/diminput, tokcount % diminput, firstpoint);
3989
fprintf(qh ferr, ", line %d is the first comment", firsttext);
3991
fprintf(qh ferr, ", line %d is the first short\nline", firstshort);
3993
fprintf(qh ferr, ", line %d is the first long line", firstlong);
3994
fprintf(qh ferr, ". Continue with %d points.\n", newnum);
3996
if (isdelaunay && qh ATinfinity) {
3997
for (k= tokcount % diminput; k--; )
3998
infinity[k] -= *(--coords);
3999
*numpoints= newnum+1;
4001
coords -= tokcount % diminput;
4005
if (isdelaunay && qh ATinfinity) {
4006
for (k= (*dimension) -1; k--; )
4007
infinity[k] /= numinput;
4008
if (coords == infinity)
4009
coords += (*dimension) -1;
4011
for (k= 0; k < (*dimension) -1; k++)
4012
*(coords++)= infinity[k];
4014
*(coords++)= maxboloid * 1.1;
4016
if (qh rbox_command[0]) {
4017
qh rbox_command[strlen(qh rbox_command)-1]= '\0';
4018
if (!strcmp (qh rbox_command, "./rbox D4"))
4019
fprintf (qh ferr, "\n\
4020
This is the qhull test case. If any errors or core dumps occur,\n\
4021
recompile qhull with 'make new'. If errors still occur, there is\n\
4022
an incompatibility. You should try a different compiler. You can also\n\
4023
change the choices in user.h. If you discover the source of the problem,\n\
4024
please send mail to qhull_bug@qhull.org.\n\
4026
Type 'qhull' for a short list of options.\n");
4030
if (qh half_space) {
4031
free (qh half_space);
4032
qh half_space= NULL;
4034
qh temp_malloc= NULL;
4035
trace1((qh ferr,"qh_readpoints: read in %d %d-dimensional points\n",
4036
numinput, diminput));
4041
/*-<a href="qh-io.htm#TOC"
4042
>-------------------------------</a><a name="setfeasible">-</a>
4044
qh_setfeasible( dim )
4045
set qh.FEASIBLEpoint from qh.feasible_string in "n,n,n" or "n n n" format
4048
"n,n,n" already checked by qh_initflags()
4049
see qh_readfeasible()
4051
void qh_setfeasible (int dim) {
4054
coordT *coords, value;
4056
if (!(s= qh feasible_string)) {
4058
qhull input error: halfspace intersection needs a feasible point.\n\
4059
Either prepend the input with 1 point or use 'Hn,n,n'. See manual.\n");
4060
qh_errexit (qh_ERRinput, NULL, NULL);
4062
if (!(qh feasible_point= (pointT*)malloc (dim* sizeof(coordT)))) {
4063
fprintf(qh ferr, "qhull error: insufficient memory for 'Hn,n,n'\n");
4064
qh_errexit(qh_ERRmem, NULL, NULL);
4066
coords= qh feasible_point;
4068
value= qh_strtod (s, &s);
4069
if (++tokcount > dim) {
4070
fprintf (qh ferr, "qhull input warning: more coordinates for 'H%s' than dimension %d\n",
4071
qh feasible_string, dim);
4078
while (++tokcount <= dim)
4082
/*-<a href="qh-io.htm#TOC"
4083
>-------------------------------</a><a name="skipfacet">-</a>
4085
qh_skipfacet( facet )
4086
returns 'True' if this facet is not to be printed
4089
based on the user provided slice thresholds and 'good' specifications
4091
boolT qh_skipfacet(facetT *facet) {
4092
facetT *neighbor, **neighborp;
4094
if (qh PRINTneighbors) {
4096
return !qh PRINTgood;
4097
FOREACHneighbor_(facet) {
4102
}else if (qh PRINTgood)
4103
return !facet->good;
4104
else if (!facet->normal)
4106
return (!qh_inthresholds (facet->normal, NULL));