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

File Contents

# Content
1 /*<html><pre> -<a href="qh-io.htm"
2 >-------------------------------</a><a name="TOP">-</a>
3
4 io.c
5 Input/Output routines of qhull application
6
7 see qh-io.htm and io.h
8
9 see user.c for qh_errprint and qh_printfacetlist
10
11 unix.c calls qh_readpoints and qh_produce_output
12
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
15
16 copyright (c) 1993-2003 The Geometry Center
17 */
18
19 #include "QuickHull/qhull_a.h"
20
21 /*========= -functions in alphabetical order after qh_produce_output() =====*/
22
23 /*-<a href="qh-io.htm#TOC"
24 >-------------------------------</a><a name="produce_output">-</a>
25
26 qh_produce_output()
27 prints out the result of qhull in desired format
28 if qh.GETarea
29 computes and prints area and volume
30 qh.PRINTout[] is an array of output formats
31
32 notes:
33 prints output in qh.PRINTout order
34 */
35 void qh_produce_output(void) {
36 int i, tempsize= qh_setsize ((setT*)qhmem.tempstack), d_1;
37
38 if (qh VORONOI) {
39 qh_clearcenters (qh_ASvoronoi);
40 qh_vertexneighbors();
41 }
42 if (qh TRIangulate) {
43 qh_triangulate();
44 if (qh VERIFYoutput && !qh CHECKfrequently)
45 qh_checkpolygon (qh facet_list);
46 }
47 qh_findgood_all (qh facet_list);
48 if (qh GETarea)
49 qh_getarea(qh facet_list);
50 if (qh KEEParea || qh KEEPmerge || qh KEEPminArea < REALmax/2)
51 qh_markkeep (qh facet_list);
52 if (qh PRINTsummary)
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);
58 qh_allstatistics();
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;
68 fprintf(qh ferr, "\
69 size in bytes: merge %d ridge %d vertex %d facet %d\n\
70 normal %d ridge vertices %d facet vertices or neighbors %d\n",
71 sizeof(mergeT), sizeof(ridgeT),
72 sizeof(vertexT), sizeof(facetT),
73 qh normal_size, d_1, d_1 + SETelemsize);
74 }
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);
79 }
80 } /* produce_output */
81
82
83 /*-<a href="qh-io.htm#TOC"
84 >-------------------------------</a><a name="dfacet">-</a>
85
86 dfacet( id )
87 print facet by id, for debugging
88
89 */
90 void dfacet (unsigned id) {
91 facetT *facet;
92
93 FORALLfacets {
94 if (facet->id == id) {
95 qh_printfacet (qh fout, facet);
96 break;
97 }
98 }
99 } /* dfacet */
100
101
102 /*-<a href="qh-io.htm#TOC"
103 >-------------------------------</a><a name="dvertex">-</a>
104
105 dvertex( id )
106 print vertex by id, for debugging
107 */
108 void dvertex (unsigned id) {
109 vertexT *vertex;
110
111 FORALLvertices {
112 if (vertex->id == id) {
113 qh_printvertex (qh fout, vertex);
114 break;
115 }
116 }
117 } /* dvertex */
118
119
120 /*-<a href="qh-io.htm#TOC"
121 >-------------------------------</a><a name="compare_vertexpoint">-</a>
122
123 qh_compare_vertexpoint( p1, p2 )
124 used by qsort() to order vertices by point id
125 */
126 int qh_compare_vertexpoint(const void *p1, const void *p2) {
127 vertexT *a= *((vertexT **)p1), *b= *((vertexT **)p2);
128
129 return ((qh_pointid(a->point) > qh_pointid(b->point)?1:-1));
130 } /* compare_vertexpoint */
131
132 /*-<a href="qh-io.htm#TOC"
133 >-------------------------------</a><a name="compare_facetarea">-</a>
134
135 qh_compare_facetarea( p1, p2 )
136 used by qsort() to order facets by area
137 */
138 int qh_compare_facetarea(const void *p1, const void *p2) {
139 facetT *a= *((facetT **)p1), *b= *((facetT **)p2);
140
141 if (!a->isarea)
142 return -1;
143 if (!b->isarea)
144 return 1;
145 if (a->f.area > b->f.area)
146 return 1;
147 else if (a->f.area == b->f.area)
148 return 0;
149 return -1;
150 } /* compare_facetarea */
151
152 /*-<a href="qh-io.htm#TOC"
153 >-------------------------------</a><a name="compare_facetmerge">-</a>
154
155 qh_compare_facetmerge( p1, p2 )
156 used by qsort() to order facets by number of merges
157 */
158 int qh_compare_facetmerge(const void *p1, const void *p2) {
159 facetT *a= *((facetT **)p1), *b= *((facetT **)p2);
160
161 return (a->nummerge - b->nummerge);
162 } /* compare_facetvisit */
163
164 /*-<a href="qh-io.htm#TOC"
165 >-------------------------------</a><a name="compare_facetvisit">-</a>
166
167 qh_compare_facetvisit( p1, p2 )
168 used by qsort() to order facets by visit id or id
169 */
170 int qh_compare_facetvisit(const void *p1, const void *p2) {
171 facetT *a= *((facetT **)p1), *b= *((facetT **)p2);
172 int i,j;
173
174 if (!(i= a->visitid))
175 i= - a->id; /* do not convert to int */
176 if (!(j= b->visitid))
177 j= - b->id;
178 return (i - j);
179 } /* compare_facetvisit */
180
181 /*-<a href="qh-io.htm#TOC"
182 >-------------------------------</a><a name="countfacets">-</a>
183
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()
188
189 notes:
190 qh_printsummary and qh_countfacets must match counts
191
192 returns:
193 numfacets, numsimplicial, total neighbors, numridges, coplanars
194 each facet with ->visitid indicating 1-relative position
195 ->visitid==0 indicates not good
196
197 notes
198 numfacets >= numsimplicial
199 if qh.NEWfacets,
200 does not count visible facets (matches qh_printafacet)
201
202 design:
203 for all facets on facetlist and in facets set
204 unless facet is skipped or visible (i.e., will be deleted)
205 mark facet->visitid
206 update counts
207 */
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;
212
213 FORALLfacet_(facetlist) {
214 if ((facet->visible && qh NEWfacets)
215 || (!printall && qh_skipfacet(facet)))
216 facet->visitid= 0;
217 else {
218 facet->visitid= ++numfacets;
219 totneighbors += qh_setsize (facet->neighbors);
220 if (facet->simplicial) {
221 numsimplicial++;
222 if (facet->keepcentrum && facet->tricoplanar)
223 numtricoplanars++;
224 }else
225 numridges += qh_setsize (facet->ridges);
226 if (facet->coplanarset)
227 numcoplanars += qh_setsize (facet->coplanarset);
228 }
229 }
230 FOREACHfacet_(facets) {
231 if ((facet->visible && qh NEWfacets)
232 || (!printall && qh_skipfacet(facet)))
233 facet->visitid= 0;
234 else {
235 facet->visitid= ++numfacets;
236 totneighbors += qh_setsize (facet->neighbors);
237 if (facet->simplicial){
238 numsimplicial++;
239 if (facet->keepcentrum && facet->tricoplanar)
240 numtricoplanars++;
241 }else
242 numridges += qh_setsize (facet->ridges);
243 if (facet->coplanarset)
244 numcoplanars += qh_setsize (facet->coplanarset);
245 }
246 }
247 qh visit_id += numfacets+1;
248 *numfacetsp= numfacets;
249 *numsimplicialp= numsimplicial;
250 *totneighborsp= totneighbors;
251 *numridgesp= numridges;
252 *numcoplanarsp= numcoplanars;
253 *numtricoplanarsp= numtricoplanars;
254 } /* countfacets */
255
256 /*-<a href="qh-io.htm#TOC"
257 >-------------------------------</a><a name="detvnorm">-</a>
258
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)
263
264 assumes:
265 qh_ASvoronoi and qh_vertexneighbors() already set
266
267 returns:
268 norm
269 a pointer into qh.gm_matrix to qh.hull_dim-1 reals
270 copy the data before reusing qh.gm_matrix
271 offset
272 if 'QVn'
273 sign adjusted so that qh.GOODvertexp is inside
274 else
275 sign adjusted so that vertex is inside
276
277 qh.gm_matrix= simplex of points from centers relative to first center
278
279 notes:
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
282
283 design:
284 determine midpoint of input sites
285 build points as the set of Voronoi vertices
286 select a simplex from points (if necessary)
287 incl. 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'
291 if 'Tv' or 'Ts'
292 if bounded
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
296 */
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;
300 setT *simplex= NULL;
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;
306 int numcenters= 0;
307 int dim= qh hull_dim - 1;
308 realT dist, offset, angle, zero= 0.0;
309
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) {
314 numcenters++;
315 if (!facet->visitid)
316 unbounded= True;
317 else {
318 if (!facet->center)
319 facet->center= qh_facetcenter (facet->vertices);
320 qh_setappend (&points, facet->center);
321 }
322 }
323 if (numcenters > dim) {
324 simplex= qh_settemp (qh TEMPsize);
325 qh_setappend (&simplex, vertex->point);
326 if (unbounded)
327 qh_setappend (&simplex, midpoint);
328 qh_maxsimplex (dim, points, NULL, 0, &simplex);
329 qh_setdelnth (simplex, 0);
330 }else if (numcenters == dim) {
331 if (unbounded)
332 qh_setappend (&points, midpoint);
333 simplex= points;
334 }else {
335 fprintf(qh ferr, "qh_detvnorm: too few points (%d) to compute separating plane\n", numcenters);
336 qh_errexit (qh_ERRqhull, NULL, NULL);
337 }
338 i= 0;
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",
344 &point, 1, dim);
345 if (point != point0) {
346 qh gm_row[i++]= gmcoord;
347 coord= point0;
348 for (k= dim; k--; )
349 *(gmcoord++)= *point++ - *coord++;
350 }
351 }
352 qh gm_row[i]= gmcoord; /* does not overlap midpoint, may be used later for qh_areasimplex */
353 normal= gmcoord;
354 qh_sethyperplane_gauss (dim, qh gm_row, point0, True,
355 normal, &offset, &nearzero);
356 if (qh GOODvertexp == vertexA->point)
357 inpoint= vertexA->point;
358 else
359 inpoint= vertex->point;
360 zinc_(Zdistio);
361 dist= qh_distnorm (dim, inpoint, normal, &offset);
362 if (dist > 0) {
363 offset= -offset;
364 normalp= normal;
365 for (k= dim; k--; ) {
366 *normalp= -(*normalp);
367 normalp++;
368 }
369 }
370 if (qh VERIFYoutput || qh PRINTstatistics) {
371 pointid= qh_pointid (vertex->point);
372 pointidA= qh_pointid (vertexA->point);
373 if (!unbounded) {
374 zinc_(Zdiststat);
375 dist= qh_distnorm (dim, midpoint, normal, &offset);
376 if (dist < 0)
377 dist= -dist;
378 zzinc_(Zridgemid);
379 wwmax_(Wridgemidmax, dist);
380 wwadd_(Wridgemid, dist);
381 trace4((qh ferr, "qh_detvnorm: points %d %d midpoint dist %2.2g\n", pointid, pointidA, dist));
382 for (k= 0; k < dim; k++)
383 midpoint[k]= vertexA->point[k] - vertex->point[k]; /* overwrites midpoint! */
384 qh_normalize (midpoint, dim, False);
385 angle= qh_distnorm (dim, midpoint, normal, &zero); /* qh_detangle uses dim+1 */
386 if (angle < 0.0)
387 angle= angle + 1.0;
388 else
389 angle= angle - 1.0;
390 if (angle < 0.0)
391 angle -= angle;
392 trace4((qh ferr, "qh_detvnorm: points %d %d angle %2.2g nearzero %d\n", pointid, pointidA, angle, nearzero));
393 if (nearzero) {
394 zzinc_(Zridge0);
395 wwmax_(Wridge0max, angle);
396 wwadd_(Wridge0, angle);
397 }else {
398 zzinc_(Zridgeok)
399 wwmax_(Wridgeokmax, angle);
400 wwadd_(Wridgeok, angle);
401 }
402 }
403 if (simplex != points) {
404 FOREACHpoint_i_(points) {
405 if (!qh_setin (simplex, point)) {
406 facet= SETelemt_(centers, point_i, facetT);
407 zinc_(Zdiststat);
408 dist= qh_distnorm (dim, point, normal, &offset);
409 if (dist < 0)
410 dist= -dist;
411 zzinc_(Zridge);
412 wwmax_(Wridgemax, dist);
413 wwadd_(Wridge, dist);
414 trace4((qh ferr, "qh_detvnorm: points %d %d Voronoi vertex %d dist %2.2g\n", pointid, pointidA, facet->visitid, dist));
415 }
416 }
417 }
418 }
419 *offsetp= offset;
420 if (simplex != points)
421 qh_settempfree (&simplex);
422 qh_settempfree (&points);
423 return normal;
424 } /* detvnorm */
425
426 /*-<a href="qh-io.htm#TOC"
427 >-------------------------------</a><a name="detvridge">-</a>
428
429 qh_detvridge( vertexA )
430 determine Voronoi ridge from 'seen' neighbors of vertexA
431 incl. one vertex-at-infinite if an !neighbor->visitid
432
433 returns:
434 temporary set of centers (facets, i.e., Voronoi vertices)
435 sorted by center id
436 */
437 setT *qh_detvridge (vertexT *vertex) {
438 setT *centers= qh_settemp (qh TEMPsize);
439 setT *tricenters= qh_settemp (qh TEMPsize);
440 facetT *neighbor, **neighborp;
441 boolT firstinf= True;
442
443 FOREACHneighbor_(vertex) {
444 if (neighbor->seen) {
445 if (neighbor->visitid) {
446 if (!neighbor->tricoplanar || qh_setunique (&tricenters, neighbor->center))
447 qh_setappend (&centers, neighbor);
448 }else if (firstinf) {
449 firstinf= False;
450 qh_setappend (&centers, neighbor);
451 }
452 }
453 }
454 qsort (SETaddr_(centers, facetT), qh_setsize (centers),
455 sizeof (facetT *), qh_compare_facetvisit);
456 qh_settempfree (&tricenters);
457 return centers;
458 } /* detvridge */
459
460 /*-<a href="qh-io.htm#TOC"
461 >-------------------------------</a><a name="detvridge3">-</a>
462
463 qh_detvridge3( atvertex, vertex )
464 determine 3-d Voronoi ridge from 'seen' neighbors of atvertex and vertex
465 incl. one vertex-at-infinite for !neighbor->visitid
466 assumes all facet->seen2= True
467
468 returns:
469 temporary set of centers (facets, i.e., Voronoi vertices)
470 listed in adjacency order (not oriented)
471 all facet->seen2= True
472
473 design:
474 mark all neighbors of atvertex
475 for each adjacent neighbor of both atvertex and vertex
476 if neighbor selected
477 add neighbor to set of Voronoi vertices
478 */
479 setT *qh_detvridge3 (vertexT *atvertex, vertexT *vertex) {
480 setT *centers= qh_settemp (qh TEMPsize);
481 setT *tricenters= qh_settemp (qh TEMPsize);
482 facetT *neighbor, **neighborp, *facet= NULL;
483 boolT firstinf= True;
484
485 FOREACHneighbor_(atvertex)
486 neighbor->seen2= False;
487 FOREACHneighbor_(vertex) {
488 if (!neighbor->seen2) {
489 facet= neighbor;
490 break;
491 }
492 }
493 while (facet) {
494 facet->seen2= True;
495 if (neighbor->seen) {
496 if (facet->visitid) {
497 if (!facet->tricoplanar || qh_setunique (&tricenters, facet->center))
498 qh_setappend (&centers, facet);
499 }else if (firstinf) {
500 firstinf= False;
501 qh_setappend (&centers, facet);
502 }
503 }
504 FOREACHneighbor_(facet) {
505 if (!neighbor->seen2) {
506 if (qh_setin (vertex->neighbors, neighbor))
507 break;
508 else
509 neighbor->seen2= True;
510 }
511 }
512 facet= neighbor;
513 }
514 if (qh CHECKfrequently) {
515 FOREACHneighbor_(vertex) {
516 if (!neighbor->seen2) {
517 fprintf (stderr, "qh_detvridge3: neigbors of vertex p%d are not connected at facet %d\n",
518 qh_pointid (vertex->point), neighbor->id);
519 qh_errexit (qh_ERRqhull, neighbor, NULL);
520 }
521 }
522 }
523 FOREACHneighbor_(atvertex)
524 neighbor->seen2= True;
525 qh_settempfree (&tricenters);
526 return centers;
527 } /* detvridge3 */
528
529 /*-<a href="qh-io.htm#TOC"
530 >-------------------------------</a><a name="eachvoronoi">-</a>
531
532 qh_eachvoronoi( fp, printvridge, vertex, visitall, innerouter, inorder )
533 if visitall,
534 visit all Voronoi ridges for vertex (i.e., an input site)
535 else
536 visit all unvisited Voronoi ridges for vertex
537 all vertex->seen= False if unvisited
538 assumes
539 all facet->seen= False
540 all facet->seen2= True (for qh_detvridge3)
541 all facet->visitid == 0 if vertex_at_infinity
542 == index of Voronoi vertex
543 >= qh.num_facets if ignored
544 innerouter:
545 qh_RIDGEall-- both inner (bounded) and outer (unbounded) ridges
546 qh_RIDGEinner- only inner
547 qh_RIDGEouter- only outer
548
549 if inorder
550 orders vertices for 3-d Voronoi diagrams
551
552 returns:
553 number of visited ridges (does not include previously visited ridges)
554
555 if printvridge,
556 calls printvridge( fp, vertex, vertexA, centers)
557 fp== any pointer (assumes FILE*)
558 vertex,vertexA= pair of input sites that define a Voronoi ridge
559 centers= set of facets (i.e., Voronoi vertices)
560 ->visitid == index or 0 if vertex_at_infinity
561 ordered for 3-d Voronoi diagram
562 notes:
563 uses qh.vertex_visit
564
565 see:
566 qh_eachvoronoi_all()
567
568 design:
569 mark selected neighbors of atvertex
570 for each selected neighbor (either Voronoi vertex or vertex-at-infinity)
571 for each unvisited vertex
572 if atvertex and vertex share more than d-1 neighbors
573 bump totalcount
574 if printvridge defined
575 build the set of shared neighbors (i.e., Voronoi vertices)
576 call printvridge
577 */
578 int qh_eachvoronoi (FILE *fp, printvridgeT printvridge, vertexT *atvertex, boolT visitall, qh_RIDGE innerouter, boolT inorder) {
579 boolT unbounded;
580 int count;
581 facetT *neighbor, **neighborp, *neighborA, **neighborAp;
582 setT *centers;
583 setT *tricenters= qh_settemp (qh TEMPsize);
584
585 vertexT *vertex, **vertexp;
586 boolT firstinf;
587 unsigned int numfacets= (unsigned int)qh num_facets;
588 int totridges= 0;
589
590 qh vertex_visit++;
591 atvertex->seen= True;
592 if (visitall) {
593 FORALLvertices
594 vertex->seen= False;
595 }
596 FOREACHneighbor_(atvertex) {
597 if (neighbor->visitid < numfacets)
598 neighbor->seen= True;
599 }
600 FOREACHneighbor_(atvertex) {
601 if (neighbor->seen) {
602 FOREACHvertex_(neighbor->vertices) {
603 if (vertex->visitid != qh vertex_visit && !vertex->seen) {
604 vertex->visitid= qh vertex_visit;
605 count= 0;
606 firstinf= True;
607 qh_settruncate (tricenters, 0);
608 FOREACHneighborA_(vertex) {
609 if (neighborA->seen) {
610 if (neighborA->visitid) {
611 if (!neighborA->tricoplanar || qh_setunique (&tricenters, neighborA->center))
612 count++;
613 }else if (firstinf) {
614 count++;
615 firstinf= False;
616 }
617 }
618 }
619 if (count >= qh hull_dim - 1) { /* e.g., 3 for 3-d Voronoi */
620 if (firstinf) {
621 if (innerouter == qh_RIDGEouter)
622 continue;
623 unbounded= False;
624 }else {
625 if (innerouter == qh_RIDGEinner)
626 continue;
627 unbounded= True;
628 }
629 totridges++;
630 trace4((qh ferr, "qh_eachvoronoi: Voronoi ridge of %d vertices between sites %d and %d\n", count, qh_pointid (atvertex->point), qh_pointid (vertex->point)));
631 if (printvridge) {
632 if (inorder && qh hull_dim == 3+1) /* 3-d Voronoi diagram */
633 centers= qh_detvridge3 (atvertex, vertex);
634 else
635 centers= qh_detvridge (vertex);
636 (*printvridge) (fp, atvertex, vertex, centers, unbounded);
637 qh_settempfree (&centers);
638 }
639 }
640 }
641 }
642 }
643 }
644 FOREACHneighbor_(atvertex)
645 neighbor->seen= False;
646 qh_settempfree (&tricenters);
647 return totridges;
648 } /* eachvoronoi */
649
650
651 /*-<a href="qh-poly.htm#TOC"
652 >-------------------------------</a><a name="eachvoronoi_all">-</a>
653
654 qh_eachvoronoi_all( fp, printvridge, isupper, innerouter, inorder )
655 visit all Voronoi ridges
656
657 innerouter:
658 see qh_eachvoronoi()
659
660 if inorder
661 orders vertices for 3-d Voronoi diagrams
662
663 returns
664 total number of ridges
665
666 if isupper == facet->upperdelaunay (i.e., a Vornoi vertex)
667 facet->visitid= Voronoi vertex index (same as 'o' format)
668 else
669 facet->visitid= 0
670
671 if printvridge,
672 calls printvridge( fp, vertex, vertexA, centers)
673 [see qh_eachvoronoi]
674
675 notes:
676 Not used for qhull.exe
677 same effect as qh_printvdiagram but ridges not sorted by point id
678 */
679 int qh_eachvoronoi_all (FILE *fp, printvridgeT printvridge, boolT isupper, qh_RIDGE innerouter, boolT inorder) {
680 facetT *facet;
681 vertexT *vertex;
682 int numcenters= 1; /* vertex 0 is vertex-at-infinity */
683 int totridges= 0;
684
685 qh_clearcenters (qh_ASvoronoi);
686 qh_vertexneighbors();
687 maximize_(qh visit_id, (unsigned) qh num_facets);
688 FORALLfacets {
689 facet->visitid= 0;
690 facet->seen= False;
691 facet->seen2= True;
692 }
693 FORALLfacets {
694 if (facet->upperdelaunay == isupper)
695 facet->visitid= numcenters++;
696 }
697 FORALLvertices
698 vertex->seen= False;
699 FORALLvertices {
700 if (qh GOODvertex > 0 && qh_pointid(vertex->point)+1 != qh GOODvertex)
701 continue;
702 totridges += qh_eachvoronoi (fp, printvridge, vertex,
703 !qh_ALL, innerouter, inorder);
704 }
705 return totridges;
706 } /* eachvoronoi_all */
707
708 /*-<a href="qh-io.htm#TOC"
709 >-------------------------------</a><a name="facet2point">-</a>
710
711 qh_facet2point( facet, point0, point1, mindist )
712 return two projected temporary vertices for a 2-d facet
713 may be non-simplicial
714
715 returns:
716 point0 and point1 oriented and projected to the facet
717 returns mindist (maximum distance below plane)
718 */
719 void qh_facet2point(facetT *facet, pointT **point0, pointT **point1, realT *mindist) {
720 vertexT *vertex0, *vertex1;
721 realT dist;
722
723 if (facet->toporient ^ qh_ORIENTclock) {
724 vertex0= SETfirstt_(facet->vertices, vertexT);
725 vertex1= SETsecondt_(facet->vertices, vertexT);
726 }else {
727 vertex1= SETfirstt_(facet->vertices, vertexT);
728 vertex0= SETsecondt_(facet->vertices, vertexT);
729 }
730 zadd_(Zdistio, 2);
731 qh_distplane(vertex0->point, facet, &dist);
732 *mindist= dist;
733 *point0= qh_projectpoint(vertex0->point, facet, dist);
734 qh_distplane(vertex1->point, facet, &dist);
735 minimize_(*mindist, dist);
736 *point1= qh_projectpoint(vertex1->point, facet, dist);
737 } /* facet2point */
738
739
740 /*-<a href="qh-io.htm#TOC"
741 >-------------------------------</a><a name="facetvertices">-</a>
742
743 qh_facetvertices( facetlist, facets, allfacets )
744 returns temporary set of vertices in a set and/or list of facets
745 if allfacets, ignores qh_skipfacet()
746
747 returns:
748 vertices with qh.vertex_visit
749
750 notes:
751 optimized for allfacets of facet_list
752
753 design:
754 if allfacets of facet_list
755 create vertex set from vertex_list
756 else
757 for each selected facet in facets or facetlist
758 append unvisited vertices to vertex set
759 */
760 setT *qh_facetvertices (facetT *facetlist, setT *facets, boolT allfacets) {
761 setT *vertices;
762 facetT *facet, **facetp;
763 vertexT *vertex, **vertexp;
764
765 qh vertex_visit++;
766 if (facetlist == qh facet_list && allfacets && !facets) {
767 vertices= qh_settemp (qh num_vertices);
768 FORALLvertices {
769 vertex->visitid= qh vertex_visit;
770 qh_setappend (&vertices, vertex);
771 }
772 }else {
773 vertices= qh_settemp (qh TEMPsize);
774 FORALLfacet_(facetlist) {
775 if (!allfacets && qh_skipfacet (facet))
776 continue;
777 FOREACHvertex_(facet->vertices) {
778 if (vertex->visitid != qh vertex_visit) {
779 vertex->visitid= qh vertex_visit;
780 qh_setappend (&vertices, vertex);
781 }
782 }
783 }
784 }
785 FOREACHfacet_(facets) {
786 if (!allfacets && qh_skipfacet (facet))
787 continue;
788 FOREACHvertex_(facet->vertices) {
789 if (vertex->visitid != qh vertex_visit) {
790 vertex->visitid= qh vertex_visit;
791 qh_setappend (&vertices, vertex);
792 }
793 }
794 }
795 return vertices;
796 } /* facetvertices */
797
798 /*-<a href="qh-geom.htm#TOC"
799 >-------------------------------</a><a name="geomplanes">-</a>
800
801 qh_geomplanes( facet, outerplane, innerplane )
802 return outer and inner planes for Geomview
803 qh.PRINTradius is size of vertices and points (includes qh.JOGGLEmax)
804
805 notes:
806 assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
807 */
808 void qh_geomplanes (facetT *facet, realT *outerplane, realT *innerplane) {
809 realT radius;
810
811 if (qh MERGING || qh JOGGLEmax < REALmax/2) {
812 qh_outerinner (facet, outerplane, innerplane);
813 radius= qh PRINTradius;
814 if (qh JOGGLEmax < REALmax/2)
815 radius -= qh JOGGLEmax * sqrt (qh hull_dim); /* already accounted for in qh_outerinner() */
816 *outerplane += radius;
817 *innerplane -= radius;
818 if (qh PRINTcoplanar || qh PRINTspheres) {
819 *outerplane += qh MAXabs_coord * qh_GEOMepsilon;
820 *innerplane -= qh MAXabs_coord * qh_GEOMepsilon;
821 }
822 }else
823 *innerplane= *outerplane= 0;
824 } /* geomplanes */
825
826
827 /*-<a href="qh-io.htm#TOC"
828 >-------------------------------</a><a name="markkeep">-</a>
829
830 qh_markkeep( facetlist )
831 mark good facets that meet qh.KEEParea, qh.KEEPmerge, and qh.KEEPminArea
832 ignores visible facets (not part of convex hull)
833
834 returns:
835 may clear facet->good
836 recomputes qh.num_good
837
838 design:
839 get set of good facets
840 if qh.KEEParea
841 sort facets by area
842 clear facet->good for all but n largest facets
843 if qh.KEEPmerge
844 sort facets by merge count
845 clear facet->good for all but n most merged facets
846 if qh.KEEPminarea
847 clear facet->good if area too small
848 update qh.num_good
849 */
850 void qh_markkeep (facetT *facetlist) {
851 facetT *facet, **facetp;
852 setT *facets= qh_settemp (qh num_facets);
853 int size, count;
854
855 trace2((qh ferr, "qh_markkeep: only keep %d largest and/or %d most merged facets and/or min area %.2g\n", qh KEEParea, qh KEEPmerge, qh KEEPminArea));
856 FORALLfacet_(facetlist) {
857 if (!facet->visible && facet->good)
858 qh_setappend (&facets, facet);
859 }
860 size= qh_setsize (facets);
861 if (qh KEEParea) {
862 qsort (SETaddr_(facets, facetT), size,
863 sizeof (facetT *), qh_compare_facetarea);
864 if ((count= size - qh KEEParea) > 0) {
865 FOREACHfacet_(facets) {
866 facet->good= False;
867 if (--count == 0)
868 break;
869 }
870 }
871 }
872 if (qh KEEPmerge) {
873 qsort (SETaddr_(facets, facetT), size,
874 sizeof (facetT *), qh_compare_facetmerge);
875 if ((count= size - qh KEEPmerge) > 0) {
876 FOREACHfacet_(facets) {
877 facet->good= False;
878 if (--count == 0)
879 break;
880 }
881 }
882 }
883 if (qh KEEPminArea < REALmax/2) {
884 FOREACHfacet_(facets) {
885 if (!facet->isarea || facet->f.area < qh KEEPminArea)
886 facet->good= False;
887 }
888 }
889 qh_settempfree (&facets);
890 count= 0;
891 FORALLfacet_(facetlist) {
892 if (facet->good)
893 count++;
894 }
895 qh num_good= count;
896 } /* markkeep */
897
898
899 /*-<a href="qh-io.htm#TOC"
900 >-------------------------------</a><a name="markvoronoi">-</a>
901
902 qh_markvoronoi( facetlist, facets, printall, islower, numcenters )
903 mark voronoi vertices for printing by site pairs
904
905 returns:
906 temporary set of vertices indexed by pointid
907 islower set if printing lower hull (i.e., at least one facet is lower hull)
908 numcenters= total number of Voronoi vertices
909 bumps qh.printoutnum for vertex-at-infinity
910 clears all facet->seen and sets facet->seen2
911
912 if selected
913 facet->visitid= Voronoi vertex id
914 else if upper hull (or 'Qu' and lower hull)
915 facet->visitid= 0
916 else
917 facet->visitid >= qh num_facets
918
919 notes:
920 ignores qh.ATinfinity, if defined
921 */
922 setT *qh_markvoronoi (facetT *facetlist, setT *facets, boolT printall, boolT *islowerp, int *numcentersp) {
923 int numcenters=0;
924 facetT *facet, **facetp;
925 setT *vertices;
926 boolT islower= False;
927
928 qh printoutnum++;
929 qh_clearcenters (qh_ASvoronoi); /* in case, qh_printvdiagram2 called by user */
930 qh_vertexneighbors();
931 vertices= qh_pointvertex();
932 if (qh ATinfinity)
933 SETelem_(vertices, qh num_points-1)= NULL;
934 qh visit_id++;
935 maximize_(qh visit_id, (unsigned) qh num_facets);
936 FORALLfacet_(facetlist) {
937 if (printall || !qh_skipfacet (facet)) {
938 if (!facet->upperdelaunay) {
939 islower= True;
940 break;
941 }
942 }
943 }
944 FOREACHfacet_(facets) {
945 if (printall || !qh_skipfacet (facet)) {
946 if (!facet->upperdelaunay) {
947 islower= True;
948 break;
949 }
950 }
951 }
952 FORALLfacets {
953 if (facet->normal && (facet->upperdelaunay == islower))
954 facet->visitid= 0; /* facetlist or facets may overwrite */
955 else
956 facet->visitid= qh visit_id;
957 facet->seen= False;
958 facet->seen2= True;
959 }
960 numcenters++; /* qh_INFINITE */
961 FORALLfacet_(facetlist) {
962 if (printall || !qh_skipfacet (facet))
963 facet->visitid= numcenters++;
964 }
965 FOREACHfacet_(facets) {
966 if (printall || !qh_skipfacet (facet))
967 facet->visitid= numcenters++;
968 }
969 *islowerp= islower;
970 *numcentersp= numcenters;
971 trace2((qh ferr, "qh_markvoronoi: islower %d numcenters %d\n", islower, numcenters));
972 return vertices;
973 } /* markvoronoi */
974
975 /*-<a href="qh-io.htm#TOC"
976 >-------------------------------</a><a name="order_vertexneighbors">-</a>
977
978 qh_order_vertexneighbors( vertex )
979 order facet neighbors of a 2-d or 3-d vertex by adjacency
980
981 notes:
982 does not orient the neighbors
983
984 design:
985 initialize a new neighbor set with the first facet in vertex->neighbors
986 while vertex->neighbors non-empty
987 select next neighbor in the previous facet's neighbor set
988 set vertex->neighbors to the new neighbor set
989 */
990 void qh_order_vertexneighbors(vertexT *vertex) {
991 setT *newset;
992 facetT *facet, *neighbor, **neighborp;
993
994 trace4((qh ferr, "qh_order_vertexneighbors: order neighbors of v%d for 3-d\n", vertex->id));
995 newset= qh_settemp (qh_setsize (vertex->neighbors));
996 facet= (facetT*)qh_setdellast (vertex->neighbors);
997 qh_setappend (&newset, facet);
998 while (qh_setsize (vertex->neighbors)) {
999 FOREACHneighbor_(vertex) {
1000 if (qh_setin (facet->neighbors, neighbor)) {
1001 qh_setdel(vertex->neighbors, neighbor);
1002 qh_setappend (&newset, neighbor);
1003 facet= neighbor;
1004 break;
1005 }
1006 }
1007 if (!neighbor) {
1008 fprintf (qh ferr, "qhull internal error (qh_order_vertexneighbors): no neighbor of v%d for f%d\n",
1009 vertex->id, facet->id);
1010 qh_errexit (qh_ERRqhull, facet, NULL);
1011 }
1012 }
1013 qh_setfree (&vertex->neighbors);
1014 qh_settemppop ();
1015 vertex->neighbors= newset;
1016 } /* order_vertexneighbors */
1017
1018 /*-<a href="qh-io.htm#TOC"
1019 >-------------------------------</a><a name="printafacet">-</a>
1020
1021 qh_printafacet( fp, format, facet, printall )
1022 print facet to fp in given output format (see qh.PRINTout)
1023
1024 returns:
1025 nop if !printall and qh_skipfacet()
1026 nop if visible facet and NEWfacets and format != PRINTfacets
1027 must match qh_countfacets
1028
1029 notes
1030 preserves qh.visit_id
1031 facet->normal may be null if PREmerge/MERGEexact and STOPcone before merge
1032
1033 see
1034 qh_printbegin() and qh_printend()
1035
1036 design:
1037 test for printing facet
1038 call appropriate routine for format
1039 or output results directly
1040 */
1041 void qh_printafacet(FILE *fp, int format, facetT *facet, boolT printall) {
1042 realT color[4], offset, dist, outerplane, innerplane;
1043 boolT zerodiv;
1044 coordT *point, *normp, *coordp, **pointp, *feasiblep;
1045 int k;
1046 vertexT *vertex, **vertexp;
1047 facetT *neighbor, **neighborp;
1048
1049 if (!printall && qh_skipfacet (facet))
1050 return;
1051 if (facet->visible && qh NEWfacets && format != qh_PRINTfacets)
1052 return;
1053 qh printoutnum++;
1054 switch (format) {
1055 case qh_PRINTarea:
1056 if (facet->isarea) {
1057 fprintf (fp, qh_REAL_1, facet->f.area);
1058 fprintf (fp, "\n");
1059 }else
1060 fprintf (fp, "0\n");
1061 break;
1062 case qh_PRINTcoplanars:
1063 fprintf (fp, "%d", qh_setsize (facet->coplanarset));
1064 FOREACHpoint_(facet->coplanarset)
1065 fprintf (fp, " %d", qh_pointid (point));
1066 fprintf (fp, "\n");
1067 break;
1068 case qh_PRINTcentrums:
1069 qh_printcenter (fp, format, NULL, facet);
1070 break;
1071 case qh_PRINTfacets:
1072 qh_printfacet (fp, facet);
1073 break;
1074 case qh_PRINTfacets_xridge:
1075 qh_printfacetheader (fp, facet);
1076 break;
1077 case qh_PRINTgeom: /* either 2 , 3, or 4-d by qh_printbegin */
1078 if (!facet->normal)
1079 break;
1080 for (k= qh hull_dim; k--; ) {
1081 color[k]= (facet->normal[k]+1.0)/2.0;
1082 maximize_(color[k], -1.0);
1083 minimize_(color[k], +1.0);
1084 }
1085 qh_projectdim3 (color, color);
1086 if (qh PRINTdim != qh hull_dim)
1087 qh_normalize2 (color, 3, True, NULL, NULL);
1088 if (qh hull_dim <= 2)
1089 qh_printfacet2geom (fp, facet, color);
1090 else if (qh hull_dim == 3) {
1091 if (facet->simplicial)
1092 qh_printfacet3geom_simplicial (fp, facet, color);
1093 else
1094 qh_printfacet3geom_nonsimplicial (fp, facet, color);
1095 }else {
1096 if (facet->simplicial)
1097 qh_printfacet4geom_simplicial (fp, facet, color);
1098 else
1099 qh_printfacet4geom_nonsimplicial (fp, facet, color);
1100 }
1101 break;
1102 case qh_PRINTids:
1103 fprintf (fp, "%d\n", facet->id);
1104 break;
1105 case qh_PRINTincidences:
1106 case qh_PRINToff:
1107 case qh_PRINTtriangles:
1108 if (qh hull_dim == 3 && format != qh_PRINTtriangles)
1109 qh_printfacet3vertex (fp, facet, format);
1110 else if (facet->simplicial || qh hull_dim == 2 || format == qh_PRINToff)
1111 qh_printfacetNvertex_simplicial (fp, facet, format);
1112 else
1113 qh_printfacetNvertex_nonsimplicial (fp, facet, qh printoutvar++, format);
1114 break;
1115 case qh_PRINTinner:
1116 qh_outerinner (facet, NULL, &innerplane);
1117 offset= facet->offset - innerplane;
1118 goto LABELprintnorm;
1119 break; /* prevent warning */
1120 case qh_PRINTmerges:
1121 fprintf (fp, "%d\n", facet->nummerge);
1122 break;
1123 case qh_PRINTnormals:
1124 offset= facet->offset;
1125 goto LABELprintnorm;
1126 break; /* prevent warning */
1127 case qh_PRINTouter:
1128 qh_outerinner (facet, &outerplane, NULL);
1129 offset= facet->offset - outerplane;
1130 LABELprintnorm:
1131 if (!facet->normal) {
1132 fprintf (fp, "no normal for facet f%d\n", facet->id);
1133 break;
1134 }
1135 if (qh CDDoutput) {
1136 fprintf (fp, qh_REAL_1, -offset);
1137 for (k=0; k < qh hull_dim; k++)
1138 fprintf (fp, qh_REAL_1, -facet->normal[k]);
1139 }else {
1140 for (k=0; k < qh hull_dim; k++)
1141 fprintf (fp, qh_REAL_1, facet->normal[k]);
1142 fprintf (fp, qh_REAL_1, offset);
1143 }
1144 fprintf (fp, "\n");
1145 break;
1146 case qh_PRINTmathematica: /* either 2 or 3-d by qh_printbegin */
1147 case qh_PRINTmaple:
1148 if (qh hull_dim == 2)
1149 qh_printfacet2math (fp, facet, format, qh printoutvar++);
1150 else
1151 qh_printfacet3math (fp, facet, format, qh printoutvar++);
1152 break;
1153 case qh_PRINTneighbors:
1154 fprintf (fp, "%d", qh_setsize (facet->neighbors));
1155 FOREACHneighbor_(facet)
1156 fprintf (fp, " %d",
1157 neighbor->visitid ? neighbor->visitid - 1: - neighbor->id);
1158 fprintf (fp, "\n");
1159 break;
1160 case qh_PRINTpointintersect:
1161 if (!qh feasible_point) {
1162 fprintf (fp, "qhull input error (qh_printafacet): option 'Fp' needs qh feasible_point\n");
1163 qh_errexit( qh_ERRinput, NULL, NULL);
1164 }
1165 if (facet->offset > 0)
1166 goto LABELprintinfinite;
1167 point= coordp= (coordT*)qh_memalloc (qh normal_size);
1168 normp= facet->normal;
1169 feasiblep= qh feasible_point;
1170 if (facet->offset < -qh MINdenom) {
1171 for (k= qh hull_dim; k--; )
1172 *(coordp++)= (*(normp++) / - facet->offset) + *(feasiblep++);
1173 }else {
1174 for (k= qh hull_dim; k--; ) {
1175 *(coordp++)= qh_divzero (*(normp++), facet->offset, qh MINdenom_1,
1176 &zerodiv) + *(feasiblep++);
1177 if (zerodiv) {
1178 qh_memfree (point, qh normal_size);
1179 goto LABELprintinfinite;
1180 }
1181 }
1182 }
1183 qh_printpoint (fp, NULL, point);
1184 qh_memfree (point, qh normal_size);
1185 break;
1186 LABELprintinfinite:
1187 for (k= qh hull_dim; k--; )
1188 fprintf (fp, qh_REAL_1, qh_INFINITE);
1189 fprintf (fp, "\n");
1190 break;
1191 case qh_PRINTpointnearest:
1192 FOREACHpoint_(facet->coplanarset) {
1193 int id, id2;
1194 vertex= qh_nearvertex (facet, point, &dist);
1195 id= qh_pointid (vertex->point);
1196 id2= qh_pointid (point);
1197 fprintf (fp, "%d %d %d " qh_REAL_1 "\n", id, id2, facet->id, dist);
1198 }
1199 break;
1200 case qh_PRINTpoints: /* VORONOI only by qh_printbegin */
1201 if (qh CDDoutput)
1202 fprintf (fp, "1 ");
1203 qh_printcenter (fp, format, NULL, facet);
1204 break;
1205 case qh_PRINTvertices:
1206 fprintf (fp, "%d", qh_setsize (facet->vertices));
1207 FOREACHvertex_(facet->vertices)
1208 fprintf (fp, " %d", qh_pointid (vertex->point));
1209 fprintf (fp, "\n");
1210 break;
1211 }
1212 } /* printafacet */
1213
1214 /*-<a href="qh-io.htm#TOC"
1215 >-------------------------------</a><a name="printbegin">-</a>
1216
1217 qh_printbegin( )
1218 prints header for all output formats
1219
1220 returns:
1221 checks for valid format
1222
1223 notes:
1224 uses qh.visit_id for 3/4off
1225 changes qh.interior_point if printing centrums
1226 qh_countfacets clears facet->visitid for non-good facets
1227
1228 see
1229 qh_printend() and qh_printafacet()
1230
1231 design:
1232 count facets and related statistics
1233 print header for format
1234 */
1235 void qh_printbegin (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
1236 int numfacets, numsimplicial, numridges, totneighbors, numcoplanars, numtricoplanars;
1237 int i, num;
1238 facetT *facet, **facetp;
1239 vertexT *vertex, **vertexp;
1240 setT *vertices;
1241 pointT *point, **pointp, *pointtemp;
1242
1243 qh printoutnum= 0;
1244 qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial,
1245 &totneighbors, &numridges, &numcoplanars, &numtricoplanars);
1246 switch (format) {
1247 case qh_PRINTnone:
1248 break;
1249 case qh_PRINTarea:
1250 fprintf (fp, "%d\n", numfacets);
1251 break;
1252 case qh_PRINTcoplanars:
1253 fprintf (fp, "%d\n", numfacets);
1254 break;
1255 case qh_PRINTcentrums:
1256 if (qh CENTERtype == qh_ASnone)
1257 qh_clearcenters (qh_AScentrum);
1258 fprintf (fp, "%d\n%d\n", qh hull_dim, numfacets);
1259 break;
1260 case qh_PRINTfacets:
1261 case qh_PRINTfacets_xridge:
1262 if (facetlist)
1263 qh_printvertexlist (fp, "Vertices and facets:\n", facetlist, facets, printall);
1264 break;
1265 case qh_PRINTgeom:
1266 if (qh hull_dim > 4) /* qh_initqhull_globals also checks */
1267 goto LABELnoformat;
1268 if (qh VORONOI && qh hull_dim > 3) /* PRINTdim == DROPdim == hull_dim-1 */
1269 goto LABELnoformat;
1270 if (qh hull_dim == 2 && (qh PRINTridges || qh DOintersections))
1271 fprintf (qh ferr, "qhull warning: output for ridges and intersections not implemented in 2-d\n");
1272 if (qh hull_dim == 4 && (qh PRINTinner || qh PRINTouter ||
1273 (qh PRINTdim == 4 && qh PRINTcentrums)))
1274 fprintf (qh ferr, "qhull warning: output for outer/inner planes and centrums not implemented in 4-d\n");
1275 if (qh PRINTdim == 4 && (qh PRINTspheres))
1276 fprintf (qh ferr, "qhull warning: output for vertices not implemented in 4-d\n");
1277 if (qh PRINTdim == 4 && qh DOintersections && qh PRINTnoplanes)
1278 fprintf (qh ferr, "qhull warning: 'Gnh' generates no output in 4-d\n");
1279 if (qh PRINTdim == 2) {
1280 fprintf(fp, "{appearance {linewidth 3} LIST # %s | %s\n",
1281 qh rbox_command, qh qhull_command);
1282 }else if (qh PRINTdim == 3) {
1283 fprintf(fp, "{appearance {+edge -evert linewidth 2} LIST # %s | %s\n",
1284 qh rbox_command, qh qhull_command);
1285 }else if (qh PRINTdim == 4) {
1286 qh visit_id++;
1287 num= 0;
1288 FORALLfacet_(facetlist) /* get number of ridges to be printed */
1289 qh_printend4geom (NULL, facet, &num, printall);
1290 FOREACHfacet_(facets)
1291 qh_printend4geom (NULL, facet, &num, printall);
1292 qh ridgeoutnum= num;
1293 qh printoutvar= 0; /* counts number of ridges in output */
1294 fprintf (fp, "LIST # %s | %s\n", qh rbox_command, qh qhull_command);
1295 }
1296 if (qh PRINTdots) {
1297 qh printoutnum++;
1298 num= qh num_points + qh_setsize (qh other_points);
1299 if (qh DELAUNAY && qh ATinfinity)
1300 num--;
1301 if (qh PRINTdim == 4)
1302 fprintf (fp, "4VECT %d %d 1\n", num, num);
1303 else
1304 fprintf (fp, "VECT %d %d 1\n", num, num);
1305 for (i= num; i--; ) {
1306 if (i % 20 == 0)
1307 fprintf (fp, "\n");
1308 fprintf (fp, "1 ");
1309 }
1310 fprintf (fp, "# 1 point per line\n1 ");
1311 for (i= num-1; i--; ) {
1312 if (i % 20 == 0)
1313 fprintf (fp, "\n");
1314 fprintf (fp, "0 ");
1315 }
1316 fprintf (fp, "# 1 color for all\n");
1317 FORALLpoints {
1318 if (!qh DELAUNAY || !qh ATinfinity || qh_pointid(point) != qh num_points-1) {
1319 if (qh PRINTdim == 4)
1320 qh_printpoint (fp, NULL, point);
1321 else
1322 qh_printpoint3 (fp, point);
1323 }
1324 }
1325 FOREACHpoint_(qh other_points) {
1326 if (qh PRINTdim == 4)
1327 qh_printpoint (fp, NULL, point);
1328 else
1329 qh_printpoint3 (fp, point);
1330 }
1331 fprintf (fp, "0 1 1 1 # color of points\n");
1332 }
1333 if (qh PRINTdim == 4 && !qh PRINTnoplanes)
1334 /* 4dview loads up multiple 4OFF objects slowly */
1335 fprintf(fp, "4OFF %d %d 1\n", 3*qh ridgeoutnum, qh ridgeoutnum);
1336 qh PRINTcradius= 2 * qh DISTround; /* include test DISTround */
1337 if (qh PREmerge) {
1338 maximize_(qh PRINTcradius, qh premerge_centrum + qh DISTround);
1339 }else if (qh POSTmerge)
1340 maximize_(qh PRINTcradius, qh postmerge_centrum + qh DISTround);
1341 qh PRINTradius= qh PRINTcradius;
1342 if (qh PRINTspheres + qh PRINTcoplanar)
1343 maximize_(qh PRINTradius, qh MAXabs_coord * qh_MINradius);
1344 if (qh premerge_cos < REALmax/2) {
1345 maximize_(qh PRINTradius, (1- qh premerge_cos) * qh MAXabs_coord);
1346 }else if (!qh PREmerge && qh POSTmerge && qh postmerge_cos < REALmax/2) {
1347 maximize_(qh PRINTradius, (1- qh postmerge_cos) * qh MAXabs_coord);
1348 }
1349 maximize_(qh PRINTradius, qh MINvisible);
1350 if (qh JOGGLEmax < REALmax/2)
1351 qh PRINTradius += qh JOGGLEmax * sqrt (qh hull_dim);
1352 if (qh PRINTdim != 4 &&
1353 (qh PRINTcoplanar || qh PRINTspheres || qh PRINTcentrums)) {
1354 vertices= qh_facetvertices (facetlist, facets, printall);
1355 if (qh PRINTspheres && qh PRINTdim <= 3)
1356 qh_printspheres (fp, vertices, qh PRINTradius);
1357 if (qh PRINTcoplanar || qh PRINTcentrums) {
1358 qh firstcentrum= True;
1359 if (qh PRINTcoplanar&& !qh PRINTspheres) {
1360 FOREACHvertex_(vertices)
1361 qh_printpointvect2 (fp, vertex->point, NULL,
1362 qh interior_point, qh PRINTradius);
1363 }
1364 FORALLfacet_(facetlist) {
1365 if (!printall && qh_skipfacet(facet))
1366 continue;
1367 if (!facet->normal)
1368 continue;
1369 if (qh PRINTcentrums && qh PRINTdim <= 3)
1370 qh_printcentrum (fp, facet, qh PRINTcradius);
1371 if (!qh PRINTcoplanar)
1372 continue;
1373 FOREACHpoint_(facet->coplanarset)
1374 qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
1375 FOREACHpoint_(facet->outsideset)
1376 qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
1377 }
1378 FOREACHfacet_(facets) {
1379 if (!printall && qh_skipfacet(facet))
1380 continue;
1381 if (!facet->normal)
1382 continue;
1383 if (qh PRINTcentrums && qh PRINTdim <= 3)
1384 qh_printcentrum (fp, facet, qh PRINTcradius);
1385 if (!qh PRINTcoplanar)
1386 continue;
1387 FOREACHpoint_(facet->coplanarset)
1388 qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
1389 FOREACHpoint_(facet->outsideset)
1390 qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
1391 }
1392 }
1393 qh_settempfree (&vertices);
1394 }
1395 qh visit_id++; /* for printing hyperplane intersections */
1396 break;
1397 case qh_PRINTids:
1398 fprintf (fp, "%d\n", numfacets);
1399 break;
1400 case qh_PRINTincidences:
1401 if (qh VORONOI && qh PRINTprecision)
1402 fprintf (qh ferr, "qhull warning: writing Delaunay. Use 'p' or 'o' for Voronoi centers\n");
1403 qh printoutvar= qh vertex_id; /* centrum id for non-simplicial facets */
1404 if (qh hull_dim <= 3)
1405 fprintf(fp, "%d\n", numfacets);
1406 else
1407 fprintf(fp, "%d\n", numsimplicial+numridges);
1408 break;
1409 case qh_PRINTinner:
1410 case qh_PRINTnormals:
1411 case qh_PRINTouter:
1412 if (qh CDDoutput)
1413 fprintf (fp, "%s | %s\nbegin\n %d %d real\n", qh rbox_command,
1414 qh qhull_command, numfacets, qh hull_dim+1);
1415 else
1416 fprintf (fp, "%d\n%d\n", qh hull_dim+1, numfacets);
1417 break;
1418 case qh_PRINTmathematica:
1419 case qh_PRINTmaple:
1420 if (qh hull_dim > 3) /* qh_initbuffers also checks */
1421 goto LABELnoformat;
1422 if (qh VORONOI)
1423 fprintf (qh ferr, "qhull warning: output is the Delaunay triangulation\n");
1424 if (format == qh_PRINTmaple) {
1425 if (qh hull_dim == 2)
1426 fprintf(fp, "PLOT(CURVES(\n");
1427 else
1428 fprintf(fp, "PLOT3D(POLYGONS(\n");
1429 }else
1430 fprintf(fp, "{\n");
1431 qh printoutvar= 0; /* counts number of facets for notfirst */
1432 break;
1433 case qh_PRINTmerges:
1434 fprintf (fp, "%d\n", numfacets);
1435 break;
1436 case qh_PRINTpointintersect:
1437 fprintf (fp, "%d\n%d\n", qh hull_dim, numfacets);
1438 break;
1439 case qh_PRINTneighbors:
1440 fprintf (fp, "%d\n", numfacets);
1441 break;
1442 case qh_PRINToff:
1443 case qh_PRINTtriangles:
1444 if (qh VORONOI)
1445 goto LABELnoformat;
1446 num = qh hull_dim;
1447 if (format == qh_PRINToff || qh hull_dim == 2)
1448 fprintf (fp, "%d\n%d %d %d\n", num,
1449 qh num_points+qh_setsize (qh other_points), numfacets, totneighbors/2);
1450 else { /* qh_PRINTtriangles */
1451 qh printoutvar= qh num_points+qh_setsize (qh other_points); /* first centrum */
1452 if (qh DELAUNAY)
1453 num--; /* drop last dimension */
1454 fprintf (fp, "%d\n%d %d %d\n", num, qh printoutvar
1455 + numfacets - numsimplicial, numsimplicial + numridges, totneighbors/2);
1456 }
1457 FORALLpoints
1458 qh_printpointid (qh fout, NULL, num, point, -1);
1459 FOREACHpoint_(qh other_points)
1460 qh_printpointid (qh fout, NULL, num, point, -1);
1461 if (format == qh_PRINTtriangles && qh hull_dim > 2) {
1462 FORALLfacets {
1463 if (!facet->simplicial && facet->visitid)
1464 qh_printcenter (qh fout, format, NULL, facet);
1465 }
1466 }
1467 break;
1468 case qh_PRINTpointnearest:
1469 fprintf (fp, "%d\n", numcoplanars);
1470 break;
1471 case qh_PRINTpoints:
1472 if (!qh VORONOI)
1473 goto LABELnoformat;
1474 if (qh CDDoutput)
1475 fprintf (fp, "%s | %s\nbegin\n%d %d real\n", qh rbox_command,
1476 qh qhull_command, numfacets, qh hull_dim);
1477 else
1478 fprintf (fp, "%d\n%d\n", qh hull_dim-1, numfacets);
1479 break;
1480 case qh_PRINTvertices:
1481 fprintf (fp, "%d\n", numfacets);
1482 break;
1483 case qh_PRINTsummary:
1484 default:
1485 LABELnoformat:
1486 fprintf (qh ferr, "qhull internal error (qh_printbegin): can not use this format for dimension %d\n",
1487 qh hull_dim);
1488 qh_errexit (qh_ERRqhull, NULL, NULL);
1489 }
1490 } /* printbegin */
1491
1492 /*-<a href="qh-io.htm#TOC"
1493 >-------------------------------</a><a name="printcenter">-</a>
1494
1495 qh_printcenter( fp, string, facet )
1496 print facet->center as centrum or Voronoi center
1497 string may be NULL. Don't include '%' codes.
1498 nop if qh CENTERtype neither CENTERvoronoi nor CENTERcentrum
1499 if upper envelope of Delaunay triangulation and point at-infinity
1500 prints qh_INFINITE instead;
1501
1502 notes:
1503 defines facet->center if needed
1504 if format=PRINTgeom, adds a 0 if would otherwise be 2-d
1505 */
1506 void qh_printcenter (FILE *fp, int format, char *string, facetT *facet) {
1507 int k, num;
1508
1509 if (qh CENTERtype != qh_ASvoronoi && qh CENTERtype != qh_AScentrum)
1510 return;
1511 if (string)
1512 fprintf (fp, string, facet->id);
1513 if (qh CENTERtype == qh_ASvoronoi) {
1514 num= qh hull_dim-1;
1515 if (!facet->normal || !facet->upperdelaunay || !qh ATinfinity) {
1516 if (!facet->center)
1517 facet->center= qh_facetcenter (facet->vertices);
1518 for (k=0; k < num; k++)
1519 fprintf (fp, qh_REAL_1, facet->center[k]);
1520 }else {
1521 for (k=0; k < num; k++)
1522 fprintf (fp, qh_REAL_1, qh_INFINITE);
1523 }
1524 }else /* qh CENTERtype == qh_AScentrum */ {
1525 num= qh hull_dim;
1526 if (format == qh_PRINTtriangles && qh DELAUNAY)
1527 num--;
1528 if (!facet->center)
1529 facet->center= qh_getcentrum (facet);
1530 for (k=0; k < num; k++)
1531 fprintf (fp, qh_REAL_1, facet->center[k]);
1532 }
1533 if (format == qh_PRINTgeom && num == 2)
1534 fprintf (fp, " 0\n");
1535 else
1536 fprintf (fp, "\n");
1537 } /* printcenter */
1538
1539 /*-<a href="qh-io.htm#TOC"
1540 >-------------------------------</a><a name="printcentrum">-</a>
1541
1542 qh_printcentrum( fp, facet, radius )
1543 print centrum for a facet in OOGL format
1544 radius defines size of centrum
1545 2-d or 3-d only
1546
1547 returns:
1548 defines facet->center if needed
1549 */
1550 void qh_printcentrum (FILE *fp, facetT *facet, realT radius) {
1551 pointT *centrum, *projpt;
1552 boolT tempcentrum= False;
1553 realT xaxis[4], yaxis[4], normal[4], dist;
1554 realT green[3]={0, 1, 0};
1555 vertexT *apex;
1556 int k;
1557
1558 if (qh CENTERtype == qh_AScentrum) {
1559 if (!facet->center)
1560 facet->center= qh_getcentrum (facet);
1561 centrum= facet->center;
1562 }else {
1563 centrum= qh_getcentrum (facet);
1564 tempcentrum= True;
1565 }
1566 fprintf (fp, "{appearance {-normal -edge normscale 0} ");
1567 if (qh firstcentrum) {
1568 qh firstcentrum= False;
1569 fprintf (fp, "{INST geom { define centrum CQUAD # f%d\n\
1570 -0.3 -0.3 0.0001 0 0 1 1\n\
1571 0.3 -0.3 0.0001 0 0 1 1\n\
1572 0.3 0.3 0.0001 0 0 1 1\n\
1573 -0.3 0.3 0.0001 0 0 1 1 } transform { \n", facet->id);
1574 }else
1575 fprintf (fp, "{INST geom { : centrum } transform { # f%d\n", facet->id);
1576 apex= SETfirstt_(facet->vertices, vertexT);
1577 qh_distplane(apex->point, facet, &dist);
1578 projpt= qh_projectpoint(apex->point, facet, dist);
1579 for (k= qh hull_dim; k--; ) {
1580 xaxis[k]= projpt[k] - centrum[k];
1581 normal[k]= facet->normal[k];
1582 }
1583 if (qh hull_dim == 2) {
1584 xaxis[2]= 0;
1585 normal[2]= 0;
1586 }else if (qh hull_dim == 4) {
1587 qh_projectdim3 (xaxis, xaxis);
1588 qh_projectdim3 (normal, normal);
1589 qh_normalize2 (normal, qh PRINTdim, True, NULL, NULL);
1590 }
1591 qh_crossproduct (3, xaxis, normal, yaxis);
1592 fprintf (fp, "%8.4g %8.4g %8.4g 0\n", xaxis[0], xaxis[1], xaxis[2]);
1593 fprintf (fp, "%8.4g %8.4g %8.4g 0\n", yaxis[0], yaxis[1], yaxis[2]);
1594 fprintf (fp, "%8.4g %8.4g %8.4g 0\n", normal[0], normal[1], normal[2]);
1595 qh_printpoint3 (fp, centrum);
1596 fprintf (fp, "1 }}}\n");
1597 qh_memfree (projpt, qh normal_size);
1598 qh_printpointvect (fp, centrum, facet->normal, NULL, radius, green);
1599 if (tempcentrum)
1600 qh_memfree (centrum, qh normal_size);
1601 } /* printcentrum */
1602
1603 /*-<a href="qh-io.htm#TOC"
1604 >-------------------------------</a><a name="printend">-</a>
1605
1606 qh_printend( fp, format )
1607 prints trailer for all output formats
1608
1609 see:
1610 qh_printbegin() and qh_printafacet()
1611
1612 */
1613 void qh_printend (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
1614 int num;
1615 facetT *facet, **facetp;
1616
1617 if (!qh printoutnum)
1618 fprintf (qh ferr, "qhull warning: no facets printed\n");
1619 switch (format) {
1620 case qh_PRINTgeom:
1621 if (qh hull_dim == 4 && qh DROPdim < 0 && !qh PRINTnoplanes) {
1622 qh visit_id++;
1623 num= 0;
1624 FORALLfacet_(facetlist)
1625 qh_printend4geom (fp, facet,&num, printall);
1626 FOREACHfacet_(facets)
1627 qh_printend4geom (fp, facet, &num, printall);
1628 if (num != qh ridgeoutnum || qh printoutvar != qh ridgeoutnum) {
1629 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);
1630 qh_errexit (qh_ERRqhull, NULL, NULL);
1631 }
1632 }else
1633 fprintf(fp, "}\n");
1634 break;
1635 case qh_PRINTinner:
1636 case qh_PRINTnormals:
1637 case qh_PRINTouter:
1638 if (qh CDDoutput)
1639 fprintf (fp, "end\n");
1640 break;
1641 case qh_PRINTmaple:
1642 fprintf(fp, "));\n");
1643 break;
1644 case qh_PRINTmathematica:
1645 fprintf(fp, "}\n");
1646 break;
1647 case qh_PRINTpoints:
1648 if (qh CDDoutput)
1649 fprintf (fp, "end\n");
1650 break;
1651 }
1652 } /* printend */
1653
1654 /*-<a href="qh-io.htm#TOC"
1655 >-------------------------------</a><a name="printend4geom">-</a>
1656
1657 qh_printend4geom( fp, facet, numridges, printall )
1658 helper function for qh_printbegin/printend
1659
1660 returns:
1661 number of printed ridges
1662
1663 notes:
1664 just counts printed ridges if fp=NULL
1665 uses facet->visitid
1666 must agree with qh_printfacet4geom...
1667
1668 design:
1669 computes color for facet from its normal
1670 prints each ridge of facet
1671 */
1672 void qh_printend4geom (FILE *fp, facetT *facet, int *nump, boolT printall) {
1673 realT color[3];
1674 int i, num= *nump;
1675 facetT *neighbor, **neighborp;
1676 ridgeT *ridge, **ridgep;
1677
1678 if (!printall && qh_skipfacet(facet))
1679 return;
1680 if (qh PRINTnoplanes || (facet->visible && qh NEWfacets))
1681 return;
1682 if (!facet->normal)
1683 return;
1684 if (fp) {
1685 for (i=0; i < 3; i++) {
1686 color[i]= (facet->normal[i]+1.0)/2.0;
1687 maximize_(color[i], -1.0);
1688 minimize_(color[i], +1.0);
1689 }
1690 }
1691 facet->visitid= qh visit_id;
1692 if (facet->simplicial) {
1693 FOREACHneighbor_(facet) {
1694 if (neighbor->visitid != qh visit_id) {
1695 if (fp)
1696 fprintf (fp, "3 %d %d %d %8.4g %8.4g %8.4g 1 # f%d f%d\n",
1697 3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],
1698 facet->id, neighbor->id);
1699 num++;
1700 }
1701 }
1702 }else {
1703 FOREACHridge_(facet->ridges) {
1704 neighbor= otherfacet_(ridge, facet);
1705 if (neighbor->visitid != qh visit_id) {
1706 if (fp)
1707 fprintf (fp, "3 %d %d %d %8.4g %8.4g %8.4g 1 #r%d f%d f%d\n",
1708 3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],
1709 ridge->id, facet->id, neighbor->id);
1710 num++;
1711 }
1712 }
1713 }
1714 *nump= num;
1715 } /* printend4geom */
1716
1717 /*-<a href="qh-io.htm#TOC"
1718 >-------------------------------</a><a name="printextremes">-</a>
1719
1720 qh_printextremes( fp, facetlist, facets, printall )
1721 print extreme points for convex hulls or halfspace intersections
1722
1723 notes:
1724 #points, followed by ids, one per line
1725
1726 sorted by id
1727 same order as qh_printpoints_out if no coplanar/interior points
1728 */
1729 void qh_printextremes (FILE *fp, facetT *facetlist, setT *facets, int printall) {
1730 setT *vertices, *points;
1731 pointT *point;
1732 vertexT *vertex, **vertexp;
1733 int id;
1734 int numpoints=0, point_i, point_n;
1735 int allpoints= qh num_points + qh_setsize (qh other_points);
1736
1737 points= qh_settemp (allpoints);
1738 qh_setzero (points, 0, allpoints);
1739 vertices= qh_facetvertices (facetlist, facets, printall);
1740 FOREACHvertex_(vertices) {
1741 id= qh_pointid (vertex->point);
1742 if (id >= 0) {
1743 SETelem_(points, id)= vertex->point;
1744 numpoints++;
1745 }
1746 }
1747 qh_settempfree (&vertices);
1748 fprintf (fp, "%d\n", numpoints);
1749 FOREACHpoint_i_(points) {
1750 if (point)
1751 fprintf (fp, "%d\n", point_i);
1752 }
1753 qh_settempfree (&points);
1754 } /* printextremes */
1755
1756 /*-<a href="qh-io.htm#TOC"
1757 >-------------------------------</a><a name="printextremes_2d">-</a>
1758
1759 qh_printextremes_2d( fp, facetlist, facets, printall )
1760 prints point ids for facets in qh_ORIENTclock order
1761
1762 notes:
1763 #points, followed by ids, one per line
1764 if facetlist/facets are disjoint than the output includes skips
1765 errors if facets form a loop
1766 does not print coplanar points
1767 */
1768 void qh_printextremes_2d (FILE *fp, facetT *facetlist, setT *facets, int printall) {
1769 int numfacets, numridges, totneighbors, numcoplanars, numsimplicial, numtricoplanars;
1770 setT *vertices;
1771 facetT *facet, *startfacet, *nextfacet;
1772 vertexT *vertexA, *vertexB;
1773
1774 qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial,
1775 &totneighbors, &numridges, &numcoplanars, &numtricoplanars); /* marks qh visit_id */
1776 vertices= qh_facetvertices (facetlist, facets, printall);
1777 fprintf(fp, "%d\n", qh_setsize (vertices));
1778 qh_settempfree (&vertices);
1779 if (!numfacets)
1780 return;
1781 facet= startfacet= facetlist ? facetlist : SETfirstt_(facets, facetT);
1782 qh vertex_visit++;
1783 qh visit_id++;
1784 do {
1785 if (facet->toporient ^ qh_ORIENTclock) {
1786 vertexA= SETfirstt_(facet->vertices, vertexT);
1787 vertexB= SETsecondt_(facet->vertices, vertexT);
1788 nextfacet= SETfirstt_(facet->neighbors, facetT);
1789 }else {
1790 vertexA= SETsecondt_(facet->vertices, vertexT);
1791 vertexB= SETfirstt_(facet->vertices, vertexT);
1792 nextfacet= SETsecondt_(facet->neighbors, facetT);
1793 }
1794 if (facet->visitid == qh visit_id) {
1795 fprintf(qh ferr, "qh_printextremes_2d: loop in facet list. facet %d nextfacet %d\n",
1796 facet->id, nextfacet->id);
1797 qh_errexit2 (qh_ERRqhull, facet, nextfacet);
1798 }
1799 if (facet->visitid) {
1800 if (vertexA->visitid != qh vertex_visit) {
1801 vertexA->visitid= qh vertex_visit;
1802 fprintf(fp, "%d\n", qh_pointid (vertexA->point));
1803 }
1804 if (vertexB->visitid != qh vertex_visit) {
1805 vertexB->visitid= qh vertex_visit;
1806 fprintf(fp, "%d\n", qh_pointid (vertexB->point));
1807 }
1808 }
1809 facet->visitid= qh visit_id;
1810 facet= nextfacet;
1811 }while (facet && facet != startfacet);
1812 } /* printextremes_2d */
1813
1814 /*-<a href="qh-io.htm#TOC"
1815 >-------------------------------</a><a name="printextremes_d">-</a>
1816
1817 qh_printextremes_d( fp, facetlist, facets, printall )
1818 print extreme points of input sites for Delaunay triangulations
1819
1820 notes:
1821 #points, followed by ids, one per line
1822
1823 unordered
1824 */
1825 void qh_printextremes_d (FILE *fp, facetT *facetlist, setT *facets, int printall) {
1826 setT *vertices;
1827 vertexT *vertex, **vertexp;
1828 boolT upperseen, lowerseen;
1829 facetT *neighbor, **neighborp;
1830 int numpoints=0;
1831
1832 vertices= qh_facetvertices (facetlist, facets, printall);
1833 qh_vertexneighbors();
1834 FOREACHvertex_(vertices) {
1835 upperseen= lowerseen= False;
1836 FOREACHneighbor_(vertex) {
1837 if (neighbor->upperdelaunay)
1838 upperseen= True;
1839 else
1840 lowerseen= True;
1841 }
1842 if (upperseen && lowerseen) {
1843 vertex->seen= True;
1844 numpoints++;
1845 }else
1846 vertex->seen= False;
1847 }
1848 fprintf (fp, "%d\n", numpoints);
1849 FOREACHvertex_(vertices) {
1850 if (vertex->seen)
1851 fprintf (fp, "%d\n", qh_pointid (vertex->point));
1852 }
1853 qh_settempfree (&vertices);
1854 } /* printextremes_d */
1855
1856 /*-<a href="qh-io.htm#TOC"
1857 >-------------------------------</a><a name="printfacet">-</a>
1858
1859 qh_printfacet( fp, facet )
1860 prints all fields of a facet to fp
1861
1862 notes:
1863 ridges printed in neighbor order
1864 */
1865 void qh_printfacet(FILE *fp, facetT *facet) {
1866
1867 qh_printfacetheader (fp, facet);
1868 if (facet->ridges)
1869 qh_printfacetridges (fp, facet);
1870 } /* printfacet */
1871
1872
1873 /*-<a href="qh-io.htm#TOC"
1874 >-------------------------------</a><a name="printfacet2geom">-</a>
1875
1876 qh_printfacet2geom( fp, facet, color )
1877 print facet as part of a 2-d VECT for Geomview
1878
1879 notes:
1880 assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
1881 mindist is calculated within io.c. maxoutside is calculated elsewhere
1882 so a DISTround error may have occured.
1883 */
1884 void qh_printfacet2geom(FILE *fp, facetT *facet, realT color[3]) {
1885 pointT *point0, *point1;
1886 realT mindist, innerplane, outerplane;
1887 int k;
1888
1889 qh_facet2point (facet, &point0, &point1, &mindist);
1890 qh_geomplanes (facet, &outerplane, &innerplane);
1891 if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner))
1892 qh_printfacet2geom_points(fp, point0, point1, facet, outerplane, color);
1893 if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter &&
1894 outerplane - innerplane > 2 * qh MAXabs_coord * qh_GEOMepsilon)) {
1895 for(k= 3; k--; )
1896 color[k]= 1.0 - color[k];
1897 qh_printfacet2geom_points(fp, point0, point1, facet, innerplane, color);
1898 }
1899 qh_memfree (point1, qh normal_size);
1900 qh_memfree (point0, qh normal_size);
1901 } /* printfacet2geom */
1902
1903 /*-<a href="qh-io.htm#TOC"
1904 >-------------------------------</a><a name="printfacet2geom_points">-</a>
1905
1906 qh_printfacet2geom_points( fp, point1, point2, facet, offset, color )
1907 prints a 2-d facet as a VECT with 2 points at some offset.
1908 The points are on the facet's plane.
1909 */
1910 void qh_printfacet2geom_points(FILE *fp, pointT *point1, pointT *point2,
1911 facetT *facet, realT offset, realT color[3]) {
1912 pointT *p1= point1, *p2= point2;
1913
1914 fprintf(fp, "VECT 1 2 1 2 1 # f%d\n", facet->id);
1915 if (offset != 0.0) {
1916 p1= qh_projectpoint (p1, facet, -offset);
1917 p2= qh_projectpoint (p2, facet, -offset);
1918 }
1919 fprintf(fp, "%8.4g %8.4g %8.4g\n%8.4g %8.4g %8.4g\n",
1920 p1[0], p1[1], 0.0, p2[0], p2[1], 0.0);
1921 if (offset != 0.0) {
1922 qh_memfree (p1, qh normal_size);
1923 qh_memfree (p2, qh normal_size);
1924 }
1925 fprintf(fp, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
1926 } /* printfacet2geom_points */
1927
1928
1929 /*-<a href="qh-io.htm#TOC"
1930 >-------------------------------</a><a name="printfacet2math">-</a>
1931
1932 qh_printfacet2math( fp, facet, format, notfirst )
1933 print 2-d Maple or Mathematica output for a facet
1934 may be non-simplicial
1935
1936 notes:
1937 please use %16.8f since Mathematica 2.2 does not handle exponential format
1938 see qh_printfacet3math
1939 */
1940 void qh_printfacet2math(FILE *fp, facetT *facet, int format, int notfirst) {
1941 pointT *point0, *point1;
1942 realT mindist;
1943 char *pointfmt;
1944
1945 qh_facet2point (facet, &point0, &point1, &mindist);
1946 if (notfirst)
1947 fprintf(fp, ",");
1948 if (format == qh_PRINTmaple)
1949 pointfmt= "[[%16.8f, %16.8f], [%16.8f, %16.8f]]\n";
1950 else
1951 pointfmt= "Line[{{%16.8f, %16.8f}, {%16.8f, %16.8f}}]\n";
1952 fprintf(fp, pointfmt, point0[0], point0[1], point1[0], point1[1]);
1953 qh_memfree (point1, qh normal_size);
1954 qh_memfree (point0, qh normal_size);
1955 } /* printfacet2math */
1956
1957
1958 /*-<a href="qh-io.htm#TOC"
1959 >-------------------------------</a><a name="printfacet3geom_nonsimplicial">-</a>
1960
1961 qh_printfacet3geom_nonsimplicial( fp, facet, color )
1962 print Geomview OFF for a 3-d nonsimplicial facet.
1963 if DOintersections, prints ridges to unvisited neighbors (qh visit_id)
1964
1965 notes
1966 uses facet->visitid for intersections and ridges
1967 */
1968 void qh_printfacet3geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]) {
1969 ridgeT *ridge, **ridgep;
1970 setT *projectedpoints, *vertices;
1971 vertexT *vertex, **vertexp, *vertexA, *vertexB;
1972 pointT *projpt, *point, **pointp;
1973 facetT *neighbor;
1974 realT dist, outerplane, innerplane;
1975 int cntvertices, k;
1976 realT black[3]={0, 0, 0}, green[3]={0, 1, 0};
1977
1978 qh_geomplanes (facet, &outerplane, &innerplane);
1979 vertices= qh_facet3vertex (facet); /* oriented */
1980 cntvertices= qh_setsize(vertices);
1981 projectedpoints= qh_settemp(cntvertices);
1982 FOREACHvertex_(vertices) {
1983 zinc_(Zdistio);
1984 qh_distplane(vertex->point, facet, &dist);
1985 projpt= qh_projectpoint(vertex->point, facet, dist);
1986 qh_setappend (&projectedpoints, projpt);
1987 }
1988 if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner))
1989 qh_printfacet3geom_points(fp, projectedpoints, facet, outerplane, color);
1990 if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter &&
1991 outerplane - innerplane > 2 * qh MAXabs_coord * qh_GEOMepsilon)) {
1992 for (k=3; k--; )
1993 color[k]= 1.0 - color[k];
1994 qh_printfacet3geom_points(fp, projectedpoints, facet, innerplane, color);
1995 }
1996 FOREACHpoint_(projectedpoints)
1997 qh_memfree (point, qh normal_size);
1998 qh_settempfree(&projectedpoints);
1999 qh_settempfree(&vertices);
2000 if ((qh DOintersections || qh PRINTridges)
2001 && (!facet->visible || !qh NEWfacets)) {
2002 facet->visitid= qh visit_id;
2003 FOREACHridge_(facet->ridges) {
2004 neighbor= otherfacet_(ridge, facet);
2005 if (neighbor->visitid != qh visit_id) {
2006 if (qh DOintersections)
2007 qh_printhyperplaneintersection(fp, facet, neighbor, ridge->vertices, black);
2008 if (qh PRINTridges) {
2009 vertexA= SETfirstt_(ridge->vertices, vertexT);
2010 vertexB= SETsecondt_(ridge->vertices, vertexT);
2011 qh_printline3geom (fp, vertexA->point, vertexB->point, green);
2012 }
2013 }
2014 }
2015 }
2016 } /* printfacet3geom_nonsimplicial */
2017
2018 /*-<a href="qh-io.htm#TOC"
2019 >-------------------------------</a><a name="printfacet3geom_points">-</a>
2020
2021 qh_printfacet3geom_points( fp, points, facet, offset )
2022 prints a 3-d facet as OFF Geomview object.
2023 offset is relative to the facet's hyperplane
2024 Facet is determined as a list of points
2025 */
2026 void qh_printfacet3geom_points(FILE *fp, setT *points, facetT *facet, realT offset, realT color[3]) {
2027 int k, n= qh_setsize(points), i;
2028 pointT *point, **pointp;
2029 setT *printpoints;
2030
2031 fprintf(fp, "{ OFF %d 1 1 # f%d\n", n, facet->id);
2032 if (offset != 0.0) {
2033 printpoints= qh_settemp (n);
2034 FOREACHpoint_(points)
2035 qh_setappend (&printpoints, qh_projectpoint(point, facet, -offset));
2036 }else
2037 printpoints= points;
2038 FOREACHpoint_(printpoints) {
2039 for (k=0; k < qh hull_dim; k++) {
2040 if (k == qh DROPdim)
2041 fprintf(fp, "0 ");
2042 else
2043 fprintf(fp, "%8.4g ", point[k]);
2044 }
2045 if (printpoints != points)
2046 qh_memfree (point, qh normal_size);
2047 fprintf (fp, "\n");
2048 }
2049 if (printpoints != points)
2050 qh_settempfree (&printpoints);
2051 fprintf(fp, "%d ", n);
2052 for(i= 0; i < n; i++)
2053 fprintf(fp, "%d ", i);
2054 fprintf(fp, "%8.4g %8.4g %8.4g 1.0 }\n", color[0], color[1], color[2]);
2055 } /* printfacet3geom_points */
2056
2057
2058 /*-<a href="qh-io.htm#TOC"
2059 >-------------------------------</a><a name="printfacet3geom_simplicial">-</a>
2060
2061 qh_printfacet3geom_simplicial( )
2062 print Geomview OFF for a 3-d simplicial facet.
2063
2064 notes:
2065 may flip color
2066 uses facet->visitid for intersections and ridges
2067
2068 assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
2069 innerplane may be off by qh DISTround. Maxoutside is calculated elsewhere
2070 so a DISTround error may have occured.
2071 */
2072 void qh_printfacet3geom_simplicial(FILE *fp, facetT *facet, realT color[3]) {
2073 setT *points, *vertices;
2074 vertexT *vertex, **vertexp, *vertexA, *vertexB;
2075 facetT *neighbor, **neighborp;
2076 realT outerplane, innerplane;
2077 realT black[3]={0, 0, 0}, green[3]={0, 1, 0};
2078 int k;
2079
2080 qh_geomplanes (facet, &outerplane, &innerplane);
2081 vertices= qh_facet3vertex (facet);
2082 points= qh_settemp (qh TEMPsize);
2083 FOREACHvertex_(vertices)
2084 qh_setappend(&points, vertex->point);
2085 if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner))
2086 qh_printfacet3geom_points(fp, points, facet, outerplane, color);
2087 if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter &&
2088 outerplane - innerplane > 2 * qh MAXabs_coord * qh_GEOMepsilon)) {
2089 for (k= 3; k--; )
2090 color[k]= 1.0 - color[k];
2091 qh_printfacet3geom_points(fp, points, facet, innerplane, color);
2092 }
2093 qh_settempfree(&points);
2094 qh_settempfree(&vertices);
2095 if ((qh DOintersections || qh PRINTridges)
2096 && (!facet->visible || !qh NEWfacets)) {
2097 facet->visitid= qh visit_id;
2098 FOREACHneighbor_(facet) {
2099 if (neighbor->visitid != qh visit_id) {
2100 vertices= qh_setnew_delnthsorted (facet->vertices, qh hull_dim,
2101 SETindex_(facet->neighbors, neighbor), 0);
2102 if (qh DOintersections)
2103 qh_printhyperplaneintersection(fp, facet, neighbor, vertices, black);
2104 if (qh PRINTridges) {
2105 vertexA= SETfirstt_(vertices, vertexT);
2106 vertexB= SETsecondt_(vertices, vertexT);
2107 qh_printline3geom (fp, vertexA->point, vertexB->point, green);
2108 }
2109 qh_setfree(&vertices);
2110 }
2111 }
2112 }
2113 } /* printfacet3geom_simplicial */
2114
2115 /*-<a href="qh-io.htm#TOC"
2116 >-------------------------------</a><a name="printfacet3math">-</a>
2117
2118 qh_printfacet3math( fp, facet, notfirst )
2119 print 3-d Maple or Mathematica output for a facet
2120
2121 notes:
2122 may be non-simplicial
2123 please use %16.8f since Mathematica 2.2 does not handle exponential format
2124 see qh_printfacet2math
2125 */
2126 void qh_printfacet3math (FILE *fp, facetT *facet, int format, int notfirst) {
2127 vertexT *vertex, **vertexp;
2128 setT *points, *vertices;
2129 pointT *point, **pointp;
2130 boolT firstpoint= True;
2131 realT dist;
2132 char *pointfmt, *endfmt;
2133
2134 if (notfirst)
2135 fprintf(fp, ",\n");
2136 vertices= qh_facet3vertex (facet);
2137 points= qh_settemp (qh_setsize (vertices));
2138 FOREACHvertex_(vertices) {
2139 zinc_(Zdistio);
2140 qh_distplane(vertex->point, facet, &dist);
2141 point= qh_projectpoint(vertex->point, facet, dist);
2142 qh_setappend (&points, point);
2143 }
2144 if (format == qh_PRINTmaple) {
2145 fprintf(fp, "[");
2146 pointfmt= "[%16.8f, %16.8f, %16.8f]";
2147 endfmt= "]";
2148 }else {
2149 fprintf(fp, "Polygon[{");
2150 pointfmt= "{%16.8f, %16.8f, %16.8f}";
2151 endfmt= "}]";
2152 }
2153 FOREACHpoint_(points) {
2154 if (firstpoint)
2155 firstpoint= False;
2156 else
2157 fprintf(fp, ",\n");
2158 fprintf(fp, pointfmt, point[0], point[1], point[2]);
2159 }
2160 FOREACHpoint_(points)
2161 qh_memfree (point, qh normal_size);
2162 qh_settempfree(&points);
2163 qh_settempfree(&vertices);
2164 fprintf(fp, endfmt);
2165 } /* printfacet3math */
2166
2167
2168 /*-<a href="qh-io.htm#TOC"
2169 >-------------------------------</a><a name="printfacet3vertex">-</a>
2170
2171 qh_printfacet3vertex( fp, facet, format )
2172 print vertices in a 3-d facet as point ids
2173
2174 notes:
2175 prints number of vertices first if format == qh_PRINToff
2176 the facet may be non-simplicial
2177 */
2178 void qh_printfacet3vertex(FILE *fp, facetT *facet, int format) {
2179 vertexT *vertex, **vertexp;
2180 setT *vertices;
2181
2182 vertices= qh_facet3vertex (facet);
2183 if (format == qh_PRINToff)
2184 fprintf (fp, "%d ", qh_setsize (vertices));
2185 FOREACHvertex_(vertices)
2186 fprintf (fp, "%d ", qh_pointid(vertex->point));
2187 fprintf (fp, "\n");
2188 qh_settempfree(&vertices);
2189 } /* printfacet3vertex */
2190
2191
2192 /*-<a href="qh-io.htm#TOC"
2193 >-------------------------------</a><a name="printfacet4geom_nonsimplicial">-</a>
2194
2195 qh_printfacet4geom_nonsimplicial( )
2196 print Geomview 4OFF file for a 4d nonsimplicial facet
2197 prints all ridges to unvisited neighbors (qh.visit_id)
2198 if qh.DROPdim
2199 prints in OFF format
2200
2201 notes:
2202 must agree with printend4geom()
2203 */
2204 void qh_printfacet4geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]) {
2205 facetT *neighbor;
2206 ridgeT *ridge, **ridgep;
2207 vertexT *vertex, **vertexp;
2208 pointT *point;
2209 int k;
2210 realT dist;
2211
2212 facet->visitid= qh visit_id;
2213 if (qh PRINTnoplanes || (facet->visible && qh NEWfacets))
2214 return;
2215 FOREACHridge_(facet->ridges) {
2216 neighbor= otherfacet_(ridge, facet);
2217 if (neighbor->visitid == qh visit_id)
2218 continue;
2219 if (qh PRINTtransparent && !neighbor->good)
2220 continue;
2221 if (qh DOintersections)
2222 qh_printhyperplaneintersection(fp, facet, neighbor, ridge->vertices, color);
2223 else {
2224 if (qh DROPdim >= 0)
2225 fprintf(fp, "OFF 3 1 1 # f%d\n", facet->id);
2226 else {
2227 qh printoutvar++;
2228 fprintf (fp, "# r%d between f%d f%d\n", ridge->id, facet->id, neighbor->id);
2229 }
2230 FOREACHvertex_(ridge->vertices) {
2231 zinc_(Zdistio);
2232 qh_distplane(vertex->point,facet, &dist);
2233 point=qh_projectpoint(vertex->point,facet, dist);
2234 for(k= 0; k < qh hull_dim; k++) {
2235 if (k != qh DROPdim)
2236 fprintf(fp, "%8.4g ", point[k]);
2237 }
2238 fprintf (fp, "\n");
2239 qh_memfree (point, qh normal_size);
2240 }
2241 if (qh DROPdim >= 0)
2242 fprintf(fp, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);
2243 }
2244 }
2245 } /* printfacet4geom_nonsimplicial */
2246
2247
2248 /*-<a href="qh-io.htm#TOC"
2249 >-------------------------------</a><a name="printfacet4geom_simplicial">-</a>
2250
2251 qh_printfacet4geom_simplicial( fp, facet, color )
2252 print Geomview 4OFF file for a 4d simplicial facet
2253 prints triangles for unvisited neighbors (qh.visit_id)
2254
2255 notes:
2256 must agree with printend4geom()
2257 */
2258 void qh_printfacet4geom_simplicial(FILE *fp, facetT *facet, realT color[3]) {
2259 setT *vertices;
2260 facetT *neighbor, **neighborp;
2261 vertexT *vertex, **vertexp;
2262 int k;
2263
2264 facet->visitid= qh visit_id;
2265 if (qh PRINTnoplanes || (facet->visible && qh NEWfacets))
2266 return;
2267 FOREACHneighbor_(facet) {
2268 if (neighbor->visitid == qh visit_id)
2269 continue;
2270 if (qh PRINTtransparent && !neighbor->good)
2271 continue;
2272 vertices= qh_setnew_delnthsorted (facet->vertices, qh hull_dim,
2273 SETindex_(facet->neighbors, neighbor), 0);
2274 if (qh DOintersections)
2275 qh_printhyperplaneintersection(fp, facet, neighbor, vertices, color);
2276 else {
2277 if (qh DROPdim >= 0)
2278 fprintf(fp, "OFF 3 1 1 # ridge between f%d f%d\n",
2279 facet->id, neighbor->id);
2280 else {
2281 qh printoutvar++;
2282 fprintf (fp, "# ridge between f%d f%d\n", facet->id, neighbor->id);
2283 }
2284 FOREACHvertex_(vertices) {
2285 for(k= 0; k < qh hull_dim; k++) {
2286 if (k != qh DROPdim)
2287 fprintf(fp, "%8.4g ", vertex->point[k]);
2288 }
2289 fprintf (fp, "\n");
2290 }
2291 if (qh DROPdim >= 0)
2292 fprintf(fp, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);
2293 }
2294 qh_setfree(&vertices);
2295 }
2296 } /* printfacet4geom_simplicial */
2297
2298
2299 /*-<a href="qh-io.htm#TOC"
2300 >-------------------------------</a><a name="printfacetNvertex_nonsimplicial">-</a>
2301
2302 qh_printfacetNvertex_nonsimplicial( fp, facet, id, format )
2303 print vertices for an N-d non-simplicial facet
2304 triangulates each ridge to the id
2305 */
2306 void qh_printfacetNvertex_nonsimplicial(FILE *fp, facetT *facet, int id, int format) {
2307 vertexT *vertex, **vertexp;
2308 ridgeT *ridge, **ridgep;
2309
2310 if (facet->visible && qh NEWfacets)
2311 return;
2312 FOREACHridge_(facet->ridges) {
2313 if (format == qh_PRINTtriangles)
2314 fprintf(fp, "%d ", qh hull_dim);
2315 fprintf(fp, "%d ", id);
2316 if ((ridge->top == facet) ^ qh_ORIENTclock) {
2317 FOREACHvertex_(ridge->vertices)
2318 fprintf(fp, "%d ", qh_pointid(vertex->point));
2319 }else {
2320 FOREACHvertexreverse12_(ridge->vertices)
2321 fprintf(fp, "%d ", qh_pointid(vertex->point));
2322 }
2323 fprintf(fp, "\n");
2324 }
2325 } /* printfacetNvertex_nonsimplicial */
2326
2327
2328 /*-<a href="qh-io.htm#TOC"
2329 >-------------------------------</a><a name="printfacetNvertex_simplicial">-</a>
2330
2331 qh_printfacetNvertex_simplicial( fp, facet, format )
2332 print vertices for an N-d simplicial facet
2333 prints vertices for non-simplicial facets
2334 2-d facets (orientation preserved by qh_mergefacet2d)
2335 PRINToff ('o') for 4-d and higher
2336 */
2337 void qh_printfacetNvertex_simplicial(FILE *fp, facetT *facet, int format) {
2338 vertexT *vertex, **vertexp;
2339
2340 if (format == qh_PRINToff || format == qh_PRINTtriangles)
2341 fprintf (fp, "%d ", qh_setsize (facet->vertices));
2342 if ((facet->toporient ^ qh_ORIENTclock)
2343 || (qh hull_dim > 2 && !facet->simplicial)) {
2344 FOREACHvertex_(facet->vertices)
2345 fprintf(fp, "%d ", qh_pointid(vertex->point));
2346 }else {
2347 FOREACHvertexreverse12_(facet->vertices)
2348 fprintf(fp, "%d ", qh_pointid(vertex->point));
2349 }
2350 fprintf(fp, "\n");
2351 } /* printfacetNvertex_simplicial */
2352
2353
2354 /*-<a href="qh-io.htm#TOC"
2355 >-------------------------------</a><a name="printfacetheader">-</a>
2356
2357 qh_printfacetheader( fp, facet )
2358 prints header fields of a facet to fp
2359
2360 notes:
2361 for 'f' output and debugging
2362 */
2363 void qh_printfacetheader(FILE *fp, facetT *facet) {
2364 pointT *point, **pointp, *furthest;
2365 facetT *neighbor, **neighborp;
2366 realT dist;
2367
2368 if (facet == qh_MERGEridge) {
2369 fprintf (fp, " MERGEridge\n");
2370 return;
2371 }else if (facet == qh_DUPLICATEridge) {
2372 fprintf (fp, " DUPLICATEridge\n");
2373 return;
2374 }else if (!facet) {
2375 fprintf (fp, " NULLfacet\n");
2376 return;
2377 }
2378 qh old_randomdist= qh RANDOMdist;
2379 qh RANDOMdist= False;
2380 fprintf(fp, "- f%d\n", facet->id);
2381 fprintf(fp, " - flags:");
2382 if (facet->toporient)
2383 fprintf(fp, " top");
2384 else
2385 fprintf(fp, " bottom");
2386 if (facet->simplicial)
2387 fprintf(fp, " simplicial");
2388 if (facet->tricoplanar)
2389 fprintf(fp, " tricoplanar");
2390 if (facet->upperdelaunay)
2391 fprintf(fp, " upperDelaunay");
2392 if (facet->visible)
2393 fprintf(fp, " visible");
2394 if (facet->newfacet)
2395 fprintf(fp, " new");
2396 if (facet->tested)
2397 fprintf(fp, " tested");
2398 if (!facet->good)
2399 fprintf(fp, " notG");
2400 if (facet->seen)
2401 fprintf(fp, " seen");
2402 if (facet->coplanar)
2403 fprintf(fp, " coplanar");
2404 if (facet->mergehorizon)
2405 fprintf(fp, " mergehorizon");
2406 if (facet->keepcentrum)
2407 fprintf(fp, " keepcentrum");
2408 if (facet->dupridge)
2409 fprintf(fp, " dupridge");
2410 if (facet->mergeridge && !facet->mergeridge2)
2411 fprintf(fp, " mergeridge1");
2412 if (facet->mergeridge2)
2413 fprintf(fp, " mergeridge2");
2414 if (facet->newmerge)
2415 fprintf(fp, " newmerge");
2416 if (facet->flipped)
2417 fprintf(fp, " flipped");
2418 if (facet->notfurthest)
2419 fprintf(fp, " notfurthest");
2420 if (facet->degenerate)
2421 fprintf(fp, " degenerate");
2422 if (facet->redundant)
2423 fprintf(fp, " redundant");
2424 fprintf(fp, "\n");
2425 if (facet->isarea)
2426 fprintf(fp, " - area: %2.2g\n", facet->f.area);
2427 else if (qh NEWfacets && facet->visible && facet->f.replace)
2428 fprintf(fp, " - replacement: f%d\n", facet->f.replace->id);
2429 else if (facet->newfacet) {
2430 if (facet->f.samecycle && facet->f.samecycle != facet)
2431 fprintf(fp, " - shares same visible/horizon as f%d\n", facet->f.samecycle->id);
2432 }else if (facet->tricoplanar /* !isarea */) {
2433 if (facet->f.triowner)
2434 fprintf(fp, " - owner of normal & centrum is facet f%d\n", facet->f.triowner->id);
2435 }else if (facet->f.newcycle)
2436 fprintf(fp, " - was horizon to f%d\n", facet->f.newcycle->id);
2437 if (facet->nummerge)
2438 fprintf(fp, " - merges: %d\n", facet->nummerge);
2439 qh_printpointid(fp, " - normal: ", qh hull_dim, facet->normal, -1);
2440 fprintf(fp, " - offset: %10.7g\n", facet->offset);
2441 if (qh CENTERtype == qh_ASvoronoi || facet->center)
2442 qh_printcenter (fp, qh_PRINTfacets, " - center: ", facet);
2443 #if qh_MAXoutside
2444 if (facet->maxoutside > qh DISTround)
2445 fprintf(fp, " - maxoutside: %10.7g\n", facet->maxoutside);
2446 #endif
2447 if (!SETempty_(facet->outsideset)) {
2448 furthest= (pointT*)qh_setlast(facet->outsideset);
2449 if (qh_setsize (facet->outsideset) < 6) {
2450 fprintf(fp, " - outside set (furthest p%d):\n", qh_pointid(furthest));
2451 FOREACHpoint_(facet->outsideset)
2452 qh_printpoint(fp, " ", point);
2453 }else if (qh_setsize (facet->outsideset) < 21) {
2454 qh_printpoints(fp, " - outside set:", facet->outsideset);
2455 }else {
2456 fprintf(fp, " - outside set: %d points.", qh_setsize(facet->outsideset));
2457 qh_printpoint(fp, " Furthest", furthest);
2458 }
2459 #if !qh_COMPUTEfurthest
2460 fprintf(fp, " - furthest distance= %2.2g\n", facet->furthestdist);
2461 #endif
2462 }
2463 if (!SETempty_(facet->coplanarset)) {
2464 furthest= (pointT*)qh_setlast(facet->coplanarset);
2465 if (qh_setsize (facet->coplanarset) < 6) {
2466 fprintf(fp, " - coplanar set (furthest p%d):\n", qh_pointid(furthest));
2467 FOREACHpoint_(facet->coplanarset)
2468 qh_printpoint(fp, " ", point);
2469 }else if (qh_setsize (facet->coplanarset) < 21) {
2470 qh_printpoints(fp, " - coplanar set:", facet->coplanarset);
2471 }else {
2472 fprintf(fp, " - coplanar set: %d points.", qh_setsize(facet->coplanarset));
2473 qh_printpoint(fp, " Furthest", furthest);
2474 }
2475 zinc_(Zdistio);
2476 qh_distplane (furthest, facet, &dist);
2477 fprintf(fp, " furthest distance= %2.2g\n", dist);
2478 }
2479 qh_printvertices (fp, " - vertices:", facet->vertices);
2480 fprintf(fp, " - neighboring facets: ");
2481 FOREACHneighbor_(facet) {
2482 if (neighbor == qh_MERGEridge)
2483 fprintf(fp, " MERGE");
2484 else if (neighbor == qh_DUPLICATEridge)
2485 fprintf(fp, " DUP");
2486 else
2487 fprintf(fp, " f%d", neighbor->id);
2488 }
2489 fprintf(fp, "\n");
2490 qh RANDOMdist= qh old_randomdist;
2491 } /* printfacetheader */
2492
2493
2494 /*-<a href="qh-io.htm#TOC"
2495 >-------------------------------</a><a name="printfacetridges">-</a>
2496
2497 qh_printfacetridges( fp, facet )
2498 prints ridges of a facet to fp
2499
2500 notes:
2501 ridges printed in neighbor order
2502 assumes the ridges exist
2503 for 'f' output
2504 */
2505 void qh_printfacetridges(FILE *fp, facetT *facet) {
2506 facetT *neighbor, **neighborp;
2507 ridgeT *ridge, **ridgep;
2508 int numridges= 0;
2509
2510
2511 if (facet->visible && qh NEWfacets) {
2512 fprintf(fp, " - ridges (ids may be garbage):");
2513 FOREACHridge_(facet->ridges)
2514 fprintf(fp, " r%d", ridge->id);
2515 fprintf(fp, "\n");
2516 }else {
2517 fprintf(fp, " - ridges:\n");
2518 FOREACHridge_(facet->ridges)
2519 ridge->seen= False;
2520 if (qh hull_dim == 3) {
2521 ridge= SETfirstt_(facet->ridges, ridgeT);
2522 while (ridge && !ridge->seen) {
2523 ridge->seen= True;
2524 qh_printridge(fp, ridge);
2525 numridges++;
2526 ridge= qh_nextridge3d (ridge, facet, NULL);
2527 }
2528 }else {
2529 FOREACHneighbor_(facet) {
2530 FOREACHridge_(facet->ridges) {
2531 if (otherfacet_(ridge,facet) == neighbor) {
2532 ridge->seen= True;
2533 qh_printridge(fp, ridge);
2534 numridges++;
2535 }
2536 }
2537 }
2538 }
2539 if (numridges != qh_setsize (facet->ridges)) {
2540 fprintf (fp, " - all ridges:");
2541 FOREACHridge_(facet->ridges)
2542 fprintf (fp, " r%d", ridge->id);
2543 fprintf (fp, "\n");
2544 }
2545 FOREACHridge_(facet->ridges) {
2546 if (!ridge->seen)
2547 qh_printridge(fp, ridge);
2548 }
2549 }
2550 } /* printfacetridges */
2551
2552 /*-<a href="qh-io.htm#TOC"
2553 >-------------------------------</a><a name="printfacets">-</a>
2554
2555 qh_printfacets( fp, format, facetlist, facets, printall )
2556 prints facetlist and/or facet set in output format
2557
2558 notes:
2559 also used for specialized formats ('FO' and summary)
2560 turns off 'Rn' option since want actual numbers
2561 */
2562 void qh_printfacets(FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
2563 int numfacets, numsimplicial, numridges, totneighbors, numcoplanars, numtricoplanars;
2564 facetT *facet, **facetp;
2565 setT *vertices;
2566 coordT *center;
2567 realT outerplane, innerplane;
2568
2569 qh old_randomdist= qh RANDOMdist;
2570 qh RANDOMdist= False;
2571 if (qh CDDoutput && (format == qh_PRINTcentrums || format == qh_PRINTpointintersect || format == qh_PRINToff))
2572 fprintf (qh ferr, "qhull warning: CDD format is not available for centrums, halfspace\nintersections, and OFF file format.\n");
2573 if (format == qh_PRINTnone)
2574 ; /* print nothing */
2575 else if (format == qh_PRINTaverage) {
2576 vertices= qh_facetvertices (facetlist, facets, printall);
2577 center= qh_getcenter (vertices);
2578 fprintf (fp, "%d 1\n", qh hull_dim);
2579 qh_printpointid (fp, NULL, qh hull_dim, center, -1);
2580 qh_memfree (center, qh normal_size);
2581 qh_settempfree (&vertices);
2582 }else if (format == qh_PRINTextremes) {
2583 if (qh DELAUNAY)
2584 qh_printextremes_d (fp, facetlist, facets, printall);
2585 else if (qh hull_dim == 2)
2586 qh_printextremes_2d (fp, facetlist, facets, printall);
2587 else
2588 qh_printextremes (fp, facetlist, facets, printall);
2589 }else if (format == qh_PRINToptions)
2590 fprintf(fp, "Options selected for Qhull %s:\n%s\n", qh_version, qh qhull_options);
2591 else if (format == qh_PRINTpoints && !qh VORONOI)
2592 qh_printpoints_out (fp, facetlist, facets, printall);
2593 else if (format == qh_PRINTqhull)
2594 fprintf (fp, "%s | %s\n", qh rbox_command, qh qhull_command);
2595 else if (format == qh_PRINTsize) {
2596 fprintf (fp, "0\n2 ");
2597 fprintf (fp, qh_REAL_1, qh totarea);
2598 fprintf (fp, qh_REAL_1, qh totvol);
2599 fprintf (fp, "\n");
2600 }else if (format == qh_PRINTsummary) {
2601 qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial,
2602 &totneighbors, &numridges, &numcoplanars, &numtricoplanars);
2603 vertices= qh_facetvertices (facetlist, facets, printall);
2604 fprintf (fp, "10 %d %d %d %d %d %d %d %d %d %d\n2 ", qh hull_dim,
2605 qh num_points + qh_setsize (qh other_points),
2606 qh num_vertices, qh num_facets - qh num_visible,
2607 qh_setsize (vertices), numfacets, numcoplanars,
2608 numfacets - numsimplicial, zzval_(Zdelvertextot),
2609 numtricoplanars);
2610 qh_settempfree (&vertices);
2611 qh_outerinner (NULL, &outerplane, &innerplane);
2612 fprintf (fp, qh_REAL_2n, outerplane, innerplane);
2613 }else if (format == qh_PRINTvneighbors)
2614 qh_printvneighbors (fp, facetlist, facets, printall);
2615 else if (qh VORONOI && format == qh_PRINToff)
2616 qh_printvoronoi (fp, format, facetlist, facets, printall);
2617 else if (qh VORONOI && format == qh_PRINTgeom) {
2618 qh_printbegin (fp, format, facetlist, facets, printall);
2619 qh_printvoronoi (fp, format, facetlist, facets, printall);
2620 qh_printend (fp, format, facetlist, facets, printall);
2621 }else if (qh VORONOI
2622 && (format == qh_PRINTvertices || format == qh_PRINTinner || format == qh_PRINTouter))
2623 qh_printvdiagram (fp, format, facetlist, facets, printall);
2624 else {
2625 qh_printbegin (fp, format, facetlist, facets, printall);
2626 FORALLfacet_(facetlist)
2627 qh_printafacet (fp, format, facet, printall);
2628 FOREACHfacet_(facets)
2629 qh_printafacet (fp, format, facet, printall);
2630 qh_printend (fp, format, facetlist, facets, printall);
2631 }
2632 qh RANDOMdist= qh old_randomdist;
2633 } /* printfacets */
2634
2635
2636 /*-<a href="qh-io.htm#TOC"
2637 >-------------------------------</a><a name="printhelp_degenerate">-</a>
2638
2639 qh_printhelp_degenerate( fp )
2640 prints descriptive message for precision error
2641
2642 notes:
2643 no message if qh_QUICKhelp
2644 */
2645 void qh_printhelp_degenerate(FILE *fp) {
2646
2647 if (qh MERGEexact || qh PREmerge || qh JOGGLEmax < REALmax/2)
2648 fprintf(fp, "\n\
2649 A Qhull error has occurred. Qhull should have corrected the above\n\
2650 precision error. Please send the input and all of the output to\n\
2651 qhull_bug@qhull.org\n");
2652 else if (!qh_QUICKhelp) {
2653 fprintf(fp, "\n\
2654 Precision problems were detected during construction of the convex hull.\n\
2655 This occurs because convex hull algorithms assume that calculations are\n\
2656 exact, but floating-point arithmetic has roundoff errors.\n\
2657 \n\
2658 To correct for precision problems, do not use 'Q0'. By default, Qhull\n\
2659 selects 'C-0' or 'Qx' and merges non-convex facets. With option 'QJ',\n\
2660 Qhull joggles the input to prevent precision problems. See \"Imprecision\n\
2661 in Qhull\" (qh-impre.htm).\n\
2662 \n\
2663 If you use 'Q0', the output may include\n\
2664 coplanar ridges, concave ridges, and flipped facets. In 4-d and higher,\n\
2665 Qhull may produce a ridge with four neighbors or two facets with the same \n\
2666 vertices. Qhull reports these events when they occur. It stops when a\n\
2667 concave ridge, flipped facet, or duplicate facet occurs.\n");
2668 #if REALfloat
2669 fprintf (fp, "\
2670 \n\
2671 Qhull is currently using single precision arithmetic. The following\n\
2672 will probably remove the precision problems:\n\
2673 - recompile qhull for double precision (#define REALfloat 0 in user.h).\n");
2674 #endif
2675 if (qh DELAUNAY && !qh SCALElast && qh MAXabs_coord > 1e4)
2676 fprintf( fp, "\
2677 \n\
2678 When computing the Delaunay triangulation of coordinates > 1.0,\n\
2679 - please use 'Qbb' to scale the last coordinate to [0,m] (max previous coordinate)\n");
2680 if (qh DELAUNAY && !qh ATinfinity)
2681 fprintf( fp, "\
2682 When computing the Delaunay triangulation:\n\
2683 - please use 'Qz' to add a point at-infinity. This reduces precision problems.\n");
2684
2685 fprintf(fp, "\
2686 \n\
2687 If you need triangular output:\n\
2688 - please use option 'Qt' to triangulate the output\n\
2689 - please use option 'QJ' to joggle the input points and remove precision errors\n\
2690 - please use option 'Ft'. It triangulates non-simplicial facets with added points.\n\
2691 \n\
2692 If you must use 'Q0',\n\
2693 try one or more of the following options. They can not guarantee an output.\n\
2694 - please use 'QbB' to scale the input to a cube.\n\
2695 - please use 'Po' to produce output and prevent partitioning for flipped facets\n\
2696 - please use 'V0' to set min. distance to visible facet as 0 instead of roundoff\n\
2697 - please use 'En' to specify a maximum roundoff error less than %2.2g.\n\
2698 - options 'Qf', 'Qbb', and 'QR0' may also help\n",
2699 qh DISTround);
2700 fprintf(fp, "\
2701 \n\
2702 To guarantee simplicial output:\n\
2703 - please use option 'Qt' to triangulate the output\n\
2704 - please use option 'QJ' to joggle the input points and remove precision errors\n\
2705 - please use option 'Ft' to triangulate the output by adding points\n\
2706 - please use exact arithmetic (see \"Imprecision in Qhull\", qh-impre.htm)\n\
2707 ");
2708 }
2709 } /* printhelp_degenerate */
2710
2711
2712 /*-<a href="qh-io.htm#TOC"
2713 >-------------------------------</a><a name="printhelp_singular">-</a>
2714
2715 qh_printhelp_singular( fp )
2716 prints descriptive message for singular input
2717 */
2718 void qh_printhelp_singular(FILE *fp) {
2719 facetT *facet;
2720 vertexT *vertex, **vertexp;
2721 realT min, max, *coord, dist;
2722 int i,k;
2723
2724 fprintf(fp, "\n\
2725 The input to qhull appears to be less than %d dimensional, or a\n\
2726 computation has overflowed.\n\n\
2727 Qhull could not construct a clearly convex simplex from points:\n",
2728 qh hull_dim);
2729 qh_printvertexlist (fp, "", qh facet_list, NULL, qh_ALL);
2730 if (!qh_QUICKhelp)
2731 fprintf(fp, "\n\
2732 The center point is coplanar with a facet, or a vertex is coplanar\n\
2733 with a neighboring facet. The maximum round off error for\n\
2734 computing distances is %2.2g. The center point, facets and distances\n\
2735 to the center point are as follows:\n\n", qh DISTround);
2736 qh_printpointid (fp, "center point", qh hull_dim, qh interior_point, -1);
2737 fprintf (fp, "\n");
2738 FORALLfacets {
2739 fprintf (fp, "facet");
2740 FOREACHvertex_(facet->vertices)
2741 fprintf (fp, " p%d", qh_pointid(vertex->point));
2742 zinc_(Zdistio);
2743 qh_distplane(qh interior_point, facet, &dist);
2744 fprintf (fp, " distance= %4.2g\n", dist);
2745 }
2746 if (!qh_QUICKhelp) {
2747 if (qh HALFspace)
2748 fprintf (fp, "\n\
2749 These points are the dual of the given halfspaces. They indicate that\n\
2750 the intersection is degenerate.\n");
2751 fprintf (fp,"\n\
2752 These points either have a maximum or minimum x-coordinate, or\n\
2753 they maximize the determinant for k coordinates. Trial points\n\
2754 are first selected from points that maximize a coordinate.\n");
2755 if (qh hull_dim >= qh_INITIALmax)
2756 fprintf (fp, "\n\
2757 Because of the high dimension, the min x-coordinate and max-coordinate\n\
2758 points are used if the determinant is non-zero. Option 'Qs' will\n\
2759 do a better, though much slower, job. Instead of 'Qs', you can change\n\
2760 the points by randomly rotating the input with 'QR0'.\n");
2761 }
2762 fprintf (fp, "\nThe min and max coordinates for each dimension are:\n");
2763 for (k=0; k < qh hull_dim; k++) {
2764 min= REALmax;
2765 max= -REALmin;
2766 for (i=qh num_points, coord= qh first_point+k; i--; coord += qh hull_dim) {
2767 maximize_(max, *coord);
2768 minimize_(min, *coord);
2769 }
2770 fprintf (fp, " %d: %8.4g %8.4g difference= %4.4g\n", k, min, max, max-min);
2771 }
2772 if (!qh_QUICKhelp) {
2773 fprintf (fp, "\n\
2774 If the input should be full dimensional, you have several options that\n\
2775 may determine an initial simplex:\n\
2776 - use 'QJ' to joggle the input and make it full dimensional\n\
2777 - use 'QbB' to scale the points to the unit cube\n\
2778 - use 'QR0' to randomly rotate the input for different maximum points\n\
2779 - use 'Qs' to search all points for the initial simplex\n\
2780 - use 'En' to specify a maximum roundoff error less than %2.2g.\n\
2781 - trace execution with 'T3' to see the determinant for each point.\n",
2782 qh DISTround);
2783 #if REALfloat
2784 fprintf (fp, "\
2785 - recompile qhull for double precision (#define REALfloat 0 in qhull.h).\n");
2786 #endif
2787 fprintf (fp, "\n\
2788 If the input is lower dimensional:\n\
2789 - use 'QJ' to joggle the input and make it full dimensional\n\
2790 - use 'Qbk:0Bk:0' to delete coordinate k from the input. You should\n\
2791 pick the coordinate with the least range. The hull will have the\n\
2792 correct topology.\n\
2793 - determine the flat containing the points, rotate the points\n\
2794 into a coordinate plane, and delete the other coordinates.\n\
2795 - add one or more points to make the input full dimensional.\n\
2796 ");
2797 if (qh DELAUNAY && !qh ATinfinity)
2798 fprintf (fp, "\n\n\
2799 This is a Delaunay triangulation and the input is co-circular or co-spherical:\n\
2800 - use 'Qz' to add a point \"at infinity\" (i.e., above the paraboloid)\n\
2801 - or use 'QJ' to joggle the input and avoid co-circular data\n");
2802 }
2803 } /* printhelp_singular */
2804
2805 /*-<a href="qh-io.htm#TOC"
2806 >-------------------------------</a><a name="printhyperplaneintersection">-</a>
2807
2808 qh_printhyperplaneintersection( fp, facet1, facet2, vertices, color )
2809 print Geomview OFF or 4OFF for the intersection of two hyperplanes in 3-d or 4-d
2810 */
2811 void qh_printhyperplaneintersection(FILE *fp, facetT *facet1, facetT *facet2,
2812 setT *vertices, realT color[3]) {
2813 realT costheta, denominator, dist1, dist2, s, t, mindenom, p[4];
2814 vertexT *vertex, **vertexp;
2815 int i, k;
2816 boolT nearzero1, nearzero2;
2817
2818 costheta= qh_getangle(facet1->normal, facet2->normal);
2819 denominator= 1 - costheta * costheta;
2820 i= qh_setsize(vertices);
2821 if (qh hull_dim == 3)
2822 fprintf(fp, "VECT 1 %d 1 %d 1 ", i, i);
2823 else if (qh hull_dim == 4 && qh DROPdim >= 0)
2824 fprintf(fp, "OFF 3 1 1 ");
2825 else
2826 qh printoutvar++;
2827 fprintf (fp, "# intersect f%d f%d\n", facet1->id, facet2->id);
2828 mindenom= 1 / (10.0 * qh MAXabs_coord);
2829 FOREACHvertex_(vertices) {
2830 zadd_(Zdistio, 2);
2831 qh_distplane(vertex->point, facet1, &dist1);
2832 qh_distplane(vertex->point, facet2, &dist2);
2833 s= qh_divzero (-dist1 + costheta * dist2, denominator,mindenom,&nearzero1);
2834 t= qh_divzero (-dist2 + costheta * dist1, denominator,mindenom,&nearzero2);
2835 if (nearzero1 || nearzero2)
2836 s= t= 0.0;
2837 for(k= qh hull_dim; k--; )
2838 p[k]= vertex->point[k] + facet1->normal[k] * s + facet2->normal[k] * t;
2839 if (qh PRINTdim <= 3) {
2840 qh_projectdim3 (p, p);
2841 fprintf(fp, "%8.4g %8.4g %8.4g # ", p[0], p[1], p[2]);
2842 }else
2843 fprintf(fp, "%8.4g %8.4g %8.4g %8.4g # ", p[0], p[1], p[2], p[3]);
2844 if (nearzero1+nearzero2)
2845 fprintf (fp, "p%d (coplanar facets)\n", qh_pointid (vertex->point));
2846 else
2847 fprintf (fp, "projected p%d\n", qh_pointid (vertex->point));
2848 }
2849 if (qh hull_dim == 3)
2850 fprintf(fp, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
2851 else if (qh hull_dim == 4 && qh DROPdim >= 0)
2852 fprintf(fp, "3 0 1 2 %8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
2853 } /* printhyperplaneintersection */
2854
2855 /*-<a href="qh-io.htm#TOC"
2856 >-------------------------------</a><a name="printline3geom">-</a>
2857
2858 qh_printline3geom( fp, pointA, pointB, color )
2859 prints a line as a VECT
2860 prints 0's for qh.DROPdim
2861
2862 notes:
2863 if pointA == pointB,
2864 it's a 1 point VECT
2865 */
2866 void qh_printline3geom (FILE *fp, pointT *pointA, pointT *pointB, realT color[3]) {
2867 int k;
2868 realT pA[4], pB[4];
2869
2870 qh_projectdim3(pointA, pA);
2871 qh_projectdim3(pointB, pB);
2872 if ((fabs(pA[0] - pB[0]) > 1e-3) ||
2873 (fabs(pA[1] - pB[1]) > 1e-3) ||
2874 (fabs(pA[2] - pB[2]) > 1e-3)) {
2875 fprintf (fp, "VECT 1 2 1 2 1\n");
2876 for (k= 0; k < 3; k++)
2877 fprintf (fp, "%8.4g ", pB[k]);
2878 fprintf (fp, " # p%d\n", qh_pointid (pointB));
2879 }else
2880 fprintf (fp, "VECT 1 1 1 1 1\n");
2881 for (k=0; k < 3; k++)
2882 fprintf (fp, "%8.4g ", pA[k]);
2883 fprintf (fp, " # p%d\n", qh_pointid (pointA));
2884 fprintf (fp, "%8.4g %8.4g %8.4g 1\n", color[0], color[1], color[2]);
2885 }
2886
2887 /*-<a href="qh-io.htm#TOC"
2888 >-------------------------------</a><a name="printneighborhood">-</a>
2889
2890 qh_printneighborhood( fp, format, facetA, facetB, printall )
2891 print neighborhood of one or two facets
2892
2893 notes:
2894 calls qh_findgood_all()
2895 bumps qh.visit_id
2896 */
2897 void qh_printneighborhood (FILE *fp, int format, facetT *facetA, facetT *facetB, boolT printall) {
2898 facetT *neighbor, **neighborp, *facet;
2899 setT *facets;
2900
2901 if (format == qh_PRINTnone)
2902 return;
2903 qh_findgood_all (qh facet_list);
2904 if (facetA == facetB)
2905 facetB= NULL;
2906 facets= qh_settemp (2*(qh_setsize (facetA->neighbors)+1));
2907 qh visit_id++;
2908 for (facet= facetA; facet; facet= ((facet == facetA) ? facetB : NULL)) {
2909 if (facet->visitid != qh visit_id) {
2910 facet->visitid= qh visit_id;
2911 qh_setappend (&facets, facet);
2912 }
2913 FOREACHneighbor_(facet) {
2914 if (neighbor->visitid == qh visit_id)
2915 continue;
2916 neighbor->visitid= qh visit_id;
2917 if (printall || !qh_skipfacet (neighbor))
2918 qh_setappend (&facets, neighbor);
2919 }
2920 }
2921 qh_printfacets (fp, format, NULL, facets, printall);
2922 qh_settempfree (&facets);
2923 } /* printneighborhood */
2924
2925 /*-<a href="qh-io.htm#TOC"
2926 >-------------------------------</a><a name="printpoint">-</a>
2927
2928 qh_printpoint( fp, string, point )
2929 qh_printpointid( fp, string, dim, point, id )
2930 prints the coordinates of a point
2931
2932 returns:
2933 if string is defined
2934 prints 'string p%d' (skips p%d if id=-1)
2935
2936 notes:
2937 nop if point is NULL
2938 prints id unless it is undefined (-1)
2939 */
2940 void qh_printpoint(FILE *fp, char *string, pointT *point) {
2941 int id= qh_pointid( point);
2942
2943 qh_printpointid( fp, string, qh hull_dim, point, id);
2944 } /* printpoint */
2945
2946 void qh_printpointid(FILE *fp, char *string, int dim, pointT *point, int id) {
2947 int k;
2948 realT r; /*bug fix*/
2949
2950 if (!point)
2951 return;
2952 if (string) {
2953 fputs (string, fp);
2954 if (id != -1)
2955 fprintf(fp, " p%d: ", id);
2956 }
2957 for(k= dim; k--; ) {
2958 r= *point++;
2959 if (string)
2960 fprintf(fp, " %8.4g", r);
2961 else
2962 fprintf(fp, qh_REAL_1, r);
2963 }
2964 fprintf(fp, "\n");
2965 } /* printpointid */
2966
2967 /*-<a href="qh-io.htm#TOC"
2968 >-------------------------------</a><a name="printpoint3">-</a>
2969
2970 qh_printpoint3( fp, point )
2971 prints 2-d, 3-d, or 4-d point as Geomview 3-d coordinates
2972 */
2973 void qh_printpoint3 (FILE *fp, pointT *point) {
2974 int k;
2975 realT p[4];
2976
2977 qh_projectdim3 (point, p);
2978 for (k=0; k < 3; k++)
2979 fprintf (fp, "%8.4g ", p[k]);
2980 fprintf (fp, " # p%d\n", qh_pointid (point));
2981 } /* printpoint3 */
2982
2983 /*----------------------------------------
2984 -printpoints- print pointids for a set of points starting at index
2985 see geom.c
2986 */
2987
2988 /*-<a href="qh-io.htm#TOC"
2989 >-------------------------------</a><a name="printpoints_out">-</a>
2990
2991 qh_printpoints_out( fp, facetlist, facets, printall )
2992 prints vertices, coplanar/inside points, for facets by their point coordinates
2993 allows qh.CDDoutput
2994
2995 notes:
2996 same format as qhull input
2997 if no coplanar/interior points,
2998 same order as qh_printextremes
2999 */
3000 void qh_printpoints_out (FILE *fp, facetT *facetlist, setT *facets, int printall) {
3001 int allpoints= qh num_points + qh_setsize (qh other_points);
3002 int numpoints=0, point_i, point_n;
3003 setT *vertices, *points;
3004 facetT *facet, **facetp;
3005 pointT *point, **pointp;
3006 vertexT *vertex, **vertexp;
3007 int id;
3008
3009 points= qh_settemp (allpoints);
3010 qh_setzero (points, 0, allpoints);
3011 vertices= qh_facetvertices (facetlist, facets, printall);
3012 FOREACHvertex_(vertices) {
3013 id= qh_pointid (vertex->point);
3014 if (id >= 0)
3015 SETelem_(points, id)= vertex->point;
3016 }
3017 if (qh KEEPinside || qh KEEPcoplanar || qh KEEPnearinside) {
3018 FORALLfacet_(facetlist) {
3019 if (!printall && qh_skipfacet(facet))
3020 continue;
3021 FOREACHpoint_(facet->coplanarset) {
3022 id= qh_pointid (point);
3023 if (id >= 0)
3024 SETelem_(points, id)= point;
3025 }
3026 }
3027 FOREACHfacet_(facets) {
3028 if (!printall && qh_skipfacet(facet))
3029 continue;
3030 FOREACHpoint_(facet->coplanarset) {
3031 id= qh_pointid (point);
3032 if (id >= 0)
3033 SETelem_(points, id)= point;
3034 }
3035 }
3036 }
3037 qh_settempfree (&vertices);
3038 FOREACHpoint_i_(points) {
3039 if (point)
3040 numpoints++;
3041 }
3042 if (qh CDDoutput)
3043 fprintf (fp, "%s | %s\nbegin\n%d %d real\n", qh rbox_command,
3044 qh qhull_command, numpoints, qh hull_dim + 1);
3045 else
3046 fprintf (fp, "%d\n%d\n", qh hull_dim, numpoints);
3047 FOREACHpoint_i_(points) {
3048 if (point) {
3049 if (qh CDDoutput)
3050 fprintf (fp, "1 ");
3051 qh_printpoint (fp, NULL, point);
3052 }
3053 }
3054 if (qh CDDoutput)
3055 fprintf (fp, "end\n");
3056 qh_settempfree (&points);
3057 } /* printpoints_out */
3058
3059
3060 /*-<a href="qh-io.htm#TOC"
3061 >-------------------------------</a><a name="printpointvect">-</a>
3062
3063 qh_printpointvect( fp, point, normal, center, radius, color )
3064 prints a 2-d, 3-d, or 4-d point as 3-d VECT's relative to normal or to center point
3065 */
3066 void qh_printpointvect (FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius, realT color[3]) {
3067 realT diff[4], pointA[4];
3068 int k;
3069
3070 for (k= qh hull_dim; k--; ) {
3071 if (center)
3072 diff[k]= point[k]-center[k];
3073 else if (normal)
3074 diff[k]= normal[k];
3075 else
3076 diff[k]= 0;
3077 }
3078 if (center)
3079 qh_normalize2 (diff, qh hull_dim, True, NULL, NULL);
3080 for (k= qh hull_dim; k--; )
3081 pointA[k]= point[k]+diff[k] * radius;
3082 qh_printline3geom (fp, point, pointA, color);
3083 } /* printpointvect */
3084
3085 /*-<a href="qh-io.htm#TOC"
3086 >-------------------------------</a><a name="printpointvect2">-</a>
3087
3088 qh_printpointvect2( fp, point, normal, center, radius )
3089 prints a 2-d, 3-d, or 4-d point as 2 3-d VECT's for an imprecise point
3090 */
3091 void qh_printpointvect2 (FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius) {
3092 realT red[3]={1, 0, 0}, yellow[3]={1, 1, 0};
3093
3094 qh_printpointvect (fp, point, normal, center, radius, red);
3095 qh_printpointvect (fp, point, normal, center, -radius, yellow);
3096 } /* printpointvect2 */
3097
3098 /*-<a href="qh-io.htm#TOC"
3099 >-------------------------------</a><a name="printridge">-</a>
3100
3101 qh_printridge( fp, ridge )
3102 prints the information in a ridge
3103
3104 notes:
3105 for qh_printfacetridges()
3106 */
3107 void qh_printridge(FILE *fp, ridgeT *ridge) {
3108
3109 fprintf(fp, " - r%d", ridge->id);
3110 if (ridge->tested)
3111 fprintf (fp, " tested");
3112 if (ridge->nonconvex)
3113 fprintf (fp, " nonconvex");
3114 fprintf (fp, "\n");
3115 qh_printvertices (fp, " vertices:", ridge->vertices);
3116 if (ridge->top && ridge->bottom)
3117 fprintf(fp, " between f%d and f%d\n",
3118 ridge->top->id, ridge->bottom->id);
3119 } /* printridge */
3120
3121 /*-<a href="qh-io.htm#TOC"
3122 >-------------------------------</a><a name="printspheres">-</a>
3123
3124 qh_printspheres( fp, vertices, radius )
3125 prints 3-d vertices as OFF spheres
3126
3127 notes:
3128 inflated octahedron from Stuart Levy earth/mksphere2
3129 */
3130 void qh_printspheres(FILE *fp, setT *vertices, realT radius) {
3131 vertexT *vertex, **vertexp;
3132
3133 qh printoutnum++;
3134 fprintf (fp, "{appearance {-edge -normal normscale 0} {\n\
3135 INST geom {define vsphere OFF\n\
3136 18 32 48\n\
3137 \n\
3138 0 0 1\n\
3139 1 0 0\n\
3140 0 1 0\n\
3141 -1 0 0\n\
3142 0 -1 0\n\
3143 0 0 -1\n\
3144 0.707107 0 0.707107\n\
3145 0 -0.707107 0.707107\n\
3146 0.707107 -0.707107 0\n\
3147 -0.707107 0 0.707107\n\
3148 -0.707107 -0.707107 0\n\
3149 0 0.707107 0.707107\n\
3150 -0.707107 0.707107 0\n\
3151 0.707107 0.707107 0\n\
3152 0.707107 0 -0.707107\n\
3153 0 0.707107 -0.707107\n\
3154 -0.707107 0 -0.707107\n\
3155 0 -0.707107 -0.707107\n\
3156 \n\
3157 3 0 6 11\n\
3158 3 0 7 6 \n\
3159 3 0 9 7 \n\
3160 3 0 11 9\n\
3161 3 1 6 8 \n\
3162 3 1 8 14\n\
3163 3 1 13 6\n\
3164 3 1 14 13\n\
3165 3 2 11 13\n\
3166 3 2 12 11\n\
3167 3 2 13 15\n\
3168 3 2 15 12\n\
3169 3 3 9 12\n\
3170 3 3 10 9\n\
3171 3 3 12 16\n\
3172 3 3 16 10\n\
3173 3 4 7 10\n\
3174 3 4 8 7\n\
3175 3 4 10 17\n\
3176 3 4 17 8\n\
3177 3 5 14 17\n\
3178 3 5 15 14\n\
3179 3 5 16 15\n\
3180 3 5 17 16\n\
3181 3 6 13 11\n\
3182 3 7 8 6\n\
3183 3 9 10 7\n\
3184 3 11 12 9\n\
3185 3 14 8 17\n\
3186 3 15 13 14\n\
3187 3 16 12 15\n\
3188 3 17 10 16\n} transforms { TLIST\n");
3189 FOREACHvertex_(vertices) {
3190 fprintf(fp, "%8.4g 0 0 0 # v%d\n 0 %8.4g 0 0\n0 0 %8.4g 0\n",
3191 radius, vertex->id, radius, radius);
3192 qh_printpoint3 (fp, vertex->point);
3193 fprintf (fp, "1\n");
3194 }
3195 fprintf (fp, "}}}\n");
3196 } /* printspheres */
3197
3198
3199 /*----------------------------------------------
3200 -printsummary-
3201 see qhull.c
3202 */
3203
3204 /*-<a href="qh-io.htm#TOC"
3205 >-------------------------------</a><a name="printvdiagram">-</a>
3206
3207 qh_printvdiagram( fp, format, facetlist, facets, printall )
3208 print voronoi diagram
3209 # of pairs of input sites
3210 #indices site1 site2 vertex1 ...
3211
3212 sites indexed by input point id
3213 point 0 is the first input point
3214 vertices indexed by 'o' and 'p' order
3215 vertex 0 is the 'vertex-at-infinity'
3216 vertex 1 is the first Voronoi vertex
3217
3218 see:
3219 qh_printvoronoi()
3220 qh_eachvoronoi_all()
3221
3222 notes:
3223 if all facets are upperdelaunay,
3224 prints upper hull (furthest-site Voronoi diagram)
3225 */
3226 void qh_printvdiagram (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
3227 setT *vertices;
3228 int totcount, numcenters;
3229 boolT islower;
3230 qh_RIDGE innerouter= qh_RIDGEall;
3231 printvridgeT printvridge= NULL;
3232
3233 if (format == qh_PRINTvertices) {
3234 innerouter= qh_RIDGEall;
3235 printvridge= qh_printvridge;
3236 }else if (format == qh_PRINTinner) {
3237 innerouter= qh_RIDGEinner;
3238 printvridge= qh_printvnorm;
3239 }else if (format == qh_PRINTouter) {
3240 innerouter= qh_RIDGEouter;
3241 printvridge= qh_printvnorm;
3242 }else {
3243 fprintf(qh ferr, "qh_printvdiagram: unknown print format %d.\n", format);
3244 qh_errexit (qh_ERRinput, NULL, NULL);
3245 }
3246 vertices= qh_markvoronoi (facetlist, facets, printall, &islower, &numcenters);
3247 totcount= qh_printvdiagram2 (NULL, NULL, vertices, innerouter, False);
3248 fprintf (fp, "%d\n", totcount);
3249 totcount= qh_printvdiagram2 (fp, printvridge, vertices, innerouter, True /* inorder*/);
3250 qh_settempfree (&vertices);
3251 #if 0
3252 /* for testing qh_eachvoronoi_all */
3253 fprintf (fp, "\n");
3254 totcount= qh_eachvoronoi_all(fp, printvridge, qh UPPERdelaunay, innerouter, True /* inorder*/);
3255 fprintf (fp, "%d\n", totcount);
3256 #endif
3257 } /* printvdiagram */
3258
3259 /*-<a href="qh-io.htm#TOC"
3260 >-------------------------------</a><a name="printvdiagram2">-</a>
3261
3262 qh_printvdiagram2( fp, printvridge, vertices, innerouter, inorder )
3263 visit all pairs of input sites (vertices) for selected Voronoi vertices
3264 vertices may include NULLs
3265
3266 innerouter:
3267 qh_RIDGEall print inner ridges (bounded) and outer ridges (unbounded)
3268 qh_RIDGEinner print only inner ridges
3269 qh_RIDGEouter print only outer ridges
3270
3271 inorder:
3272 print 3-d Voronoi vertices in order
3273
3274 assumes:
3275 qh_markvoronoi marked facet->visitid for Voronoi vertices
3276 all facet->seen= False
3277 all facet->seen2= True
3278
3279 returns:
3280 total number of Voronoi ridges
3281 if printvridge,
3282 calls printvridge( fp, vertex, vertexA, centers) for each ridge
3283 [see qh_eachvoronoi()]
3284
3285 see:
3286 qh_eachvoronoi_all()
3287 */
3288 int qh_printvdiagram2 (FILE *fp, printvridgeT printvridge, setT *vertices, qh_RIDGE innerouter, boolT inorder) {
3289 int totcount= 0;
3290 int vertex_i, vertex_n;
3291 vertexT *vertex;
3292
3293 FORALLvertices
3294 vertex->seen= False;
3295 FOREACHvertex_i_(vertices) {
3296 if (vertex) {
3297 if (qh GOODvertex > 0 && qh_pointid(vertex->point)+1 != qh GOODvertex)
3298 continue;
3299 totcount += qh_eachvoronoi (fp, printvridge, vertex, !qh_ALL, innerouter, inorder);
3300 }
3301 }
3302 return totcount;
3303 } /* printvdiagram2 */
3304
3305 /*-<a href="qh-io.htm#TOC"
3306 >-------------------------------</a><a name="printvertex">-</a>
3307
3308 qh_printvertex( fp, vertex )
3309 prints the information in a vertex
3310 */
3311 void qh_printvertex(FILE *fp, vertexT *vertex) {
3312 pointT *point;
3313 int k, count= 0;
3314 facetT *neighbor, **neighborp;
3315 realT r; /*bug fix*/
3316
3317 if (!vertex) {
3318 fprintf (fp, " NULLvertex\n");
3319 return;
3320 }
3321 fprintf(fp, "- p%d (v%d):", qh_pointid(vertex->point), vertex->id);
3322 point= vertex->point;
3323 if (point) {
3324 for(k= qh hull_dim; k--; ) {
3325 r= *point++;
3326 fprintf(fp, " %5.2g", r);
3327 }
3328 }
3329 if (vertex->deleted)
3330 fprintf(fp, " deleted");
3331 if (vertex->delridge)
3332 fprintf (fp, " ridgedeleted");
3333 fprintf(fp, "\n");
3334 if (vertex->neighbors) {
3335 fprintf(fp, " neighbors:");
3336 FOREACHneighbor_(vertex) {
3337 if (++count % 100 == 0)
3338 fprintf (fp, "\n ");
3339 fprintf(fp, " f%d", neighbor->id);
3340 }
3341 fprintf(fp, "\n");
3342 }
3343 } /* printvertex */
3344
3345
3346 /*-<a href="qh-io.htm#TOC"
3347 >-------------------------------</a><a name="printvertexlist">-</a>
3348
3349 qh_printvertexlist( fp, string, facetlist, facets, printall )
3350 prints vertices used by a facetlist or facet set
3351 tests qh_skipfacet() if !printall
3352 */
3353 void qh_printvertexlist (FILE *fp, char* string, facetT *facetlist,
3354 setT *facets, boolT printall) {
3355 vertexT *vertex, **vertexp;
3356 setT *vertices;
3357
3358 vertices= qh_facetvertices (facetlist, facets, printall);
3359 fputs (string, fp);
3360 FOREACHvertex_(vertices)
3361 qh_printvertex(fp, vertex);
3362 qh_settempfree (&vertices);
3363 } /* printvertexlist */
3364
3365
3366 /*-<a href="qh-io.htm#TOC"
3367 >-------------------------------</a><a name="printvertices">-</a>
3368
3369 qh_printvertices( fp, string, vertices )
3370 prints vertices in a set
3371 */
3372 void qh_printvertices(FILE *fp, char* string, setT *vertices) {
3373 vertexT *vertex, **vertexp;
3374
3375 fputs (string, fp);
3376 FOREACHvertex_(vertices)
3377 fprintf (fp, " p%d (v%d)", qh_pointid(vertex->point), vertex->id);
3378 fprintf(fp, "\n");
3379 } /* printvertices */
3380
3381 /*-<a href="qh-io.htm#TOC"
3382 >-------------------------------</a><a name="printvneighbors">-</a>
3383
3384 qh_printvneighbors( fp, facetlist, facets, printall )
3385 print vertex neighbors of vertices in facetlist and facets ('FN')
3386
3387 notes:
3388 qh_countfacets clears facet->visitid for non-printed facets
3389
3390 design:
3391 collect facet count and related statistics
3392 if necessary, build neighbor sets for each vertex
3393 collect vertices in facetlist and facets
3394 build a point array for point->vertex and point->coplanar facet
3395 for each point
3396 list vertex neighbors or coplanar facet
3397 */
3398 void qh_printvneighbors (FILE *fp, facetT* facetlist, setT *facets, boolT printall) {
3399 int numfacets, numsimplicial, numridges, totneighbors, numneighbors, numcoplanars, numtricoplanars;
3400 setT *vertices, *vertex_points, *coplanar_points;
3401 int numpoints= qh num_points + qh_setsize (qh other_points);
3402 vertexT *vertex, **vertexp;
3403 int vertex_i, vertex_n;
3404 facetT *facet, **facetp, *neighbor, **neighborp;
3405 pointT *point, **pointp;
3406
3407 qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial,
3408 &totneighbors, &numridges, &numcoplanars, &numtricoplanars); /* sets facet->visitid */
3409 fprintf (fp, "%d\n", numpoints);
3410 qh_vertexneighbors();
3411 vertices= qh_facetvertices (facetlist, facets, printall);
3412 vertex_points= qh_settemp (numpoints);
3413 coplanar_points= qh_settemp (numpoints);
3414 qh_setzero (vertex_points, 0, numpoints);
3415 qh_setzero (coplanar_points, 0, numpoints);
3416 FOREACHvertex_(vertices)
3417 qh_point_add (vertex_points, vertex->point, vertex);
3418 FORALLfacet_(facetlist) {
3419 FOREACHpoint_(facet->coplanarset)
3420 qh_point_add (coplanar_points, point, facet);
3421 }
3422 FOREACHfacet_(facets) {
3423 FOREACHpoint_(facet->coplanarset)
3424 qh_point_add (coplanar_points, point, facet);
3425 }
3426 FOREACHvertex_i_(vertex_points) {
3427 if (vertex) {
3428 numneighbors= qh_setsize (vertex->neighbors);
3429 fprintf (fp, "%d", numneighbors);
3430 if (qh hull_dim == 3)
3431 qh_order_vertexneighbors (vertex);
3432 else if (qh hull_dim >= 4)
3433 qsort (SETaddr_(vertex->neighbors, facetT), numneighbors,
3434 sizeof (facetT *), qh_compare_facetvisit);
3435 FOREACHneighbor_(vertex)
3436 fprintf (fp, " %d",
3437 neighbor->visitid ? neighbor->visitid - 1 : - neighbor->id);
3438 fprintf (fp, "\n");
3439 }else if ((facet= SETelemt_(coplanar_points, vertex_i, facetT)))
3440 fprintf (fp, "1 %d\n",
3441 facet->visitid ? facet->visitid - 1 : - facet->id);
3442 else
3443 fprintf (fp, "0\n");
3444 }
3445 qh_settempfree (&coplanar_points);
3446 qh_settempfree (&vertex_points);
3447 qh_settempfree (&vertices);
3448 } /* printvneighbors */
3449
3450 /*-<a href="qh-io.htm#TOC"
3451 >-------------------------------</a><a name="printvoronoi">-</a>
3452
3453 qh_printvoronoi( fp, format, facetlist, facets, printall )
3454 print voronoi diagram in 'o' or 'G' format
3455 for 'o' format
3456 prints voronoi centers for each facet and for infinity
3457 for each vertex, lists ids of printed facets or infinity
3458 assumes facetlist and facets are disjoint
3459 for 'G' format
3460 prints an OFF object
3461 adds a 0 coordinate to center
3462 prints infinity but does not list in vertices
3463
3464 see:
3465 qh_printvdiagram()
3466
3467 notes:
3468 if 'o',
3469 prints a line for each point except "at-infinity"
3470 if all facets are upperdelaunay,
3471 reverses lower and upper hull
3472 */
3473 void qh_printvoronoi (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
3474 int k, numcenters, numvertices= 0, numneighbors, numinf, vid=1, vertex_i, vertex_n;
3475 facetT *facet, **facetp, *neighbor, **neighborp;
3476 setT *vertices;
3477 vertexT *vertex;
3478 boolT islower;
3479 unsigned int numfacets= (unsigned int) qh num_facets;
3480
3481 vertices= qh_markvoronoi (facetlist, facets, printall, &islower, &numcenters);
3482 FOREACHvertex_i_(vertices) {
3483 if (vertex) {
3484 numvertices++;
3485 numneighbors = numinf = 0;
3486 FOREACHneighbor_(vertex) {
3487 if (neighbor->visitid == 0)
3488 numinf= 1;
3489 else if (neighbor->visitid < numfacets)
3490 numneighbors++;
3491 }
3492 if (numinf && !numneighbors) {
3493 SETelem_(vertices, vertex_i)= NULL;
3494 numvertices--;
3495 }
3496 }
3497 }
3498 if (format == qh_PRINTgeom)
3499 fprintf (fp, "{appearance {+edge -face} OFF %d %d 1 # Voronoi centers and cells\n",
3500 numcenters, numvertices);
3501 else
3502 fprintf (fp, "%d\n%d %d 1\n", qh hull_dim-1, numcenters, qh_setsize(vertices));
3503 if (format == qh_PRINTgeom) {
3504 for (k= qh hull_dim-1; k--; )
3505 fprintf (fp, qh_REAL_1, 0.0);
3506 fprintf (fp, " 0 # infinity not used\n");
3507 }else {
3508 for (k= qh hull_dim-1; k--; )
3509 fprintf (fp, qh_REAL_1, qh_INFINITE);
3510 fprintf (fp, "\n");
3511 }
3512 FORALLfacet_(facetlist) {
3513 if (facet->visitid && facet->visitid < numfacets) {
3514 if (format == qh_PRINTgeom)
3515 fprintf (fp, "# %d f%d\n", vid++, facet->id);
3516 qh_printcenter (fp, format, NULL, facet);
3517 }
3518 }
3519 FOREACHfacet_(facets) {
3520 if (facet->visitid && facet->visitid < numfacets) {
3521 if (format == qh_PRINTgeom)
3522 fprintf (fp, "# %d f%d\n", vid++, facet->id);
3523 qh_printcenter (fp, format, NULL, facet);
3524 }
3525 }
3526 FOREACHvertex_i_(vertices) {
3527 numneighbors= 0;
3528 numinf=0;
3529 if (vertex) {
3530 if (qh hull_dim == 3)
3531 qh_order_vertexneighbors(vertex);
3532 else if (qh hull_dim >= 4)
3533 qsort (SETaddr_(vertex->neighbors, vertexT),
3534 qh_setsize (vertex->neighbors),
3535 sizeof (facetT *), qh_compare_facetvisit);
3536 FOREACHneighbor_(vertex) {
3537 if (neighbor->visitid == 0)
3538 numinf= 1;
3539 else if (neighbor->visitid < numfacets)
3540 numneighbors++;
3541 }
3542 }
3543 if (format == qh_PRINTgeom) {
3544 if (vertex) {
3545 fprintf (fp, "%d", numneighbors);
3546 if (vertex) {
3547 FOREACHneighbor_(vertex) {
3548 if (neighbor->visitid && neighbor->visitid < numfacets)
3549 fprintf (fp, " %d", neighbor->visitid);
3550 }
3551 }
3552 fprintf (fp, " # p%d (v%d)\n", vertex_i, vertex->id);
3553 }else
3554 fprintf (fp, " # p%d is coplanar or isolated\n", vertex_i);
3555 }else {
3556 if (numinf)
3557 numneighbors++;
3558 fprintf (fp, "%d", numneighbors);
3559 if (vertex) {
3560 FOREACHneighbor_(vertex) {
3561 if (neighbor->visitid == 0) {
3562 if (numinf) {
3563 numinf= 0;
3564 fprintf (fp, " %d", neighbor->visitid);
3565 }
3566 }else if (neighbor->visitid < numfacets)
3567 fprintf (fp, " %d", neighbor->visitid);
3568 }
3569 }
3570 fprintf (fp, "\n");
3571 }
3572 }
3573 if (format == qh_PRINTgeom)
3574 fprintf (fp, "}\n");
3575 qh_settempfree (&vertices);
3576 } /* printvoronoi */
3577
3578 /*-<a href="qh-io.htm#TOC"
3579 >-------------------------------</a><a name="printvnorm">-</a>
3580
3581 qh_printvnorm( fp, vertex, vertexA, centers, unbounded )
3582 print one separating plane of the Voronoi diagram for a pair of input sites
3583 unbounded==True if centers includes vertex-at-infinity
3584
3585 assumes:
3586 qh_ASvoronoi and qh_vertexneighbors() already set
3587
3588 see:
3589 qh_printvdiagram()
3590 qh_eachvoronoi()
3591 */
3592 void qh_printvnorm (FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {
3593 pointT *normal;
3594 realT offset;
3595 int k;
3596
3597 normal= qh_detvnorm (vertex, vertexA, centers, &offset);
3598 fprintf (fp, "%d %d %d ",
3599 2+qh hull_dim, qh_pointid (vertex->point), qh_pointid (vertexA->point));
3600 for (k= 0; k< qh hull_dim-1; k++)
3601 fprintf (fp, qh_REAL_1, normal[k]);
3602 fprintf (fp, qh_REAL_1, offset);
3603 fprintf (fp, "\n");
3604 } /* printvnorm */
3605
3606 /*-<a href="qh-io.htm#TOC"
3607 >-------------------------------</a><a name="printvridge">-</a>
3608
3609 qh_printvridge( fp, vertex, vertexA, centers, unbounded )
3610 print one ridge of the Voronoi diagram for a pair of input sites
3611 unbounded==True if centers includes vertex-at-infinity
3612
3613 see:
3614 qh_printvdiagram()
3615
3616 notes:
3617 the user may use a different function
3618 */
3619 void qh_printvridge (FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {
3620 facetT *facet, **facetp;
3621
3622 fprintf (fp, "%d %d %d", qh_setsize (centers)+2,
3623 qh_pointid (vertex->point), qh_pointid (vertexA->point));
3624 FOREACHfacet_(centers)
3625 fprintf (fp, " %d", facet->visitid);
3626 fprintf (fp, "\n");
3627 } /* printvridge */
3628
3629 /*-<a href="qh-io.htm#TOC"
3630 >-------------------------------</a><a name="projectdim3">-</a>
3631
3632 qh_projectdim3( source, destination )
3633 project 2-d 3-d or 4-d point to a 3-d point
3634 uses qh.DROPdim and qh.hull_dim
3635 source and destination may be the same
3636
3637 notes:
3638 allocate 4 elements to destination just in case
3639 */
3640 void qh_projectdim3 (pointT *source, pointT *destination) {
3641 int i,k;
3642
3643 for (k= 0, i=0; k < qh hull_dim; k++) {
3644 if (qh hull_dim == 4) {
3645 if (k != qh DROPdim)
3646 destination[i++]= source[k];
3647 }else if (k == qh DROPdim)
3648 destination[i++]= 0;
3649 else
3650 destination[i++]= source[k];
3651 }
3652 while (i < 3)
3653 destination[i++]= 0.0;
3654 } /* projectdim3 */
3655
3656 /*-<a href="qh-io.htm#TOC"
3657 >-------------------------------</a><a name="readfeasible">-</a>
3658
3659 qh_readfeasible( dim, remainder )
3660 read feasible point from remainder string and qh.fin
3661
3662 returns:
3663 number of lines read from qh.fin
3664 sets qh.FEASIBLEpoint with malloc'd coordinates
3665
3666 notes:
3667 checks for qh.HALFspace
3668 assumes dim > 1
3669
3670 see:
3671 qh_setfeasible
3672 */
3673 int qh_readfeasible (int dim, char *remainder) {
3674 boolT isfirst= True;
3675 int linecount= 0, tokcount= 0;
3676 char *s, *t, firstline[qh_MAXfirst+1];
3677 coordT *coords, value;
3678
3679 if (!qh HALFspace) {
3680 fprintf (qh ferr, "qhull input error: feasible point (dim 1 coords) is only valid for halfspace intersection\n");
3681 qh_errexit (qh_ERRinput, NULL, NULL);
3682 }
3683 if (qh feasible_string)
3684 fprintf (qh ferr, "qhull input warning: feasible point (dim 1 coords) overrides 'Hn,n,n' feasible point for halfspace intersection\n");
3685 if (!(qh feasible_point= (coordT*)malloc (dim* sizeof(coordT)))) {
3686 fprintf(qh ferr, "qhull error: insufficient memory for feasible point\n");
3687 qh_errexit(qh_ERRmem, NULL, NULL);
3688 }
3689 coords= qh feasible_point;
3690 while ((s= (isfirst ? remainder : fgets(firstline, qh_MAXfirst, qh fin)))) {
3691 if (isfirst)
3692 isfirst= False;
3693 else
3694 linecount++;
3695 while (*s) {
3696 while (isspace(*s))
3697 s++;
3698 value= qh_strtod (s, &t);
3699 if (s == t)
3700 break;
3701 s= t;
3702 *(coords++)= value;
3703 if (++tokcount == dim) {
3704 while (isspace (*s))
3705 s++;
3706 qh_strtod (s, &t);
3707 if (s != t) {
3708 fprintf (qh ferr, "qhull input error: coordinates for feasible point do not finish out the line: %s\n",
3709 s);
3710 qh_errexit (qh_ERRinput, NULL, NULL);
3711 }
3712 return linecount;
3713 }
3714 }
3715 }
3716 fprintf (qh ferr, "qhull input error: only %d coordinates. Could not read %d-d feasible point.\n",
3717 tokcount, dim);
3718 qh_errexit (qh_ERRinput, NULL, NULL);
3719 return 0;
3720 } /* readfeasible */
3721
3722 /*-<a href="qh-io.htm#TOC"
3723 >-------------------------------</a><a name="readpoints">-</a>
3724
3725 qh_readpoints( numpoints, dimension, ismalloc )
3726 read points from qh.fin into qh.first_point, qh.num_points
3727 qh.fin is lines of coordinates, one per vertex, first line number of points
3728 if 'rbox D4',
3729 gives message
3730 if qh.ATinfinity,
3731 adds point-at-infinity for Delaunay triangulations
3732
3733 returns:
3734 number of points, array of point coordinates, dimension, ismalloc True
3735 if qh.DELAUNAY & !qh.PROJECTinput, projects points to paraboloid
3736 and clears qh.PROJECTdelaunay
3737 if qh.HALFspace, reads optional feasible point, reads halfspaces,
3738 converts to dual.
3739
3740 for feasible point in "cdd format" in 3-d:
3741 3 1
3742 coordinates
3743 comments
3744 begin
3745 n 4 real/integer
3746 ...
3747 end
3748
3749 notes:
3750 dimension will change in qh_initqhull_globals if qh.PROJECTinput
3751 uses malloc() since qh_mem not initialized
3752 FIXUP: this routine needs rewriting
3753 */
3754 coordT *qh_readpoints(int *numpoints, int *dimension, boolT *ismalloc) {
3755 coordT *points, *coords, *infinity= NULL;
3756 realT paraboloid, maxboloid= -REALmax, value;
3757 realT *coordp= NULL, *offsetp= NULL, *normalp= NULL;
3758 char *s, *t, firstline[qh_MAXfirst+1];
3759 int diminput=0, numinput=0, dimfeasible= 0, newnum, k, tempi;
3760 int firsttext=0, firstshort=0, firstlong=0, firstpoint=0;
3761 int tokcount= 0, linecount=0, maxcount, coordcount=0;
3762 boolT islong, isfirst= True, wasbegin= False;
3763 boolT isdelaunay= qh DELAUNAY && !qh PROJECTinput;
3764
3765 if (qh CDDinput) {
3766 while ((s= fgets(firstline, qh_MAXfirst, qh fin))) {
3767 linecount++;
3768 if (qh HALFspace && linecount == 1 && isdigit(*s)) {
3769 dimfeasible= qh_strtol (s, &s);
3770 while (isspace(*s))
3771 s++;
3772 if (qh_strtol (s, &s) == 1)
3773 linecount += qh_readfeasible (dimfeasible, s);
3774 else
3775 dimfeasible= 0;
3776 }else if (!memcmp (firstline, "begin", 5) || !memcmp (firstline, "BEGIN", 5))
3777 break;
3778 else if (!*qh rbox_command)
3779 strncat(qh rbox_command, s, sizeof (qh rbox_command)-1);
3780 }
3781 if (!s) {
3782 fprintf (qh ferr, "qhull input error: missing \"begin\" for cdd-formated input\n");
3783 qh_errexit (qh_ERRinput, NULL, NULL);
3784 }
3785 }
3786 while(!numinput && (s= fgets(firstline, qh_MAXfirst, qh fin))) {
3787 linecount++;
3788 if (!memcmp (s, "begin", 5) || !memcmp (s, "BEGIN", 5))
3789 wasbegin= True;
3790 while (*s) {
3791 while (isspace(*s))
3792 s++;
3793 if (!*s)
3794 break;
3795 if (!isdigit(*s)) {
3796 if (!*qh rbox_command) {
3797 strncat(qh rbox_command, s, sizeof (qh rbox_command)-1);
3798 firsttext= linecount;
3799 }
3800 break;
3801 }
3802 if (!diminput)
3803 diminput= qh_strtol (s, &s);
3804 else {
3805 numinput= qh_strtol (s, &s);
3806 if (numinput == 1 && diminput >= 2 && qh HALFspace && !qh CDDinput) {
3807 linecount += qh_readfeasible (diminput, s); /* checks if ok */
3808 dimfeasible= diminput;
3809 diminput= numinput= 0;
3810 }else
3811 break;
3812 }
3813 }
3814 }
3815 if (!s) {
3816 fprintf(qh ferr, "qhull input error: short input file. Did not find dimension and number of points\n");
3817 qh_errexit(qh_ERRinput, NULL, NULL);
3818 }
3819 if (diminput > numinput) {
3820 tempi= diminput; /* exchange dim and n, e.g., for cdd input format */
3821 diminput= numinput;
3822 numinput= tempi;
3823 }
3824 if (diminput < 2) {
3825 fprintf(qh ferr,"qhull input error: dimension %d (first number) should be at least 2\n",
3826 diminput);
3827 qh_errexit(qh_ERRinput, NULL, NULL);
3828 }
3829 if (isdelaunay) {
3830 qh PROJECTdelaunay= False;
3831 if (qh CDDinput)
3832 *dimension= diminput;
3833 else
3834 *dimension= diminput+1;
3835 *numpoints= numinput;
3836 if (qh ATinfinity)
3837 (*numpoints)++;
3838 }else if (qh HALFspace) {
3839 *dimension= diminput - 1;
3840 *numpoints= numinput;
3841 if (diminput < 3) {
3842 fprintf(qh ferr,"qhull input error: dimension %d (first number, includes offset) should be at least 3 for halfspaces\n",
3843 diminput);
3844 qh_errexit(qh_ERRinput, NULL, NULL);
3845 }
3846 if (dimfeasible) {
3847 if (dimfeasible != *dimension) {
3848 fprintf(qh ferr,"qhull input error: dimension %d of feasible point is not one less than dimension %d for halfspaces\n",
3849 dimfeasible, diminput);
3850 qh_errexit(qh_ERRinput, NULL, NULL);
3851 }
3852 }else
3853 qh_setfeasible (*dimension);
3854 }else {
3855 if (qh CDDinput)
3856 *dimension= diminput-1;
3857 else
3858 *dimension= diminput;
3859 *numpoints= numinput;
3860 }
3861 qh normal_size= *dimension * sizeof(coordT); /* for tracing with qh_printpoint */
3862 if (qh HALFspace) {
3863 qh half_space= coordp= (coordT*) malloc (qh normal_size + sizeof(coordT));
3864 if (qh CDDinput) {
3865 offsetp= qh half_space;
3866 normalp= offsetp + 1;
3867 }else {
3868 normalp= qh half_space;
3869 offsetp= normalp + *dimension;
3870 }
3871 }
3872 qh maxline= diminput * (qh_REALdigits + 5);
3873 maximize_(qh maxline, 500);
3874 qh line= (char*)malloc ((qh maxline+1) * sizeof (char));
3875 *ismalloc= True; /* use malloc since memory not setup */
3876 coords= points= qh temp_malloc=
3877 (coordT*)malloc((*numpoints)*(*dimension)*sizeof(coordT));
3878 if (!coords || !qh line || (qh HALFspace && !qh half_space)) {
3879 fprintf(qh ferr, "qhull error: insufficient memory to read %d points\n",
3880 numinput);
3881 qh_errexit(qh_ERRmem, NULL, NULL);
3882 }
3883 if (isdelaunay && qh ATinfinity) {
3884 infinity= points + numinput * (*dimension);
3885 for (k= (*dimension) - 1; k--; )
3886 infinity[k]= 0.0;
3887 }
3888 maxcount= numinput * diminput;
3889 paraboloid= 0.0;
3890 while ((s= (isfirst ? s : fgets(qh line, qh maxline, qh fin)))) {
3891 if (!isfirst) {
3892 linecount++;
3893 if (*s == 'e' || *s == 'E') {
3894 if (!memcmp (s, "end", 3) || !memcmp (s, "END", 3)) {
3895 if (qh CDDinput )
3896 break;
3897 else if (wasbegin)
3898 fprintf (qh ferr, "qhull input warning: the input appears to be in cdd format. If so, use 'Fd'\n");
3899 }
3900 }
3901 }
3902 islong= False;
3903 while (*s) {
3904 while (isspace(*s))
3905 s++;
3906 value= qh_strtod (s, &t);
3907 if (s == t) {
3908 if (!*qh rbox_command)
3909 strncat(qh rbox_command, s, sizeof (qh rbox_command)-1);
3910 if (*s && !firsttext)
3911 firsttext= linecount;
3912 if (!islong && !firstshort && coordcount)
3913 firstshort= linecount;
3914 break;
3915 }
3916 if (!firstpoint)
3917 firstpoint= linecount;
3918 s= t;
3919 if (++tokcount > maxcount)
3920 continue;
3921 if (qh HALFspace) {
3922 if (qh CDDinput)
3923 *(coordp++)= -value; /* both coefficients and offset */
3924 else
3925 *(coordp++)= value;
3926 }else {
3927 *(coords++)= value;
3928 if (qh CDDinput && !coordcount) {
3929 if (value != 1.0) {
3930 fprintf (qh ferr, "qhull input error: for cdd format, point at line %d does not start with '1'\n",
3931 linecount);
3932 qh_errexit (qh_ERRinput, NULL, NULL);
3933 }
3934 coords--;
3935 }else if (isdelaunay) {
3936 paraboloid += value * value;
3937 if (qh ATinfinity) {
3938 if (qh CDDinput)
3939 infinity[coordcount-1] += value;
3940 else
3941 infinity[coordcount] += value;
3942 }
3943 }
3944 }
3945 if (++coordcount == diminput) {
3946 coordcount= 0;
3947 if (isdelaunay) {
3948 *(coords++)= paraboloid;
3949 maximize_(maxboloid, paraboloid);
3950 paraboloid= 0.0;
3951 }else if (qh HALFspace) {
3952 if (!qh_sethalfspace (*dimension, coords, &coords, normalp, offsetp, qh feasible_point)) {
3953 fprintf (qh ferr, "The halfspace was on line %d\n", linecount);
3954 if (wasbegin)
3955 fprintf (qh ferr, "The input appears to be in cdd format. If so, you should use option 'Fd'\n");
3956 qh_errexit (qh_ERRinput, NULL, NULL);
3957 }
3958 coordp= qh half_space;
3959 }
3960 while (isspace(*s))
3961 s++;
3962 if (*s) {
3963 islong= True;
3964 if (!firstlong)
3965 firstlong= linecount;
3966 }
3967 }
3968 }
3969 if (!islong && !firstshort && coordcount)
3970 firstshort= linecount;
3971 if (!isfirst && s - qh line >= qh maxline) {
3972 fprintf(qh ferr, "qhull input error: line %d contained more than %d characters\n",
3973 linecount, (int) (s - qh line));
3974 qh_errexit(qh_ERRinput, NULL, NULL);
3975 }
3976 isfirst= False;
3977 }
3978 if (tokcount != maxcount) {
3979 newnum= fmin_(numinput, tokcount/diminput);
3980 fprintf(qh ferr,"\
3981 qhull warning: instead of %d %d-dimensional points, input contains\n\
3982 %d points and %d extra coordinates. Line %d is the first\npoint",
3983 numinput, diminput, tokcount/diminput, tokcount % diminput, firstpoint);
3984 if (firsttext)
3985 fprintf(qh ferr, ", line %d is the first comment", firsttext);
3986 if (firstshort)
3987 fprintf(qh ferr, ", line %d is the first short\nline", firstshort);
3988 if (firstlong)
3989 fprintf(qh ferr, ", line %d is the first long line", firstlong);
3990 fprintf(qh ferr, ". Continue with %d points.\n", newnum);
3991 numinput= newnum;
3992 if (isdelaunay && qh ATinfinity) {
3993 for (k= tokcount % diminput; k--; )
3994 infinity[k] -= *(--coords);
3995 *numpoints= newnum+1;
3996 }else {
3997 coords -= tokcount % diminput;
3998 *numpoints= newnum;
3999 }
4000 }
4001 if (isdelaunay && qh ATinfinity) {
4002 for (k= (*dimension) -1; k--; )
4003 infinity[k] /= numinput;
4004 if (coords == infinity)
4005 coords += (*dimension) -1;
4006 else {
4007 for (k= 0; k < (*dimension) -1; k++)
4008 *(coords++)= infinity[k];
4009 }
4010 *(coords++)= maxboloid * 1.1;
4011 }
4012 if (qh rbox_command[0]) {
4013 qh rbox_command[strlen(qh rbox_command)-1]= '\0';
4014 if (!strcmp (qh rbox_command, "./rbox D4"))
4015 fprintf (qh ferr, "\n\
4016 This is the qhull test case. If any errors or core dumps occur,\n\
4017 recompile qhull with 'make new'. If errors still occur, there is\n\
4018 an incompatibility. You should try a different compiler. You can also\n\
4019 change the choices in user.h. If you discover the source of the problem,\n\
4020 please send mail to qhull_bug@qhull.org.\n\
4021 \n\
4022 Type 'qhull' for a short list of options.\n");
4023 }
4024 free (qh line);
4025 qh line= NULL;
4026 if (qh half_space) {
4027 free (qh half_space);
4028 qh half_space= NULL;
4029 }
4030 qh temp_malloc= NULL;
4031 trace1((qh ferr,"qh_readpoints: read in %d %d-dimensional points\n", numinput, diminput));
4032 return(points);
4033 } /* readpoints */
4034
4035
4036 /*-<a href="qh-io.htm#TOC"
4037 >-------------------------------</a><a name="setfeasible">-</a>
4038
4039 qh_setfeasible( dim )
4040 set qh.FEASIBLEpoint from qh.feasible_string in "n,n,n" or "n n n" format
4041
4042 notes:
4043 "n,n,n" already checked by qh_initflags()
4044 see qh_readfeasible()
4045 */
4046 void qh_setfeasible (int dim) {
4047 int tokcount= 0;
4048 char *s;
4049 coordT *coords, value;
4050
4051 if (!(s= qh feasible_string)) {
4052 fprintf(qh ferr, "\
4053 qhull input error: halfspace intersection needs a feasible point.\n\
4054 Either prepend the input with 1 point or use 'Hn,n,n'. See manual.\n");
4055 qh_errexit (qh_ERRinput, NULL, NULL);
4056 }
4057 if (!(qh feasible_point= (pointT*)malloc (dim* sizeof(coordT)))) {
4058 fprintf(qh ferr, "qhull error: insufficient memory for 'Hn,n,n'\n");
4059 qh_errexit(qh_ERRmem, NULL, NULL);
4060 }
4061 coords= qh feasible_point;
4062 while (*s) {
4063 value= qh_strtod (s, &s);
4064 if (++tokcount > dim) {
4065 fprintf (qh ferr, "qhull input warning: more coordinates for 'H%s' than dimension %d\n",
4066 qh feasible_string, dim);
4067 break;
4068 }
4069 *(coords++)= value;
4070 if (*s)
4071 s++;
4072 }
4073 while (++tokcount <= dim)
4074 *(coords++)= 0.0;
4075 } /* setfeasible */
4076
4077 /*-<a href="qh-io.htm#TOC"
4078 >-------------------------------</a><a name="skipfacet">-</a>
4079
4080 qh_skipfacet( facet )
4081 returns 'True' if this facet is not to be printed
4082
4083 notes:
4084 based on the user provided slice thresholds and 'good' specifications
4085 */
4086 boolT qh_skipfacet(facetT *facet) {
4087 facetT *neighbor, **neighborp;
4088
4089 if (qh PRINTneighbors) {
4090 if (facet->good)
4091 return !qh PRINTgood;
4092 FOREACHneighbor_(facet) {
4093 if (neighbor->good)
4094 return False;
4095 }
4096 return True;
4097 }else if (qh PRINTgood)
4098 return !facet->good;
4099 else if (!facet->normal)
4100 return True;
4101 return (!qh_inthresholds (facet->normal, NULL));
4102 } /* skipfacet */
4103