Skip to content

AFNI/NIfTI Server

Sections
Personal tools
You are here: Home » AFNI » Documentation

Doxygen Source Code Documentation


Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search  

io.c

Go to the documentation of this file.
00001 /*<html><pre>  -<a                             href="qh-io.htm"
00002   >-------------------------------</a><a name="TOP">-</a>
00003 
00004    io.c 
00005    Input/Output routines of qhull application
00006 
00007    see qh-io.htm and io.h
00008 
00009    see user.c for qh_errprint and qh_printfacetlist
00010 
00011    unix.c calls qh_readpoints and qh_produce_output
00012 
00013    unix.c and user.c are the only callers of io.c functions
00014    This allows the user to avoid loading io.o from qhull.a
00015 
00016    copyright (c) 1993-2001 The Geometry Center        
00017 */
00018 
00019 #include "qhull_a.h"
00020 
00021 /*========= -prototypes for internal functions ========= */
00022 
00023 static int qh_compare_facetarea(const void *p1, const void *p2);
00024 static int qh_compare_facetmerge(const void *p1, const void *p2);
00025 static int qh_compare_facetvisit(const void *p1, const void *p2);
00026 int qh_compare_vertexpoint(const void *p1, const void *p2); /* not used */
00027 
00028 /*========= -functions in alphabetical order after qh_produce_output()  =====*/
00029 
00030 /*-<a                             href="qh-io.htm#TOC"
00031   >-------------------------------</a><a name="produce_output">-</a>
00032   
00033   qh_produce_output()
00034     prints out the result of qhull in desired format
00035     if qh.GETarea
00036       computes and prints area and volume
00037     qh.PRINTout[] is an array of output formats
00038 
00039   notes:
00040     prints output in qh.PRINTout order
00041 */
00042 void qh_produce_output(void) {
00043   int i, tempsize= qh_setsize ((setT*)qhmem.tempstack), d_1;
00044 
00045   if (qh VORONOI) {
00046     qh_clearcenters (qh_ASvoronoi);
00047     qh_vertexneighbors();
00048   }
00049   if (qh GETarea)
00050     qh_getarea(qh facet_list);
00051   qh_findgood_all (qh facet_list); 
00052   if (qh KEEParea || qh KEEPmerge || qh KEEPminArea < REALmax/2)
00053     qh_markkeep (qh facet_list);
00054   if (qh PRINTsummary)
00055     qh_printsummary(qh ferr);
00056   else if (qh PRINTout[0] == qh_PRINTnone)
00057     qh_printsummary(qh fout);
00058   for (i= 0; i < qh_PRINTEND; i++)
00059     qh_printfacets (qh fout, qh PRINTout[i], qh facet_list, NULL, !qh_ALL);
00060   qh_allstatistics();
00061   if (qh PRINTprecision && !qh MERGING && (qh JOGGLEmax > REALmax/2 || qh RERUN))
00062     qh_printstats (qh ferr, qhstat precision, NULL);
00063   if (qh VERIFYoutput && (zzval_(Zridge) > 0 || zzval_(Zridgemid) > 0)) 
00064     qh_printstats (qh ferr, qhstat vridges, NULL);
00065   if (qh PRINTstatistics) {
00066     qh_collectstatistics();
00067     qh_printstatistics(qh ferr, "");
00068     qh_memstatistics (qh ferr);
00069     d_1= sizeof(setT) + (qh hull_dim - 1) * SETelemsize;
00070     fprintf(qh ferr, "\
00071     size in bytes: merge %d ridge %d vertex %d facet %d\n\
00072          normal %d ridge vertices %d facet vertices or neighbors %d\n",
00073             sizeof(mergeT), sizeof(ridgeT),
00074             sizeof(vertexT), sizeof(facetT),
00075             qh normal_size, d_1, d_1 + SETelemsize);
00076   }
00077   if (qh_setsize ((setT*)qhmem.tempstack) != tempsize) {
00078     fprintf (qh ferr, "qhull internal error (qh_produce_output): temporary sets not empty (%d)\n",
00079              qh_setsize ((setT*)qhmem.tempstack));
00080     qh_errexit (qh_ERRqhull, NULL, NULL);
00081   }
00082 } /* produce_output */
00083 
00084 
00085 /*-<a                             href="qh-io.htm#TOC"
00086   >-------------------------------</a><a name="dfacet">-</a>
00087   
00088   dfacet( id )
00089     print facet by id, for debugging
00090 
00091 */
00092 void dfacet (unsigned id) {
00093   facetT *facet;
00094 
00095   FORALLfacets {
00096     if (facet->id == id) {
00097       qh_printfacet (qh fout, facet);
00098       break;
00099     }
00100   }
00101 } /* dfacet */
00102 
00103 
00104 /*-<a                             href="qh-io.htm#TOC"
00105   >-------------------------------</a><a name="dvertex">-</a>
00106   
00107   dvertex( id )
00108     print vertex by id, for debugging
00109 */
00110 void dvertex (unsigned id) {
00111   vertexT *vertex;
00112 
00113   FORALLvertices {
00114     if (vertex->id == id) {
00115       qh_printvertex (qh fout, vertex);
00116       break;
00117     }
00118   }
00119 } /* dvertex */
00120 
00121 
00122 /*-<a                             href="qh-io.htm#TOC"
00123   >-------------------------------</a><a name="compare_vertexpoint">-</a>
00124   
00125   qh_compare_vertexpoint( p1, p2 )
00126     used by qsort() to order vertices by point id 
00127 */
00128 int qh_compare_vertexpoint(const void *p1, const void *p2) {
00129   vertexT *a= *((vertexT **)p1), *b= *((vertexT **)p2);
00130  
00131   return ((qh_pointid(a->point) > qh_pointid(b->point)?1:-1));
00132 } /* compare_vertexpoint */
00133 
00134 /*-<a                             href="qh-io.htm#TOC"
00135   >-------------------------------</a><a name="compare_facetarea">-</a>
00136   
00137   qh_compare_facetarea( p1, p2 )
00138     used by qsort() to order facets by area
00139 */
00140 static int qh_compare_facetarea(const void *p1, const void *p2) {
00141   facetT *a= *((facetT **)p1), *b= *((facetT **)p2);
00142 
00143   if (!a->isarea)
00144     return -1;
00145   if (!b->isarea)
00146     return 1; 
00147   if (a->f.area > b->f.area)
00148     return 1;
00149   else if (a->f.area == b->f.area)
00150     return 0;
00151   return -1;
00152 } /* compare_facetarea */
00153 
00154 /*-<a                             href="qh-io.htm#TOC"
00155   >-------------------------------</a><a name="compare_facetmerge">-</a>
00156   
00157   qh_compare_facetmerge( p1, p2 )
00158     used by qsort() to order facets by number of merges
00159 */
00160 static int qh_compare_facetmerge(const void *p1, const void *p2) {
00161   facetT *a= *((facetT **)p1), *b= *((facetT **)p2);
00162  
00163   return (a->nummerge - b->nummerge);
00164 } /* compare_facetvisit */
00165 
00166 /*-<a                             href="qh-io.htm#TOC"
00167   >-------------------------------</a><a name="compare_facetvisit">-</a>
00168   
00169   qh_compare_facetvisit( p1, p2 )
00170     used by qsort() to order facets by visit id or id
00171 */
00172 static int qh_compare_facetvisit(const void *p1, const void *p2) {
00173   facetT *a= *((facetT **)p1), *b= *((facetT **)p2);
00174   int i,j;
00175 
00176   if (!(i= a->visitid))
00177     i= - a->id; /* do not convert to int */
00178   if (!(j= b->visitid))
00179     j= - b->id;
00180   return (i - j);
00181 } /* compare_facetvisit */
00182 
00183 /*-<a                             href="qh-io.htm#TOC"
00184   >-------------------------------</a><a name="countfacets">-</a>
00185   
00186   qh_countfacets( facetlist, facets, printall, 
00187           numfacets, numsimplicial, totneighbors, numridges, numcoplanar  )
00188     count good facets for printing and set visitid
00189     if allfacets, ignores qh_skipfacet()
00190 
00191   returns:
00192     numfacets, numsimplicial, total neighbors, numridges, coplanars
00193     each facet with ->visitid indicating 1-relative position
00194       ->visitid==0 indicates not good
00195   
00196   notes
00197     numfacets >= numsimplicial
00198     if qh.NEWfacets, 
00199       does not count visible facets (matches qh_printafacet)
00200 
00201   design:
00202     for all facets on facetlist and in facets set
00203       unless facet is skipped or visible (i.e., will be deleted)
00204         mark facet->visitid
00205         update counts
00206 */
00207 void qh_countfacets (facetT *facetlist, setT *facets, boolT printall,
00208     int *numfacetsp, int *numsimplicialp, int *totneighborsp, int *numridgesp, int *numcoplanarsp) {
00209   facetT *facet, **facetp;
00210   int numfacets= 0, numsimplicial= 0, numridges= 0, totneighbors= 0, numcoplanars= 0;
00211 
00212   FORALLfacet_(facetlist) {
00213     if ((facet->visible && qh NEWfacets)
00214     || (!printall && qh_skipfacet(facet)))
00215       facet->visitid= 0;
00216     else {
00217       facet->visitid= ++numfacets;
00218       totneighbors += qh_setsize (facet->neighbors);
00219       if (facet->simplicial) 
00220         numsimplicial++;
00221       else
00222         numridges += qh_setsize (facet->ridges);
00223       if (facet->coplanarset)
00224         numcoplanars += qh_setsize (facet->coplanarset);
00225     }
00226   }
00227   FOREACHfacet_(facets) {
00228     if ((facet->visible && qh NEWfacets)
00229     || (!printall && qh_skipfacet(facet)))
00230       facet->visitid= 0;
00231     else {
00232       facet->visitid= ++numfacets;
00233       totneighbors += qh_setsize (facet->neighbors);
00234       if (facet->simplicial)
00235         numsimplicial++;
00236       else
00237         numridges += qh_setsize (facet->ridges);
00238       if (facet->coplanarset)
00239         numcoplanars += qh_setsize (facet->coplanarset);
00240     }
00241   }
00242   qh visit_id += numfacets+1;
00243   *numfacetsp= numfacets;
00244   *numsimplicialp= numsimplicial;
00245   *totneighborsp= totneighbors;
00246   *numridgesp= numridges;
00247   *numcoplanarsp= numcoplanars;
00248 } /* countfacets */
00249 
00250 /*-<a                             href="qh-io.htm#TOC"
00251   >-------------------------------</a><a name="detvnorm">-</a>
00252   
00253   qh_detvnorm( vertex, vertexA, centers, offset )
00254     compute separating plane of the Voronoi diagram for a pair of input sites
00255     centers= set of facets (i.e., Voronoi vertices)
00256       facet->visitid= 0 iff vertex-at-infinity (i.e., unbounded)
00257         
00258   assumes:
00259     qh_ASvoronoi and qh_vertexneighbors() already set
00260   
00261   returns:
00262     norm
00263       a pointer into qh.gm_matrix to qh.hull_dim-1 reals
00264       copy the data before reusing qh.gm_matrix
00265     offset
00266       if 'QVn'
00267         sign adjusted so that qh.GOODvertexp is inside
00268       else
00269         sign adjusted so that vertex is inside
00270       
00271     qh.gm_matrix= simplex of points from centers relative to first center
00272     
00273   notes:
00274     in io.c so that code for 'v Tv' can be removed by removing io.c
00275     returns pointer into qh.gm_matrix to avoid tracking of temporary memory
00276   
00277   design:
00278     determine midpoint of input sites
00279     build points as the set of Voronoi vertices
00280     select a simplex from points (if necessary)
00281       include midpoint if the Voronoi region is unbounded
00282     relocate the first vertex of the simplex to the origin
00283     compute the normalized hyperplane through the simplex
00284     orient the hyperplane toward 'QVn' or 'vertex'
00285     if 'Tv' or 'Ts'
00286       if bounded
00287         test that hyperplane is the perpendicular bisector of the input sites
00288       test that Voronoi vertices not in the simplex are still on the hyperplane
00289     free up temporary memory
00290 */
00291 pointT *qh_detvnorm (vertexT *vertex, vertexT *vertexA, setT *centers, realT *offsetp) {
00292   facetT *facet, **facetp;
00293   int  i, k, pointid, pointidA, point_i, point_n;
00294   setT *simplex= NULL;
00295   pointT *point, **pointp, *point0, *midpoint, *normal, *inpoint;
00296   coordT *coord, *gmcoord, *normalp;
00297   setT *points= qh_settemp (qh TEMPsize);
00298   boolT nearzero= False;
00299   boolT unbounded= False;
00300   int numcenters= 0;
00301   int dim= qh hull_dim - 1;
00302   realT dist, offset, angle, zero= 0.0;
00303 
00304   midpoint= qh gm_matrix + qh hull_dim * qh hull_dim;  /* last row */
00305   for (k= 0; k < dim; k++)
00306     midpoint[k]= (vertex->point[k] + vertexA->point[k])/2;
00307   FOREACHfacet_(centers) {
00308     numcenters++;
00309     if (!facet->visitid)
00310       unbounded= True;
00311     else {
00312       if (!facet->center)
00313         facet->center= qh_facetcenter (facet->vertices);
00314       qh_setappend (&points, facet->center);
00315     }
00316   }
00317   if (numcenters > dim) {
00318     simplex= qh_settemp (qh TEMPsize);
00319     qh_setappend (&simplex, vertex->point);
00320     if (unbounded)
00321       qh_setappend (&simplex, midpoint);
00322     qh_maxsimplex (dim, points, NULL, 0, &simplex);
00323     qh_setdelnth (simplex, 0);
00324   }else if (numcenters == dim) {
00325     if (unbounded)
00326       qh_setappend (&points, midpoint);
00327     simplex= points; 
00328   }else {
00329     fprintf(qh ferr, "qh_detvnorm: too few points (%d) to compute separating plane\n", numcenters);
00330     qh_errexit (qh_ERRqhull, NULL, NULL);
00331   }
00332   i= 0;
00333   gmcoord= qh gm_matrix;
00334   point0= SETfirstt_(simplex, pointT);
00335   FOREACHpoint_(simplex) {
00336     if (qh IStracing >= 4)
00337       qh_printmatrix(qh ferr, "qh_detvnorm: Voronoi vertex or midpoint", 
00338                               &point, 1, dim);
00339     if (point != point0) {
00340       qh gm_row[i++]= gmcoord;
00341       coord= point0;
00342       for (k= dim; k--; )
00343         *(gmcoord++)= *point++ - *coord++;
00344     }
00345   }
00346   qh gm_row[i]= gmcoord;  /* does not overlap midpoint, may be used later for qh_areasimplex */
00347   normal= gmcoord;
00348   qh_sethyperplane_gauss (dim, qh gm_row, point0, True,
00349                 normal, &offset, &nearzero);
00350   if (qh GOODvertexp == vertexA->point)
00351     inpoint= vertexA->point;
00352   else
00353     inpoint= vertex->point;
00354   zinc_(Zdistio);
00355   dist= qh_distnorm (dim, inpoint, normal, &offset);
00356   if (dist > 0) {
00357     offset= -offset;
00358     normalp= normal;
00359     for (k= dim; k--; ) {
00360       *normalp= -(*normalp);
00361       normalp++;
00362     }
00363   }
00364   if (qh VERIFYoutput || qh PRINTstatistics) {
00365     pointid= qh_pointid (vertex->point);
00366     pointidA= qh_pointid (vertexA->point);
00367     if (!unbounded) {
00368       zinc_(Zdiststat);
00369       dist= qh_distnorm (dim, midpoint, normal, &offset);
00370       if (dist < 0)
00371         dist= -dist;
00372       zzinc_(Zridgemid);
00373       wwmax_(Wridgemidmax, dist);
00374       wwadd_(Wridgemid, dist);
00375       trace4((qh ferr, "qh_detvnorm: points %d %d midpoint dist %2.2g\n",
00376                  pointid, pointidA, dist));
00377       for (k= 0; k < dim; k++) 
00378         midpoint[k]= vertexA->point[k] - vertex->point[k];  /* overwrites midpoint! */
00379       qh_normalize (midpoint, dim, False);
00380       angle= qh_distnorm (dim, midpoint, normal, &zero); /* qh_detangle uses dim+1 */
00381       if (angle < 0.0)
00382         angle= angle + 1.0;
00383       else
00384         angle= angle - 1.0;
00385       if (angle < 0.0)
00386         angle -= angle;
00387       trace4((qh ferr, "qh_detvnorm: points %d %d angle %2.2g nearzero %d\n",
00388                  pointid, pointidA, angle, nearzero));
00389       if (nearzero) {
00390         zzinc_(Zridge0);
00391         wwmax_(Wridge0max, angle);
00392         wwadd_(Wridge0, angle);
00393       }else {
00394         zzinc_(Zridgeok)
00395         wwmax_(Wridgeokmax, angle);
00396         wwadd_(Wridgeok, angle);
00397       }
00398     }
00399     if (simplex != points) {
00400       FOREACHpoint_i_(points) {
00401         if (!qh_setin (simplex, point)) {
00402           facet= SETelemt_(centers, point_i, facetT);
00403           zinc_(Zdiststat);
00404           dist= qh_distnorm (dim, point, normal, &offset);
00405           if (dist < 0)
00406             dist= -dist;
00407           zzinc_(Zridge);
00408           wwmax_(Wridgemax, dist);
00409           wwadd_(Wridge, dist);
00410           trace4((qh ferr, "qh_detvnorm: points %d %d Voronoi vertex %d dist %2.2g\n",
00411                              pointid, pointidA, facet->visitid, dist));
00412         }
00413       }
00414     }
00415   }
00416   *offsetp= offset;
00417   if (simplex != points)
00418     qh_settempfree (&simplex);
00419   qh_settempfree (&points);
00420   return normal;
00421 } /* detvnorm */
00422 
00423 /*-<a                             href="qh-io.htm#TOC"
00424   >-------------------------------</a><a name="detvridge">-</a>
00425 
00426   qh_detvridge( vertexA )
00427     determine Voronoi ridge from 'seen' neighbors of vertexA
00428     include one vertex-at-infinite if an !neighbor->visitid
00429 
00430   returns:
00431     temporary set of centers (facets, i.e., Voronoi vertices)
00432     sorted by center id
00433 */
00434 setT *qh_detvridge (vertexT *vertex) {
00435   setT *centers= qh_settemp (qh TEMPsize);
00436   facetT *neighbor, **neighborp;
00437   boolT firstinf= True;
00438   
00439   FOREACHneighbor_(vertex) {
00440     if (neighbor->seen) {
00441       if (neighbor->visitid)
00442         qh_setappend (&centers, neighbor);
00443       else if (firstinf) {
00444         firstinf= False;
00445         qh_setappend (&centers, neighbor);
00446       }
00447     }
00448   }
00449   qsort (SETaddr_(centers, facetT), qh_setsize (centers),
00450              sizeof (facetT *), qh_compare_facetvisit);
00451   return centers;
00452 } /* detvridge */      
00453 
00454 /*-<a                             href="qh-io.htm#TOC"
00455   >-------------------------------</a><a name="detvridge3">-</a>
00456 
00457   qh_detvridge3( atvertex, vertex )
00458     determine 3-d Voronoi ridge from 'seen' neighbors of atvertex and vertex
00459     include one vertex-at-infinite for !neighbor->visitid
00460     assumes all facet->seen2= True
00461 
00462   returns:
00463     temporary set of centers (facets, i.e., Voronoi vertices)
00464     listed in adjacency order (not oriented)
00465     all facet->seen2= True
00466 
00467   design:
00468     mark all neighbors of atvertex
00469     for each adjacent neighbor of both atvertex and vertex
00470       if neighbor selected
00471         add neighbor to set of Voronoi vertices
00472 */
00473 setT *qh_detvridge3 (vertexT *atvertex, vertexT *vertex) {
00474   setT *centers= qh_settemp (qh TEMPsize);
00475   facetT *neighbor, **neighborp, *facet= NULL;
00476   boolT firstinf= True;
00477   
00478   FOREACHneighbor_(atvertex)
00479     neighbor->seen2= False;
00480   FOREACHneighbor_(vertex) {
00481     if (!neighbor->seen2) {
00482       facet= neighbor;
00483       break;
00484     }
00485   }
00486   while (facet) { 
00487     facet->seen2= True;
00488     if (neighbor->seen) {
00489       if (facet->visitid)
00490         qh_setappend (&centers, facet);
00491       else if (firstinf) {
00492         firstinf= False;
00493         qh_setappend (&centers, facet);
00494       }
00495     }
00496     FOREACHneighbor_(facet) {
00497       if (!neighbor->seen2) {
00498         if (qh_setin (vertex->neighbors, neighbor))
00499           break;
00500         else
00501           neighbor->seen2= True;
00502       }
00503     }
00504     facet= neighbor;
00505   }
00506   if (qh CHECKfrequently) {
00507     FOREACHneighbor_(vertex) {
00508       if (!neighbor->seen2) {
00509         fprintf (stderr, "qh_detvridge3: neigbors of vertex p%d are not connected at facet %d\n",
00510                  qh_pointid (vertex->point), neighbor->id);
00511         qh_errexit (qh_ERRqhull, neighbor, NULL);
00512       }
00513     }
00514   }
00515   FOREACHneighbor_(atvertex) 
00516     neighbor->seen2= True;
00517   return centers;
00518 } /* detvridge3 */      
00519 
00520 /*-<a                             href="qh-io.htm#TOC"
00521   >-------------------------------</a><a name="eachvoronoi">-</a>
00522   
00523   qh_eachvoronoi( fp, printvridge, vertex, visitall, innerouter, inorder )
00524     if visitall,
00525       visit all Voronoi ridges for vertex (i.e., an input site)
00526     else
00527       visit all unvisited Voronoi ridges for vertex
00528       all vertex->seen= False if unvisited
00529     assumes
00530       all facet->seen= False
00531       all facet->seen2= True (for qh_detvridge3)
00532       all facet->visitid == 0 if vertex_at_infinity
00533                          == index of Voronoi vertex 
00534                          >= qh.num_facets if ignored
00535     innerouter:
00536       qh_RIDGEall--  both inner (bounded) and outer (unbounded) ridges
00537       qh_RIDGEinner- only inner
00538       qh_RIDGEouter- only outer
00539       
00540     if inorder
00541       orders vertices for 3-d Voronoi diagrams
00542   
00543   returns:
00544     number of visited ridges (does not include previously visited ridges)
00545     
00546     if printvridge,
00547       calls printvridge( fp, vertex, vertexA, centers)
00548         fp== any pointer (assumes FILE*)
00549         vertex,vertexA= pair of input sites that define a Voronoi ridge
00550         centers= set of facets (i.e., Voronoi vertices)
00551                  ->visitid == index or 0 if vertex_at_infinity
00552                  ordered for 3-d Voronoi diagram
00553   notes:
00554     uses qh.vertex_visit
00555   
00556   see:
00557     qh_eachvoronoi_all()
00558   
00559   design:
00560     mark selected neighbors of atvertex
00561     for each selected neighbor (either Voronoi vertex or vertex-at-infinity)
00562       for each unvisited vertex 
00563         if atvertex and vertex share more than d-1 neighbors
00564           bump totalcount
00565           if printvridge defined
00566             build the set of shared neighbors (i.e., Voronoi vertices)
00567             call printvridge
00568 */
00569 int qh_eachvoronoi (FILE *fp, printvridgeT printvridge, vertexT *atvertex, boolT visitall, qh_RIDGE innerouter, boolT inorder) {
00570   boolT unbounded;
00571   int count;
00572   facetT *neighbor, **neighborp, *neighborA, **neighborAp;
00573   setT *centers;
00574   vertexT *vertex, **vertexp;
00575   boolT firstinf;
00576   unsigned int numfacets= (unsigned int)qh num_facets;
00577   int totridges= 0;
00578 
00579   qh vertex_visit++;
00580   atvertex->seen= True;
00581   if (visitall) {
00582     FORALLvertices 
00583       vertex->seen= False;
00584   }
00585   FOREACHneighbor_(atvertex) {
00586     if (neighbor->visitid < numfacets) 
00587       neighbor->seen= True;
00588   }
00589   FOREACHneighbor_(atvertex) {
00590     if (neighbor->seen) {
00591       FOREACHvertex_(neighbor->vertices) {
00592         if (vertex->visitid != qh vertex_visit && !vertex->seen) {
00593           vertex->visitid= qh vertex_visit;
00594           count= 0;
00595           firstinf= True;
00596           FOREACHneighborA_(vertex) {
00597             if (neighborA->seen) {
00598               if (neighborA->visitid)
00599                 count++;
00600               else if (firstinf) {
00601                 count++;
00602                 firstinf= False;
00603               }
00604             }
00605           }
00606           if (count >= qh hull_dim - 1) {  /* e.g., 3 for 3-d Voronoi */
00607             if (firstinf) {
00608               if (innerouter == qh_RIDGEouter)
00609                 continue;
00610               unbounded= False;
00611             }else {
00612               if (innerouter == qh_RIDGEinner)
00613                 continue;
00614               unbounded= True;
00615             }
00616             totridges++;
00617             trace4((qh ferr, "qh_eachvoronoi: Voronoi ridge of %d vertices between sites %d and %d\n",
00618                   count, qh_pointid (atvertex->point), qh_pointid (vertex->point)));
00619             if (printvridge) { 
00620               if (inorder && qh hull_dim == 3+1) /* 3-d Voronoi diagram */
00621                 centers= qh_detvridge3 (atvertex, vertex);
00622               else
00623                 centers= qh_detvridge (vertex);
00624               (*printvridge) (fp, atvertex, vertex, centers, unbounded);
00625               qh_settempfree (&centers);
00626             }
00627           }
00628         }
00629       }
00630     }
00631   }
00632   FOREACHneighbor_(atvertex) 
00633     neighbor->seen= False;
00634   return totridges;
00635 } /* eachvoronoi */
00636   
00637 
00638 /*-<a                             href="qh-poly.htm#TOC"
00639   >-------------------------------</a><a name="eachvoronoi_all">-</a>
00640   
00641   qh_eachvoronoi_all( fp, printvridge, isupper, innerouter, inorder )
00642     visit all Voronoi ridges
00643     
00644     innerouter:
00645       see qh_eachvoronoi()
00646       
00647     if inorder
00648       orders vertices for 3-d Voronoi diagrams
00649     
00650   returns
00651     total number of ridges 
00652 
00653     if isupper == facet->upperdelaunay  (i.e., a Vornoi vertex)
00654       facet->visitid= Voronoi vertex index (same as 'o' format)
00655     else 
00656       facet->visitid= 0
00657 
00658     if printvridge,
00659       calls printvridge( fp, vertex, vertexA, centers)
00660       [see qh_eachvoronoi]
00661       
00662   notes:
00663     Not used for qhull.exe
00664     same effect as qh_printvdiagram but ridges not sorted by point id
00665 */
00666 int qh_eachvoronoi_all (FILE *fp, printvridgeT printvridge, boolT isupper, qh_RIDGE innerouter, boolT inorder) {
00667   facetT *facet;
00668   vertexT *vertex;
00669   int numcenters= 1;  /* vertex 0 is vertex-at-infinity */
00670   int totridges= 0;
00671 
00672   qh_clearcenters (qh_ASvoronoi);
00673   qh_vertexneighbors();
00674   maximize_(qh visit_id, (unsigned) qh num_facets);
00675   FORALLfacets {
00676     facet->visitid= 0;
00677     facet->seen= False;
00678     facet->seen2= True;
00679   }
00680   FORALLfacets {
00681     if (facet->upperdelaunay == isupper)
00682       facet->visitid= numcenters++;
00683   }
00684   FORALLvertices 
00685     vertex->seen= False;
00686   FORALLvertices {
00687     if (qh GOODvertex > 0 && qh_pointid(vertex->point)+1 != qh GOODvertex)
00688       continue;
00689     totridges += qh_eachvoronoi (fp, printvridge, vertex, 
00690                    !qh_ALL, innerouter, inorder);
00691   }
00692   return totridges;
00693 } /* eachvoronoi_all */
00694       
00695 /*-<a                             href="qh-io.htm#TOC"
00696   >-------------------------------</a><a name="facet2point">-</a>
00697   
00698   qh_facet2point( facet, point0, point1, mindist )
00699     return two projected temporary vertices for a 2-d facet
00700     may be non-simplicial
00701 
00702   returns:
00703     point0 and point1 oriented and projected to the facet
00704     returns mindist (maximum distance below plane)
00705 */
00706 void qh_facet2point(facetT *facet, pointT **point0, pointT **point1, realT *mindist) {
00707   vertexT *vertex0, *vertex1;
00708   realT dist;
00709   
00710   if (facet->toporient ^ qh_ORIENTclock) {
00711     vertex0= SETfirstt_(facet->vertices, vertexT);
00712     vertex1= SETsecondt_(facet->vertices, vertexT);
00713   }else {
00714     vertex1= SETfirstt_(facet->vertices, vertexT);
00715     vertex0= SETsecondt_(facet->vertices, vertexT);
00716   }
00717   zadd_(Zdistio, 2);
00718   qh_distplane(vertex0->point, facet, &dist);
00719   *mindist= dist;
00720   *point0= qh_projectpoint(vertex0->point, facet, dist);
00721   qh_distplane(vertex1->point, facet, &dist);
00722   minimize_(*mindist, dist);            
00723   *point1= qh_projectpoint(vertex1->point, facet, dist);
00724 } /* facet2point */
00725 
00726 
00727 /*-<a                             href="qh-io.htm#TOC"
00728   >-------------------------------</a><a name="facetvertices">-</a>
00729   
00730   qh_facetvertices( facetlist, facets, allfacets )
00731     returns temporary set of vertices in a set and/or list of facets
00732     if allfacets, ignores qh_skipfacet()
00733 
00734   returns:
00735     vertices with qh.vertex_visit
00736     
00737   notes:
00738     optimized for allfacets of facet_list
00739 
00740   design:
00741     if allfacets of facet_list
00742       create vertex set from vertex_list
00743     else
00744       for each selected facet in facets or facetlist
00745         append unvisited vertices to vertex set
00746 */
00747 setT *qh_facetvertices (facetT *facetlist, setT *facets, boolT allfacets) {
00748   setT *vertices;
00749   facetT *facet, **facetp;
00750   vertexT *vertex, **vertexp;
00751 
00752   qh vertex_visit++;
00753   if (facetlist == qh facet_list && allfacets && !facets) {
00754     vertices= qh_settemp (qh num_vertices);
00755     FORALLvertices {
00756       vertex->visitid= qh vertex_visit; 
00757       qh_setappend (&vertices, vertex);
00758     }
00759   }else {
00760     vertices= qh_settemp (qh TEMPsize);
00761     FORALLfacet_(facetlist) {
00762       if (!allfacets && qh_skipfacet (facet))
00763         continue;
00764       FOREACHvertex_(facet->vertices) {
00765         if (vertex->visitid != qh vertex_visit) {
00766           vertex->visitid= qh vertex_visit;
00767           qh_setappend (&vertices, vertex);
00768         }
00769       }
00770     }
00771   }
00772   FOREACHfacet_(facets) {
00773     if (!allfacets && qh_skipfacet (facet))
00774       continue;
00775     FOREACHvertex_(facet->vertices) {
00776       if (vertex->visitid != qh vertex_visit) {
00777         vertex->visitid= qh vertex_visit;
00778         qh_setappend (&vertices, vertex);
00779       }
00780     }
00781   }
00782   return vertices;
00783 } /* facetvertices */
00784 
00785 /*-<a                             href="qh-geom.htm#TOC"
00786   >-------------------------------</a><a name="geomplanes">-</a>
00787   
00788   qh_geomplanes( facet, outerplane, innerplane )
00789     return outer and inner planes for Geomview 
00790     qh.PRINTradius is size of vertices and points (includes qh.JOGGLEmax)
00791 
00792   notes:
00793     assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
00794 */
00795 void qh_geomplanes (facetT *facet, realT *outerplane, realT *innerplane) {
00796   realT radius;
00797 
00798   if (qh MERGING || qh JOGGLEmax < REALmax/2) {
00799     qh_outerinner (facet, outerplane, innerplane);
00800     radius= qh PRINTradius;
00801     if (qh JOGGLEmax < REALmax/2)
00802       radius -= qh JOGGLEmax * sqrt (qh hull_dim);  /* already accounted for in qh_outerinner() */
00803     *outerplane += radius;
00804     *innerplane -= radius;
00805     if (qh PRINTcoplanar || qh PRINTspheres) {
00806       *outerplane += qh MAXabs_coord * qh_GEOMepsilon;
00807       *innerplane -= qh MAXabs_coord * qh_GEOMepsilon;
00808     }
00809   }else 
00810     *innerplane= *outerplane= 0;
00811 } /* geomplanes */
00812 
00813 
00814 /*-<a                             href="qh-io.htm#TOC"
00815   >-------------------------------</a><a name="markkeep">-</a>
00816   
00817   qh_markkeep( facetlist )
00818     mark good facets that meet qh.KEEParea, qh.KEEPmerge, and qh.KEEPminArea
00819     ignores visible facets (not part of convex hull)
00820 
00821   returns:
00822     may clear facet->good
00823     recomputes qh.num_good
00824 
00825   design:
00826     get set of good facets
00827     if qh.KEEParea
00828       sort facets by area
00829       clear facet->good for all but n largest facets
00830     if qh.KEEPmerge
00831       sort facets by merge count
00832       clear facet->good for all but n most merged facets
00833     if qh.KEEPminarea
00834       clear facet->good if area too small
00835     update qh.num_good    
00836 */
00837 void qh_markkeep (facetT *facetlist) {
00838   facetT *facet, **facetp;
00839   setT *facets= qh_settemp (qh num_facets);
00840   int size, count;
00841 
00842   trace2((qh ferr, "qh_markkeep: only keep %d largest and/or %d most merged facets and/or min area %.2g\n",
00843           qh KEEParea, qh KEEPmerge, qh KEEPminArea));
00844   FORALLfacet_(facetlist) {
00845     if (!facet->visible && facet->good)
00846       qh_setappend (&facets, facet);
00847   }
00848   size= qh_setsize (facets);
00849   if (qh KEEParea) {
00850     qsort (SETaddr_(facets, facetT), size,
00851              sizeof (facetT *), qh_compare_facetarea);
00852     if ((count= size - qh KEEParea) > 0) {
00853       FOREACHfacet_(facets) {
00854         facet->good= False;
00855         if (--count == 0)
00856           break;
00857       }
00858     }
00859   }
00860   if (qh KEEPmerge) {
00861     qsort (SETaddr_(facets, facetT), size,
00862              sizeof (facetT *), qh_compare_facetmerge);
00863     if ((count= size - qh KEEPmerge) > 0) {
00864       FOREACHfacet_(facets) {
00865         facet->good= False;
00866         if (--count == 0)
00867           break;
00868       }
00869     }
00870   }
00871   if (qh KEEPminArea < REALmax/2) {
00872     FOREACHfacet_(facets) {
00873       if (!facet->isarea || facet->f.area < qh KEEPminArea)
00874         facet->good= False;
00875     }
00876   }
00877   qh_settempfree (&facets);
00878   count= 0;
00879   FORALLfacet_(facetlist) {
00880     if (facet->good)
00881       count++;
00882   }
00883   qh num_good= count;
00884 } /* markkeep */
00885 
00886 
00887 /*-<a                             href="qh-io.htm#TOC"
00888   >-------------------------------</a><a name="markvoronoi">-</a>
00889   
00890   qh_markvoronoi( facetlist, facets, printall, islower, numcenters )
00891     mark voronoi vertices for printing by site pairs
00892   
00893   returns:
00894     temporary set of vertices indexed by pointid
00895     islower set if printing lower hull (i.e., at least one facet is lower hull)
00896     numcenters= total number of Voronoi vertices
00897     bumps qh.printoutnum for vertex-at-infinity
00898     clears all facet->seen and sets facet->seen2
00899     
00900     if selected
00901       facet->visitid= Voronoi vertex id
00902     else if upper hull (or 'Qu' and lower hull)
00903       facet->visitid= 0
00904     else
00905       facet->visitid >= qh num_facets
00906   
00907   notes:
00908     ignores qh ATinfinity, if defined
00909 */
00910 setT *qh_markvoronoi (facetT *facetlist, setT *facets, boolT printall, boolT *islowerp, int *numcentersp) {
00911   int numcenters=0;
00912   facetT *facet, **facetp;
00913   setT *vertices;
00914   boolT islower= False;
00915 
00916   qh printoutnum++;
00917   qh_clearcenters (qh_ASvoronoi);  /* in case, qh_printvdiagram2 called by user */
00918   qh_vertexneighbors();
00919   vertices= qh_pointvertex();
00920   if (qh ATinfinity) 
00921     SETelem_(vertices, qh num_points-1)= NULL;
00922   qh visit_id++;
00923   maximize_(qh visit_id, (unsigned) qh num_facets);
00924   FORALLfacet_(facetlist) {  /* FIXUP: could merge with below */
00925     if (printall || !qh_skipfacet (facet)) {
00926       if (!facet->upperdelaunay) {
00927         islower= True;
00928         break;
00929       }
00930     }
00931   }
00932   FOREACHfacet_(facets) {
00933     if (printall || !qh_skipfacet (facet)) {
00934       if (!facet->upperdelaunay) {
00935         islower= True;
00936         break;
00937       }
00938     }
00939   }
00940   FORALLfacets {
00941     if (facet->normal && (facet->upperdelaunay == islower))
00942       facet->visitid= 0;  /* facetlist or facets may overwrite */
00943     else
00944       facet->visitid= qh visit_id;
00945     facet->seen= False;
00946     facet->seen2= True;
00947   }
00948   numcenters++;  /* qh_INFINITE */
00949   FORALLfacet_(facetlist) {
00950     if (printall || !qh_skipfacet (facet))
00951       facet->visitid= numcenters++;
00952   }
00953   FOREACHfacet_(facets) {
00954     if (printall || !qh_skipfacet (facet))
00955       facet->visitid= numcenters++;  
00956   }
00957   *islowerp= islower;
00958   *numcentersp= numcenters;
00959   trace2((qh ferr, "qh_markvoronoi: islower %d numcenters %d\n", islower, numcenters));
00960   return vertices;
00961 } /* markvoronoi */
00962 
00963 /*-<a                             href="qh-io.htm#TOC"
00964   >-------------------------------</a><a name="order_vertexneighbors">-</a>
00965   
00966   qh_order_vertexneighbors( vertex )
00967     order facet neighbors of a 2-d or 3-d vertex by adjacency
00968 
00969   notes:
00970     does not orient the neighbors
00971 
00972   design:
00973     initialize a new neighbor set with the first facet in vertex->neighbors
00974     while vertex->neighbors non-empty
00975       select next neighbor in the previous facet's neighbor set
00976     set vertex->neighbors to the new neighbor set
00977 */
00978 void qh_order_vertexneighbors(vertexT *vertex) {
00979   setT *newset;
00980   facetT *facet, *neighbor, **neighborp;
00981 
00982   trace4((qh ferr, "qh_order_vertexneighbors: order neighbors of v%d for 3-d\n", vertex->id));
00983   newset= qh_settemp (qh_setsize (vertex->neighbors));
00984   facet= (facetT*)qh_setdellast (vertex->neighbors);
00985   qh_setappend (&newset, facet);
00986   while (qh_setsize (vertex->neighbors)) {
00987     FOREACHneighbor_(vertex) {
00988       if (qh_setin (facet->neighbors, neighbor)) {
00989         qh_setdel(vertex->neighbors, neighbor);
00990         qh_setappend (&newset, neighbor);
00991         facet= neighbor;
00992         break;
00993       }
00994     }
00995     if (!neighbor) {
00996       fprintf (qh ferr, "qhull internal error (qh_order_vertexneighbors): no neighbor of v%d for f%d\n",
00997         vertex->id, facet->id);
00998       qh_errexit (qh_ERRqhull, facet, NULL);
00999     }
01000   }
01001   qh_setfree (&vertex->neighbors);
01002   qh_settemppop ();
01003   vertex->neighbors= newset;
01004 } /* order_vertexneighbors */
01005 
01006 /*-<a                             href="qh-io.htm#TOC"
01007   >-------------------------------</a><a name="printafacet">-</a>
01008   
01009   qh_printafacet( fp, format, facet, printall )
01010     print facet to fp in given output format (see qh.PRINTout)
01011 
01012   returns:
01013     nop if !printall and qh_skipfacet()
01014     nop if visible facet and NEWfacets and format != PRINTfacets
01015     must match qh_countfacets
01016 
01017   notes
01018     preserves qh.visit_id
01019     facet->normal may be null if PREmerge/MERGEexact and STOPcone before merge
01020 
01021   see
01022     qh_printbegin() and qh_printend()
01023 
01024   design:
01025     test for printing facet
01026     call appropriate routine for format
01027     or output results directly
01028 */
01029 void qh_printafacet(FILE *fp, int format, facetT *facet, boolT printall) {
01030   realT color[4], offset, dist, outerplane, innerplane;
01031   boolT zerodiv;
01032   coordT *point, *normp, *coordp, **pointp, *feasiblep;
01033   int k;
01034   vertexT *vertex, **vertexp;
01035   facetT *neighbor, **neighborp;
01036 
01037   if (!printall && qh_skipfacet (facet))
01038     return;
01039   if (facet->visible && qh NEWfacets && format != qh_PRINTfacets)
01040     return;
01041   qh printoutnum++;
01042   switch (format) {
01043   case qh_PRINTarea:
01044     if (facet->isarea) {
01045       fprintf (fp, qh_REAL_1, facet->f.area);
01046       fprintf (fp, "\n");
01047     }else
01048       fprintf (fp, "0\n");
01049     break;
01050   case qh_PRINTcoplanars:
01051     fprintf (fp, "%d", qh_setsize (facet->coplanarset));
01052     FOREACHpoint_(facet->coplanarset)
01053       fprintf (fp, " %d", qh_pointid (point));
01054     fprintf (fp, "\n");
01055     break;
01056   case qh_PRINTcentrums:
01057     qh_printcenter (fp, format, NULL, facet);
01058     break;
01059   case qh_PRINTfacets:
01060     qh_printfacet (fp, facet);
01061     break;
01062   case qh_PRINTfacets_xridge:
01063     qh_printfacetheader (fp, facet);
01064     break;
01065   case qh_PRINTgeom:  /* either 2 , 3, or 4-d by qh_printbegin */
01066     if (!facet->normal)
01067       break;
01068     for (k= qh hull_dim; k--; ) {
01069       color[k]= (facet->normal[k]+1.0)/2.0;
01070       maximize_(color[k], -1.0);
01071       minimize_(color[k], +1.0);
01072     }
01073     qh_projectdim3 (color, color);
01074     if (qh PRINTdim != qh hull_dim)
01075       qh_normalize2 (color, 3, True, NULL, NULL);
01076     if (qh hull_dim <= 2)
01077       qh_printfacet2geom (fp, facet, color);
01078     else if (qh hull_dim == 3) {
01079       if (facet->simplicial)
01080         qh_printfacet3geom_simplicial (fp, facet, color);
01081       else
01082         qh_printfacet3geom_nonsimplicial (fp, facet, color);
01083     }else {
01084       if (facet->simplicial)
01085         qh_printfacet4geom_simplicial (fp, facet, color);
01086       else
01087         qh_printfacet4geom_nonsimplicial (fp, facet, color);
01088     }
01089     break;
01090   case qh_PRINTids:
01091     fprintf (fp, "%d\n", facet->id);
01092     break;
01093   case qh_PRINTincidences:
01094   case qh_PRINToff:
01095   case qh_PRINTtriangles:
01096     if (qh hull_dim == 3 && format != qh_PRINTtriangles) 
01097       qh_printfacet3vertex (fp, facet, format);
01098     else if (facet->simplicial || qh hull_dim == 2 || format == qh_PRINToff)
01099       qh_printfacetNvertex_simplicial (fp, facet, format);
01100     else
01101       qh_printfacetNvertex_nonsimplicial (fp, facet, qh printoutvar++, format);
01102     break;
01103   case qh_PRINTinner:
01104     qh_outerinner (facet, NULL, &innerplane);
01105     offset= facet->offset - innerplane;
01106     goto LABELprintnorm;
01107     break; /* prevent warning */
01108   case qh_PRINTmerges:
01109     fprintf (fp, "%d\n", facet->nummerge);
01110     break;
01111   case qh_PRINTnormals:
01112     offset= facet->offset;
01113     goto LABELprintnorm;
01114     break; /* prevent warning */
01115   case qh_PRINTouter:
01116     qh_outerinner (facet, &outerplane, NULL);
01117     offset= facet->offset - outerplane;
01118   LABELprintnorm:
01119     if (!facet->normal) {
01120       fprintf (fp, "no normal for facet f%d\n", facet->id);
01121       break;
01122     }
01123     if (qh CDDoutput) 
01124       fprintf (fp, qh_REAL_1, -offset);
01125     for (k=0; k < qh hull_dim; k++) 
01126       fprintf (fp, qh_REAL_1, facet->normal[k]);
01127     if (!qh CDDoutput) 
01128       fprintf (fp, qh_REAL_1, offset);
01129     fprintf (fp, "\n");
01130     break;
01131   case qh_PRINTmathematica:  /* either 2 or 3-d by qh_printbegin */
01132     if (qh hull_dim == 2)
01133       qh_printfacet2math (fp, facet, qh printoutvar++);
01134     else 
01135       qh_printfacet3math (fp, facet, qh printoutvar++);
01136     break;
01137   case qh_PRINTneighbors:
01138     fprintf (fp, "%d", qh_setsize (facet->neighbors));
01139     FOREACHneighbor_(facet)
01140       fprintf (fp, " %d", 
01141                neighbor->visitid ? neighbor->visitid - 1: - neighbor->id);
01142     fprintf (fp, "\n");
01143     break;
01144   case qh_PRINTpointintersect:
01145     if (!qh feasible_point) {
01146       fprintf (fp, "qhull input error (qh_printafacet): option 'Fp' needs qh feasible_point\n");
01147       qh_errexit( qh_ERRinput, NULL, NULL);
01148     }
01149     if (facet->offset > 0)
01150       goto LABELprintinfinite;
01151     point= coordp= (coordT*)qh_memalloc (qh normal_size);
01152     normp= facet->normal;
01153     feasiblep= qh feasible_point;
01154     if (facet->offset < -qh MINdenom) {
01155       for (k= qh hull_dim; k--; )
01156         *(coordp++)= (*(normp++) / - facet->offset) + *(feasiblep++);
01157     }else {
01158       for (k= qh hull_dim; k--; ) {
01159         *(coordp++)= qh_divzero (*(normp++), facet->offset, qh MINdenom_1,
01160                                  &zerodiv) + *(feasiblep++);
01161         if (zerodiv) {
01162           qh_memfree (point, qh normal_size);
01163           goto LABELprintinfinite;
01164         }
01165       }
01166     }
01167     qh_printpoint (fp, NULL, point);
01168     qh_memfree (point, qh normal_size);
01169     break;
01170   LABELprintinfinite:
01171     for (k= qh hull_dim; k--; )
01172       fprintf (fp, qh_REAL_1, qh_INFINITE);
01173     fprintf (fp, "\n");   
01174     break;
01175   case qh_PRINTpointnearest:
01176     FOREACHpoint_(facet->coplanarset) {
01177       int id, id2;
01178       vertex= qh_nearvertex (facet, point, &dist);
01179       id= qh_pointid (vertex->point);
01180       id2= qh_pointid (point);
01181       fprintf (fp, "%d %d %d " qh_REAL_1 "\n", id, id2, facet->id, dist);
01182     }
01183     break;
01184   case qh_PRINTpoints:  /* VORONOI only by qh_printbegin */
01185     if (qh CDDoutput)
01186       fprintf (fp, "1 ");
01187     qh_printcenter (fp, format, NULL, facet);
01188     break;
01189   case qh_PRINTvertices:
01190     fprintf (fp, "%d", qh_setsize (facet->vertices));
01191     FOREACHvertex_(facet->vertices)
01192       fprintf (fp, " %d", qh_pointid (vertex->point));
01193     fprintf (fp, "\n");
01194     break;
01195   }
01196 } /* printafacet */
01197 
01198 /*-<a                             href="qh-io.htm#TOC"
01199   >-------------------------------</a><a name="printbegin">-</a>
01200   
01201   qh_printbegin(  )
01202     prints header for all output formats
01203 
01204   returns:
01205     checks for valid format
01206   
01207   notes:
01208     uses qh.visit_id for 3/4off
01209     changes qh.interior_point if printing centrums
01210     qh_countfacets clears facet->visitid for non-good facets
01211     
01212   see
01213     qh_printend() and qh_printafacet()
01214     
01215   design:
01216     count facets and related statistics
01217     print header for format
01218 */
01219 void qh_printbegin (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
01220   int numfacets, numsimplicial, numridges, totneighbors, numcoplanars;
01221   int i, num;
01222   facetT *facet, **facetp;
01223   vertexT *vertex, **vertexp;
01224   setT *vertices;
01225   pointT *point, **pointp, *pointtemp;
01226 
01227   qh printoutnum= 0;
01228   qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial, 
01229       &totneighbors, &numridges, &numcoplanars);
01230   switch (format) {
01231   case qh_PRINTnone:
01232     break;
01233   case qh_PRINTarea:
01234     fprintf (fp, "%d\n", numfacets);
01235     break;
01236   case qh_PRINTcoplanars:
01237     fprintf (fp, "%d\n", numfacets);
01238     break;
01239   case qh_PRINTcentrums:
01240     if (qh CENTERtype == qh_ASnone)
01241       qh_clearcenters (qh_AScentrum);
01242     fprintf (fp, "%d\n%d\n", qh hull_dim, numfacets);
01243     break;
01244   case qh_PRINTfacets:
01245   case qh_PRINTfacets_xridge:
01246     if (facetlist)
01247       qh_printvertexlist (fp, "Vertices and facets:\n", facetlist, facets, printall);
01248     break;
01249   case qh_PRINTgeom: 
01250     if (qh hull_dim > 4)  /* qh_initqhull_globals also checks */
01251       goto LABELnoformat;
01252     if (qh VORONOI && qh hull_dim > 3)  /* PRINTdim == DROPdim == hull_dim-1 */
01253       goto LABELnoformat;
01254     if (qh hull_dim == 2 && (qh PRINTridges || qh DOintersections))
01255       fprintf (qh ferr, "qhull warning: output for ridges and intersections not implemented in 2-d\n");
01256     if (qh hull_dim == 4 && (qh PRINTinner || qh PRINTouter ||
01257                              (qh PRINTdim == 4 && qh PRINTcentrums)))
01258       fprintf (qh ferr, "qhull warning: output for outer/inner planes and centrums not implemented in 4-d\n");
01259     if (qh PRINTdim == 4 && (qh PRINTspheres))
01260       fprintf (qh ferr, "qhull warning: output for vertices not implemented in 4-d\n");
01261     if (qh PRINTdim == 4 && qh DOintersections && qh PRINTnoplanes)
01262       fprintf (qh ferr, "qhull warning: 'Gnh' generates no output in 4-d\n");
01263     if (qh PRINTdim == 2) {
01264       fprintf(fp, "{appearance {linewidth 3} LIST # %s | %s\n",
01265               qh rbox_command, qh qhull_command);
01266     }else if (qh PRINTdim == 3) {
01267       fprintf(fp, "{appearance {+edge -evert linewidth 2} LIST # %s | %s\n",
01268               qh rbox_command, qh qhull_command);
01269     }else if (qh PRINTdim == 4) {
01270       qh visit_id++;
01271       num= 0;
01272       FORALLfacet_(facetlist)    /* get number of ridges to be printed */
01273         qh_printend4geom (NULL, facet, &num, printall);
01274       FOREACHfacet_(facets)
01275         qh_printend4geom (NULL, facet, &num, printall);
01276       qh ridgeoutnum= num;
01277       qh printoutvar= 0;  /* counts number of ridges in output */
01278       fprintf (fp, "LIST # %s | %s\n", qh rbox_command, qh qhull_command);
01279     }
01280     if (qh PRINTdots) {
01281       qh printoutnum++;
01282       num= qh num_points + qh_setsize (qh other_points);
01283       if (qh DELAUNAY && qh ATinfinity)
01284         num--;
01285       if (qh PRINTdim == 4)
01286         fprintf (fp, "4VECT %d %d 1\n", num, num);
01287       else
01288         fprintf (fp, "VECT %d %d 1\n", num, num);
01289       for (i= num; i--; ) {
01290         if (i % 20 == 0)
01291           fprintf (fp, "\n");
01292         fprintf (fp, "1 ");
01293       }
01294       fprintf (fp, "# 1 point per line\n1 ");
01295       for (i= num-1; i--; ) {
01296         if (i % 20 == 0)
01297           fprintf (fp, "\n");
01298         fprintf (fp, "0 ");
01299       }
01300       fprintf (fp, "# 1 color for all\n");
01301       FORALLpoints {
01302         if (!qh DELAUNAY || !qh ATinfinity || qh_pointid(point) != qh num_points-1) {
01303           if (qh PRINTdim == 4)
01304             qh_printpoint (fp, NULL, point);
01305           else
01306             qh_printpoint3 (fp, point);
01307         }
01308       }
01309       FOREACHpoint_(qh other_points) {
01310         if (qh PRINTdim == 4)
01311           qh_printpoint (fp, NULL, point);
01312         else
01313           qh_printpoint3 (fp, point);
01314       }
01315       fprintf (fp, "0 1 1 1  # color of points\n");
01316     }
01317     if (qh PRINTdim == 4  && !qh PRINTnoplanes)
01318       /* 4dview loads up multiple 4OFF objects slowly */
01319       fprintf(fp, "4OFF %d %d 1\n", 3*qh ridgeoutnum, qh ridgeoutnum);
01320     qh PRINTcradius= 2 * qh DISTround;  /* include test DISTround */
01321     if (qh PREmerge) {
01322       maximize_(qh PRINTcradius, qh premerge_centrum + qh DISTround);
01323     }else if (qh POSTmerge)
01324       maximize_(qh PRINTcradius, qh postmerge_centrum + qh DISTround);
01325     qh PRINTradius= qh PRINTcradius;
01326     if (qh PRINTspheres + qh PRINTcoplanar)
01327       maximize_(qh PRINTradius, qh MAXabs_coord * qh_MINradius);
01328     if (qh premerge_cos < REALmax/2) {
01329       maximize_(qh PRINTradius, (1- qh premerge_cos) * qh MAXabs_coord);
01330     }else if (!qh PREmerge && qh POSTmerge && qh postmerge_cos < REALmax/2) {
01331       maximize_(qh PRINTradius, (1- qh postmerge_cos) * qh MAXabs_coord);
01332     }
01333     maximize_(qh PRINTradius, qh MINvisible); 
01334     if (qh JOGGLEmax < REALmax/2)
01335       qh PRINTradius += qh JOGGLEmax * sqrt (qh hull_dim);
01336     if (qh PRINTdim != 4 &&
01337         (qh PRINTcoplanar || qh PRINTspheres || qh PRINTcentrums)) {
01338       vertices= qh_facetvertices (facetlist, facets, printall);
01339       if (qh PRINTspheres && qh PRINTdim <= 3)
01340          qh_printspheres (fp, vertices, qh PRINTradius);
01341       if (qh PRINTcoplanar || qh PRINTcentrums) {
01342         qh firstcentrum= True;
01343         if (qh PRINTcoplanar&& !qh PRINTspheres) {
01344           FOREACHvertex_(vertices) 
01345             qh_printpointvect2 (fp, vertex->point, NULL,
01346                                 qh interior_point, qh PRINTradius);
01347         }
01348         FORALLfacet_(facetlist) {
01349           if (!printall && qh_skipfacet(facet))
01350             continue;
01351           if (!facet->normal)
01352             continue;
01353           if (qh PRINTcentrums && qh PRINTdim <= 3)
01354             qh_printcentrum (fp, facet, qh PRINTcradius);
01355           if (!qh PRINTcoplanar)
01356             continue;
01357           FOREACHpoint_(facet->coplanarset)
01358             qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
01359           FOREACHpoint_(facet->outsideset)
01360             qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
01361         }
01362         FOREACHfacet_(facets) {
01363           if (!printall && qh_skipfacet(facet))
01364             continue;
01365           if (!facet->normal)
01366             continue;
01367           if (qh PRINTcentrums && qh PRINTdim <= 3)
01368             qh_printcentrum (fp, facet, qh PRINTcradius);
01369           if (!qh PRINTcoplanar)
01370             continue;
01371           FOREACHpoint_(facet->coplanarset)
01372             qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
01373           FOREACHpoint_(facet->outsideset)
01374             qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
01375         }
01376       }
01377       qh_settempfree (&vertices);
01378     }
01379     qh visit_id++; /* for printing hyperplane intersections */
01380     break;
01381   case qh_PRINTids:
01382     fprintf (fp, "%d\n", numfacets);
01383     break;
01384   case qh_PRINTincidences:
01385     if (qh VORONOI && qh PRINTprecision)
01386       fprintf (qh ferr, "qhull warning: writing Delaunay.  Use 'p' or 'o' for Voronoi centers\n");
01387     qh printoutvar= qh vertex_id;  /* centrum id for non-simplicial facets */
01388     if (qh hull_dim <= 3)
01389       fprintf(fp, "%d\n", numfacets);
01390     else
01391       fprintf(fp, "%d\n", numsimplicial+numridges);
01392     break;
01393   case qh_PRINTinner:
01394   case qh_PRINTnormals:
01395   case qh_PRINTouter:
01396     if (qh CDDoutput)
01397       fprintf (fp, "%s | %s\nbegin\n    %d %d real\n", qh rbox_command, 
01398               qh qhull_command, numfacets, qh hull_dim+1);
01399     else
01400       fprintf (fp, "%d\n%d\n", qh hull_dim+1, numfacets);
01401     break;
01402   case qh_PRINTmathematica:  
01403     if (qh hull_dim > 3)  /* qh_initbuffers also checks */
01404       goto LABELnoformat;
01405     if (qh VORONOI)
01406       fprintf (qh ferr, "qhull warning: output is the Delaunay triangulation\n");
01407     fprintf(fp, "{\n");
01408     qh printoutvar= 0;   /* counts number of facets for notfirst */
01409     break;
01410   case qh_PRINTmerges:
01411     fprintf (fp, "%d\n", numfacets);
01412     break;
01413   case qh_PRINTpointintersect:
01414     fprintf (fp, "%d\n%d\n", qh hull_dim, numfacets);
01415     break;
01416   case qh_PRINTneighbors:
01417     fprintf (fp, "%d\n", numfacets);
01418     break;
01419   case qh_PRINToff:
01420   case qh_PRINTtriangles:
01421     if (qh VORONOI)
01422       goto LABELnoformat;
01423     num = qh hull_dim;
01424     if (format == qh_PRINToff || qh hull_dim == 2)
01425       fprintf (fp, "%d\n%d %d %d\n", num, 
01426         qh num_points+qh_setsize (qh other_points), numfacets, totneighbors/2);
01427     else { /* qh_PRINTtriangles */
01428       qh printoutvar= qh num_points+qh_setsize (qh other_points); /* first centrum */
01429       if (qh DELAUNAY)
01430         num--;  /* drop last dimension */
01431       fprintf (fp, "%d\n%d %d %d\n", num, qh printoutvar 
01432         + numfacets - numsimplicial, numsimplicial + numridges, totneighbors/2);
01433     }
01434     FORALLpoints
01435       qh_printpointid (qh fout, NULL, num, point, -1);
01436     FOREACHpoint_(qh other_points)
01437       qh_printpointid (qh fout, NULL, num, point, -1);
01438     if (format == qh_PRINTtriangles && qh hull_dim > 2) {
01439       FORALLfacets {
01440         if (!facet->simplicial && facet->visitid)
01441           qh_printcenter (qh fout, format, NULL, facet);
01442       }
01443     }
01444     break;
01445   case qh_PRINTpointnearest:
01446     fprintf (fp, "%d\n", numcoplanars);
01447     break;
01448   case qh_PRINTpoints:
01449     if (!qh VORONOI)
01450       goto LABELnoformat;
01451     if (qh CDDoutput)
01452       fprintf (fp, "%s | %s\nbegin\n%d %d real\n", qh rbox_command,
01453              qh qhull_command, numfacets, qh hull_dim);
01454     else
01455       fprintf (fp, "%d\n%d\n", qh hull_dim-1, numfacets);
01456     break;
01457   case qh_PRINTvertices:
01458     fprintf (fp, "%d\n", numfacets);
01459     break;
01460   case qh_PRINTsummary:
01461   default:
01462   LABELnoformat:
01463     fprintf (qh ferr, "qhull internal error (qh_printbegin): can not use this format for dimension %d\n",
01464          qh hull_dim);
01465     qh_errexit (qh_ERRqhull, NULL, NULL);
01466   }
01467 } /* printbegin */
01468 
01469 /*-<a                             href="qh-io.htm#TOC"
01470   >-------------------------------</a><a name="printcenter">-</a>
01471   
01472   qh_printcenter( fp, string, facet )
01473     print facet->center as centrum or Voronoi center
01474     string may be NULL.  Don't include '%' codes.
01475     nop if qh CENTERtype neither CENTERvoronoi nor CENTERcentrum
01476     if upper envelope of Delaunay triangulation and point at-infinity
01477       prints qh_INFINITE instead;
01478 
01479   notes:
01480     defines facet->center if needed
01481     if format=PRINTgeom, adds a 0 if would otherwise be 2-d
01482 */
01483 void qh_printcenter (FILE *fp, int format, char *string, facetT *facet) {
01484   int k, num;
01485 
01486   if (qh CENTERtype != qh_ASvoronoi && qh CENTERtype != qh_AScentrum)
01487     return;
01488   if (string)
01489     fprintf (fp, string, facet->id);
01490   if (qh CENTERtype == qh_ASvoronoi) {
01491     num= qh hull_dim-1;
01492     if (!facet->normal || !facet->upperdelaunay || !qh ATinfinity) {
01493       if (!facet->center)
01494         facet->center= qh_facetcenter (facet->vertices);
01495       for (k=0; k < num; k++)
01496         fprintf (fp, qh_REAL_1, facet->center[k]);
01497     }else {
01498       for (k=0; k < num; k++)
01499         fprintf (fp, qh_REAL_1, qh_INFINITE);
01500     }
01501   }else /* qh CENTERtype == qh_AScentrum */ {
01502     num= qh hull_dim;
01503     if (format == qh_PRINTtriangles && qh DELAUNAY) 
01504       num--;
01505     if (!facet->center) 
01506       facet->center= qh_getcentrum (facet);
01507     for (k=0; k < num; k++)
01508       fprintf (fp, qh_REAL_1, facet->center[k]);
01509   }
01510   if (format == qh_PRINTgeom && num == 2)
01511     fprintf (fp, " 0\n");
01512   else
01513     fprintf (fp, "\n");
01514 } /* printcenter */
01515 
01516 /*-<a                             href="qh-io.htm#TOC"
01517   >-------------------------------</a><a name="printcentrum">-</a>
01518   
01519   qh_printcentrum( fp, facet, radius )
01520     print centrum for a facet in OOGL format
01521     radius defines size of centrum
01522     2-d or 3-d only
01523 
01524   returns:
01525     defines facet->center if needed
01526 */
01527 void qh_printcentrum (FILE *fp, facetT *facet, realT radius) {
01528   pointT *centrum, *projpt;
01529   boolT tempcentrum= False;
01530   realT xaxis[4], yaxis[4], normal[4], dist;
01531   realT green[3]={0, 1, 0};
01532   vertexT *apex;
01533   int k;
01534   
01535   if (qh CENTERtype == qh_AScentrum) {
01536     if (!facet->center)
01537       facet->center= qh_getcentrum (facet);
01538     centrum= facet->center;
01539   }else {
01540     centrum= qh_getcentrum (facet);
01541     tempcentrum= True;
01542   }
01543   fprintf (fp, "{appearance {-normal -edge normscale 0} ");
01544   if (qh firstcentrum) {
01545     qh firstcentrum= False;
01546     fprintf (fp, "{INST geom { define centrum CQUAD  # f%d\n\
01547 -0.3 -0.3 0.0001     0 0 1 1\n\
01548  0.3 -0.3 0.0001     0 0 1 1\n\
01549  0.3  0.3 0.0001     0 0 1 1\n\
01550 -0.3  0.3 0.0001     0 0 1 1 } transform { \n", facet->id);
01551   }else
01552     fprintf (fp, "{INST geom { : centrum } transform { # f%d\n", facet->id);
01553   apex= SETfirstt_(facet->vertices, vertexT);
01554   qh_distplane(apex->point, facet, &dist);
01555   projpt= qh_projectpoint(apex->point, facet, dist);
01556   for (k= qh hull_dim; k--; ) {
01557     xaxis[k]= projpt[k] - centrum[k];
01558     normal[k]= facet->normal[k];
01559   }
01560   if (qh hull_dim == 2) {
01561     xaxis[2]= 0;
01562     normal[2]= 0;
01563   }else if (qh hull_dim == 4) {
01564     qh_projectdim3 (xaxis, xaxis);
01565     qh_projectdim3 (normal, normal);
01566     qh_normalize2 (normal, qh PRINTdim, True, NULL, NULL);
01567   }
01568   qh_crossproduct (3, xaxis, normal, yaxis);
01569   fprintf (fp, "%8.4g %8.4g %8.4g 0\n", xaxis[0], xaxis[1], xaxis[2]);
01570   fprintf (fp, "%8.4g %8.4g %8.4g 0\n", yaxis[0], yaxis[1], yaxis[2]);
01571   fprintf (fp, "%8.4g %8.4g %8.4g 0\n", normal[0], normal[1], normal[2]);
01572   qh_printpoint3 (fp, centrum);
01573   fprintf (fp, "1 }}}\n"); 
01574   qh_memfree (projpt, qh normal_size);
01575   qh_printpointvect (fp, centrum, facet->normal, NULL, radius, green);
01576   if (tempcentrum)
01577     qh_memfree (centrum, qh normal_size);
01578 } /* printcentrum */
01579   
01580 /*-<a                             href="qh-io.htm#TOC"
01581   >-------------------------------</a><a name="printend">-</a>
01582   
01583   qh_printend( fp, format )
01584     prints trailer for all output formats
01585 
01586   see:
01587     qh_printbegin() and qh_printafacet()
01588       
01589 */
01590 void qh_printend (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
01591   int num;
01592   facetT *facet, **facetp;
01593 
01594   if (!qh printoutnum)
01595     fprintf (qh ferr, "qhull warning: no facets printed\n");
01596   switch (format) {
01597   case qh_PRINTgeom:
01598     if (qh hull_dim == 4 && qh DROPdim < 0  && !qh PRINTnoplanes) {
01599       qh visit_id++;
01600       num= 0;
01601       FORALLfacet_(facetlist)
01602         qh_printend4geom (fp, facet,&num, printall);
01603       FOREACHfacet_(facets) 
01604         qh_printend4geom (fp, facet, &num, printall);
01605       if (num != qh ridgeoutnum || qh printoutvar != qh ridgeoutnum) {
01606         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);
01607         qh_errexit (qh_ERRqhull, NULL, NULL);
01608       }
01609     }else
01610       fprintf(fp, "}\n");
01611     break;
01612   case qh_PRINTinner:
01613   case qh_PRINTnormals:
01614   case qh_PRINTouter:
01615     if (qh CDDoutput) 
01616       fprintf (fp, "end\n");
01617     break;
01618   case qh_PRINTmathematica:
01619     fprintf(fp, "}\n");
01620     break;
01621   case qh_PRINTpoints:
01622     if (qh CDDoutput)
01623       fprintf (fp, "end\n");
01624     break;
01625   }
01626 } /* printend */
01627 
01628 /*-<a                             href="qh-io.htm#TOC"
01629   >-------------------------------</a><a name="printend4geom">-</a>
01630   
01631   qh_printend4geom( fp, facet, numridges, printall )
01632     helper function for qh_printbegin/printend
01633 
01634   returns:
01635     number of printed ridges
01636   
01637   notes:
01638     just counts printed ridges if fp=NULL
01639     uses facet->visitid
01640     must agree with qh_printfacet4geom...
01641 
01642   design:
01643     computes color for facet from its normal
01644     prints each ridge of facet 
01645 */
01646 void qh_printend4geom (FILE *fp, facetT *facet, int *nump, boolT printall) {
01647   realT color[3];
01648   int i, num= *nump;
01649   facetT *neighbor, **neighborp;
01650   ridgeT *ridge, **ridgep;
01651   
01652   if (!printall && qh_skipfacet(facet))
01653     return;
01654   if (qh PRINTnoplanes || (facet->visible && qh NEWfacets))
01655     return;
01656   if (!facet->normal)
01657     return;
01658   if (fp) {
01659     for (i=0; i < 3; i++) {
01660       color[i]= (facet->normal[i]+1.0)/2.0;
01661       maximize_(color[i], -1.0);
01662       minimize_(color[i], +1.0);
01663     }
01664   }
01665   facet->visitid= qh visit_id;
01666   if (facet->simplicial) {
01667     FOREACHneighbor_(facet) {
01668       if (neighbor->visitid != qh visit_id) {
01669         if (fp)
01670           fprintf (fp, "3 %d %d %d %8.4g %8.4g %8.4g 1 # f%d f%d\n",
01671                  3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],
01672                  facet->id, neighbor->id);
01673         num++;
01674       }
01675     }
01676   }else {
01677     FOREACHridge_(facet->ridges) {
01678       neighbor= otherfacet_(ridge, facet);
01679       if (neighbor->visitid != qh visit_id) {
01680         if (fp)
01681           fprintf (fp, "3 %d %d %d %8.4g %8.4g %8.4g 1 #r%d f%d f%d\n",
01682                  3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],
01683                  ridge->id, facet->id, neighbor->id);
01684         num++;
01685       }
01686     }
01687   }
01688   *nump= num;
01689 } /* printend4geom */
01690 
01691 /*-<a                             href="qh-io.htm#TOC"
01692   >-------------------------------</a><a name="printextremes">-</a>
01693   
01694   qh_printextremes( fp, facetlist, facets, printall )
01695     print extreme points for convex hulls or halfspace intersections
01696 
01697   notes:
01698     #points, followed by ids, one per line
01699     
01700     sorted by id
01701     same order as qh_printpoints_out if no coplanar/interior points
01702 */
01703 void qh_printextremes (FILE *fp, facetT *facetlist, setT *facets, int printall) {
01704   setT *vertices, *points;
01705   pointT *point;
01706   vertexT *vertex, **vertexp;
01707   int id;
01708   int numpoints=0, point_i, point_n;
01709   int allpoints= qh num_points + qh_setsize (qh other_points);
01710 
01711   points= qh_settemp (allpoints);
01712   qh_setzero (points, 0, allpoints);
01713   vertices= qh_facetvertices (facetlist, facets, printall);
01714   FOREACHvertex_(vertices) {
01715     id= qh_pointid (vertex->point);
01716     if (id >= 0) {
01717       SETelem_(points, id)= vertex->point;
01718       numpoints++;
01719     }
01720   }
01721   qh_settempfree (&vertices);
01722   fprintf (fp, "%d\n", numpoints);
01723   FOREACHpoint_i_(points) {
01724     if (point) 
01725       fprintf (fp, "%d\n", point_i);
01726   }
01727   qh_settempfree (&points);
01728 } /* printextremes */
01729 
01730 /*-<a                             href="qh-io.htm#TOC"
01731   >-------------------------------</a><a name="printextremes_2d">-</a>
01732   
01733   qh_printextremes_2d( fp, facetlist, facets, printall )
01734     prints point ids for facets in qh_ORIENTclock order
01735 
01736   notes:
01737     #points, followed by ids, one per line
01738     if facetlist/facets are disjoint than the output includes skips
01739     errors if facets form a loop
01740     does not print coplanar points
01741 */
01742 void qh_printextremes_2d (FILE *fp, facetT *facetlist, setT *facets, int printall) {
01743   int numfacets, numridges, totneighbors, numcoplanars, numsimplicial;
01744   setT *vertices;
01745   facetT *facet, *startfacet, *nextfacet;
01746   vertexT *vertexA, *vertexB;
01747 
01748   qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial, 
01749       &totneighbors, &numridges, &numcoplanars); /* marks qh visit_id */
01750   vertices= qh_facetvertices (facetlist, facets, printall);
01751   fprintf(fp, "%d\n", qh_setsize (vertices));
01752   qh_settempfree (&vertices);
01753   if (!numfacets)
01754     return;
01755   facet= startfacet= facetlist ? facetlist : SETfirstt_(facets, facetT);
01756   qh vertex_visit++;
01757   qh visit_id++;
01758   do {
01759     if (facet->toporient ^ qh_ORIENTclock) {
01760       vertexA= SETfirstt_(facet->vertices, vertexT);
01761       vertexB= SETsecondt_(facet->vertices, vertexT);
01762       nextfacet= SETfirstt_(facet->neighbors, facetT);
01763     }else {
01764       vertexA= SETsecondt_(facet->vertices, vertexT);
01765       vertexB= SETfirstt_(facet->vertices, vertexT);
01766       nextfacet= SETsecondt_(facet->neighbors, facetT);
01767     }
01768     if (facet->visitid == qh visit_id) {
01769       fprintf(qh ferr, "qh_printextremes_2d: loop in facet list.  facet %d nextfacet %d\n",
01770                  facet->id, nextfacet->id);
01771       qh_errexit2 (qh_ERRqhull, facet, nextfacet);
01772     }
01773     if (facet->visitid) {
01774       if (vertexA->visitid != qh vertex_visit) {
01775         vertexA->visitid= qh vertex_visit;
01776         fprintf(fp, "%d\n", qh_pointid (vertexA->point));
01777       }
01778       if (vertexB->visitid != qh vertex_visit) {
01779         vertexB->visitid= qh vertex_visit;
01780         fprintf(fp, "%d\n", qh_pointid (vertexB->point));
01781       }
01782     }
01783     facet->visitid= qh visit_id;
01784     facet= nextfacet;
01785   }while (facet && facet != startfacet);
01786 } /* printextremes_2d */
01787 
01788 /*-<a                             href="qh-io.htm#TOC"
01789   >-------------------------------</a><a name="printextremes_d">-</a>
01790   
01791   qh_printextremes_d( fp, facetlist, facets, printall )
01792     print extreme points of input sites for Delaunay triangulations
01793 
01794   notes:
01795     #points, followed by ids, one per line
01796     
01797     unordered
01798 */
01799 void qh_printextremes_d (FILE *fp, facetT *facetlist, setT *facets, int printall) {
01800   setT *vertices;
01801   vertexT *vertex, **vertexp;
01802   boolT upperseen, lowerseen;
01803   facetT *neighbor, **neighborp;
01804   int numpoints=0;
01805 
01806   vertices= qh_facetvertices (facetlist, facets, printall);
01807   qh_vertexneighbors();
01808   FOREACHvertex_(vertices) {
01809     upperseen= lowerseen= False;
01810     FOREACHneighbor_(vertex) {
01811       if (neighbor->upperdelaunay)
01812         upperseen= True;
01813       else
01814         lowerseen= True;
01815     }
01816     if (upperseen && lowerseen) {
01817       vertex->seen= True;
01818       numpoints++;
01819     }else
01820       vertex->seen= False;
01821   }
01822   fprintf (fp, "%d\n", numpoints);
01823   FOREACHvertex_(vertices) {
01824     if (vertex->seen)
01825       fprintf (fp, "%d\n", qh_pointid (vertex->point));
01826   }
01827   qh_settempfree (&vertices);
01828 } /* printextremes_d */
01829 
01830 /*-<a                             href="qh-io.htm#TOC"
01831   >-------------------------------</a><a name="printfacet">-</a>
01832   
01833   qh_printfacet( fp, facet )
01834     prints all fields of a facet to fp
01835 
01836   notes:
01837     ridges printed in neighbor order
01838 */
01839 void qh_printfacet(FILE *fp, facetT *facet) {
01840 
01841   qh_printfacetheader (fp, facet);
01842   if (facet->ridges)
01843     qh_printfacetridges (fp, facet);
01844 } /* printfacet */
01845 
01846 
01847 /*-<a                             href="qh-io.htm#TOC"
01848   >-------------------------------</a><a name="printfacet2geom">-</a>
01849   
01850   qh_printfacet2geom( fp, facet, color )
01851     print facet as part of a 2-d VECT for Geomview
01852   
01853     notes:
01854       assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
01855       mindist is calculated within io.c.  maxoutside is calculated elsewhere
01856       so a DISTround error may have occured.
01857 */
01858 void qh_printfacet2geom(FILE *fp, facetT *facet, realT color[3]) {
01859   pointT *point0, *point1;
01860   realT mindist, innerplane, outerplane;
01861   int k;
01862 
01863   qh_facet2point (facet, &point0, &point1, &mindist);
01864   qh_geomplanes (facet, &outerplane, &innerplane);
01865   if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner))
01866     qh_printfacet2geom_points(fp, point0, point1, facet, outerplane, color);
01867   if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter &&
01868                 outerplane - innerplane > 2 * qh MAXabs_coord * qh_GEOMepsilon)) {
01869     for(k= 3; k--; )
01870       color[k]= 1.0 - color[k];
01871     qh_printfacet2geom_points(fp, point0, point1, facet, innerplane, color);
01872   }
01873   qh_memfree (point1, qh normal_size);
01874   qh_memfree (point0, qh normal_size); 
01875 } /* printfacet2geom */
01876 
01877 /*-<a                             href="qh-io.htm#TOC"
01878   >-------------------------------</a><a name="printfacet2geom_points">-</a>
01879   
01880   qh_printfacet2geom_points( fp, point1, point2, facet, offset, color )
01881     prints a 2-d facet as a VECT with 2 points at some offset.   
01882     The points are on the facet's plane.
01883 */
01884 void qh_printfacet2geom_points(FILE *fp, pointT *point1, pointT *point2,
01885                                facetT *facet, realT offset, realT color[3]) {
01886   pointT *p1= point1, *p2= point2;
01887 
01888   fprintf(fp, "VECT 1 2 1 2 1 # f%d\n", facet->id);
01889   if (offset != 0.0) {
01890     p1= qh_projectpoint (p1, facet, -offset);
01891     p2= qh_projectpoint (p2, facet, -offset);
01892   }
01893   fprintf(fp, "%8.4g %8.4g %8.4g\n%8.4g %8.4g %8.4g\n",
01894            p1[0], p1[1], 0.0, p2[0], p2[1], 0.0);
01895   if (offset != 0.0) {
01896     qh_memfree (p1, qh normal_size);
01897     qh_memfree (p2, qh normal_size);
01898   }
01899   fprintf(fp, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
01900 } /* printfacet2geom_points */
01901 
01902 
01903 /*-<a                             href="qh-io.htm#TOC"
01904   >-------------------------------</a><a name="printfacet2math">-</a>
01905   
01906   qh_printfacet2math( fp, facet, notfirst )
01907     print 2-d Mathematica output for a facet
01908     may be non-simplicial
01909 
01910   notes:
01911     use %16.8f since Mathematica 2.2 does not handle exponential format
01912 */
01913 void qh_printfacet2math(FILE *fp, facetT *facet, int notfirst) {
01914   pointT *point0, *point1;
01915   realT mindist;
01916   
01917   qh_facet2point (facet, &point0, &point1, &mindist);
01918   if (notfirst)
01919     fprintf(fp, ",");
01920   fprintf(fp, "Line[{{%16.8f, %16.8f}, {%16.8f, %16.8f}}]\n",
01921           point0[0], point0[1], point1[0], point1[1]);
01922   qh_memfree (point1, qh normal_size);
01923   qh_memfree (point0, qh normal_size);
01924 } /* printfacet2math */
01925 
01926 
01927 /*-<a                             href="qh-io.htm#TOC"
01928   >-------------------------------</a><a name="printfacet3geom_nonsimplicial">-</a>
01929   
01930   qh_printfacet3geom_nonsimplicial( fp, facet, color )
01931     print Geomview OFF for a 3-d nonsimplicial facet.
01932     if DOintersections, prints ridges to unvisited neighbors (qh visit_id) 
01933 
01934   notes
01935     uses facet->visitid for intersections and ridges
01936 */
01937 void qh_printfacet3geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]) {
01938   ridgeT *ridge, **ridgep;
01939   setT *projectedpoints, *vertices;
01940   vertexT *vertex, **vertexp, *vertexA, *vertexB;
01941   pointT *projpt, *point, **pointp;
01942   facetT *neighbor;
01943   realT dist, outerplane, innerplane;
01944   int cntvertices, k;
01945   realT black[3]={0, 0, 0}, green[3]={0, 1, 0};
01946 
01947   qh_geomplanes (facet, &outerplane, &innerplane); 
01948   vertices= qh_facet3vertex (facet); /* oriented */
01949   cntvertices= qh_setsize(vertices);
01950   projectedpoints= qh_settemp(cntvertices);
01951   FOREACHvertex_(vertices) {
01952     zinc_(Zdistio);
01953     qh_distplane(vertex->point, facet, &dist);
01954     projpt= qh_projectpoint(vertex->point, facet, dist);
01955     qh_setappend (&projectedpoints, projpt);
01956   }
01957   if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner))
01958     qh_printfacet3geom_points(fp, projectedpoints, facet, outerplane, color);
01959   if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter &&
01960                 outerplane - innerplane > 2 * qh MAXabs_coord * qh_GEOMepsilon)) {
01961     for (k=3; k--; )
01962       color[k]= 1.0 - color[k];
01963     qh_printfacet3geom_points(fp, projectedpoints, facet, innerplane, color);
01964   }
01965   FOREACHpoint_(projectedpoints)
01966     qh_memfree (point, qh normal_size);
01967   qh_settempfree(&projectedpoints);
01968   qh_settempfree(&vertices);
01969   if ((qh DOintersections || qh PRINTridges)
01970   && (!facet->visible || !qh NEWfacets)) {
01971     facet->visitid= qh visit_id;
01972     FOREACHridge_(facet->ridges) {
01973       neighbor= otherfacet_(ridge, facet);
01974       if (neighbor->visitid != qh visit_id) {
01975         if (qh DOintersections)
01976           qh_printhyperplaneintersection(fp, facet, neighbor, ridge->vertices, black);
01977         if (qh PRINTridges) {
01978           vertexA= SETfirstt_(ridge->vertices, vertexT);
01979           vertexB= SETsecondt_(ridge->vertices, vertexT);
01980           qh_printline3geom (fp, vertexA->point, vertexB->point, green);
01981         }
01982       }
01983     }
01984   }
01985 } /* printfacet3geom_nonsimplicial */
01986 
01987 /*-<a                             href="qh-io.htm#TOC"
01988   >-------------------------------</a><a name="printfacet3geom_points">-</a>
01989   
01990   qh_printfacet3geom_points( fp, points, facet, offset )
01991     prints a 3-d facet as OFF Geomview object. 
01992     offset is relative to the facet's hyperplane
01993     Facet is determined as a list of points
01994 */
01995 void qh_printfacet3geom_points(FILE *fp, setT *points, facetT *facet, realT offset, realT color[3]) {
01996   int k, n= qh_setsize(points), i;
01997   pointT *point, **pointp;
01998   setT *printpoints;
01999 
02000   fprintf(fp, "{ OFF %d 1 1 # f%d\n", n, facet->id);
02001   if (offset != 0.0) {
02002     printpoints= qh_settemp (n);
02003     FOREACHpoint_(points) 
02004       qh_setappend (&printpoints, qh_projectpoint(point, facet, -offset));
02005   }else
02006     printpoints= points;
02007   FOREACHpoint_(printpoints) {
02008     for (k=0; k < qh hull_dim; k++) {
02009       if (k == qh DROPdim)
02010         fprintf(fp, "0 ");
02011       else
02012         fprintf(fp, "%8.4g ", point[k]);
02013     }
02014     if (printpoints != points)
02015       qh_memfree (point, qh normal_size);
02016     fprintf (fp, "\n");
02017   }
02018   if (printpoints != points)
02019     qh_settempfree (&printpoints);
02020   fprintf(fp, "%d ", n);
02021   for(i= 0; i < n; i++)
02022     fprintf(fp, "%d ", i);
02023   fprintf(fp, "%8.4g %8.4g %8.4g 1.0 }\n", color[0], color[1], color[2]);
02024 } /* printfacet3geom_points */
02025 
02026 
02027 /*-<a                             href="qh-io.htm#TOC"
02028   >-------------------------------</a><a name="printfacet3geom_simplicial">-</a>
02029   
02030   qh_printfacet3geom_simplicial(  )
02031     print Geomview OFF for a 3-d simplicial facet.
02032 
02033   notes:
02034     may flip color
02035     uses facet->visitid for intersections and ridges
02036 
02037     assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
02038     innerplane may be off by qh DISTround.  Maxoutside is calculated elsewhere
02039     so a DISTround error may have occured.
02040 */
02041 void qh_printfacet3geom_simplicial(FILE *fp, facetT *facet, realT color[3]) {
02042   setT *points, *vertices;
02043   vertexT *vertex, **vertexp, *vertexA, *vertexB;
02044   facetT *neighbor, **neighborp;
02045   realT outerplane, innerplane;
02046   realT black[3]={0, 0, 0}, green[3]={0, 1, 0};
02047   int k;
02048 
02049   qh_geomplanes (facet, &outerplane, &innerplane); 
02050   vertices= qh_facet3vertex (facet);
02051   points= qh_settemp (qh TEMPsize);
02052   FOREACHvertex_(vertices)
02053     qh_setappend(&points, vertex->point);
02054   if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner))
02055     qh_printfacet3geom_points(fp, points, facet, outerplane, color);
02056   if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter &&
02057               outerplane - innerplane > 2 * qh MAXabs_coord * qh_GEOMepsilon)) {
02058     for (k= 3; k--; )
02059       color[k]= 1.0 - color[k];
02060     qh_printfacet3geom_points(fp, points, facet, innerplane, color);
02061   }
02062   qh_settempfree(&points);
02063   qh_settempfree(&vertices);
02064   if ((qh DOintersections || qh PRINTridges)
02065   && (!facet->visible || !qh NEWfacets)) {
02066     facet->visitid= qh visit_id;
02067     FOREACHneighbor_(facet) {
02068       if (neighbor->visitid != qh visit_id) {
02069         vertices= qh_setnew_delnthsorted (facet->vertices, qh hull_dim,
02070                           SETindex_(facet->neighbors, neighbor), 0);
02071         if (qh DOintersections)
02072            qh_printhyperplaneintersection(fp, facet, neighbor, vertices, black); 
02073         if (qh PRINTridges) {
02074           vertexA= SETfirstt_(vertices, vertexT);
02075           vertexB= SETsecondt_(vertices, vertexT);
02076           qh_printline3geom (fp, vertexA->point, vertexB->point, green);
02077         }
02078         qh_setfree(&vertices);
02079       }
02080     }
02081   }
02082 } /* printfacet3geom_simplicial */
02083 
02084 /*-<a                             href="qh-io.htm#TOC"
02085   >-------------------------------</a><a name="printfacet3math">-</a>
02086   
02087   qh_printfacet3math( fp, facet, notfirst )
02088     print 3-d Mathematica output for a facet
02089 
02090   notes:
02091     may be non-simplicial
02092     use %16.8f since Mathematica 2.2 does not handle exponential format
02093 */
02094 void qh_printfacet3math (FILE *fp, facetT *facet, int notfirst) {
02095   vertexT *vertex, **vertexp;
02096   setT *points, *vertices;
02097   pointT *point, **pointp;
02098   boolT firstpoint= True;
02099   realT dist;
02100   
02101   if (notfirst)
02102     fprintf(fp, ",\n");
02103   vertices= qh_facet3vertex (facet);
02104   points= qh_settemp (qh_setsize (vertices));
02105   FOREACHvertex_(vertices) {
02106     zinc_(Zdistio);
02107     qh_distplane(vertex->point, facet, &dist);
02108     point= qh_projectpoint(vertex->point, facet, dist);
02109     qh_setappend (&points, point);
02110   }
02111   fprintf(fp, "Polygon[{");
02112   FOREACHpoint_(points) {
02113     if (firstpoint)
02114       firstpoint= False;
02115     else
02116       fprintf(fp, ",\n");
02117     fprintf(fp, "{%16.8f, %16.8f, %16.8f}", point[0], point[1], point[2]);
02118   }
02119   FOREACHpoint_(points)
02120     qh_memfree (point, qh normal_size);
02121   qh_settempfree(&points);
02122   qh_settempfree(&vertices);
02123   fprintf(fp, "}]");
02124 } /* printfacet3math */
02125 
02126 
02127 /*-<a                             href="qh-io.htm#TOC"
02128   >-------------------------------</a><a name="printfacet3vertex">-</a>
02129   
02130   qh_printfacet3vertex( fp, facet, format )
02131     print vertices in a 3-d facet as point ids
02132 
02133   notes:
02134     prints number of vertices first if format == qh_PRINToff
02135     the facet may be non-simplicial
02136 */
02137 void qh_printfacet3vertex(FILE *fp, facetT *facet, int format) {
02138   vertexT *vertex, **vertexp;
02139   setT *vertices;
02140 
02141   vertices= qh_facet3vertex (facet);
02142   if (format == qh_PRINToff)
02143     fprintf (fp, "%d ", qh_setsize (vertices));
02144   FOREACHvertex_(vertices) 
02145     fprintf (fp, "%d ", qh_pointid(vertex->point));
02146   fprintf (fp, "\n");
02147   qh_settempfree(&vertices);
02148 } /* printfacet3vertex */
02149 
02150 
02151 /*-<a                             href="qh-io.htm#TOC"
02152   >-------------------------------</a><a name="printfacet4geom_nonsimplicial">-</a>
02153   
02154   qh_printfacet4geom_nonsimplicial(  )
02155     print Geomview 4OFF file for a 4d nonsimplicial facet
02156     prints all ridges to unvisited neighbors (qh.visit_id)
02157     if qh.DROPdim
02158       prints in OFF format
02159   
02160   notes:
02161     must agree with printend4geom()
02162 */
02163 void qh_printfacet4geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]) {
02164   facetT *neighbor;
02165   ridgeT *ridge, **ridgep;
02166   vertexT *vertex, **vertexp;
02167   pointT *point;
02168   int k;
02169   realT dist;
02170   
02171   facet->visitid= qh visit_id;
02172   if (qh PRINTnoplanes || (facet->visible && qh NEWfacets))
02173     return;
02174   FOREACHridge_(facet->ridges) {
02175     neighbor= otherfacet_(ridge, facet);
02176     if (neighbor->visitid == qh visit_id) 
02177       continue;
02178     if (qh PRINTtransparent && !neighbor->good)
02179       continue;  
02180     if (qh DOintersections)
02181       qh_printhyperplaneintersection(fp, facet, neighbor, ridge->vertices, color);
02182     else {
02183       if (qh DROPdim >= 0) 
02184         fprintf(fp, "OFF 3 1 1 # f%d\n", facet->id);
02185       else {
02186         qh printoutvar++;
02187         fprintf (fp, "# r%d between f%d f%d\n", ridge->id, facet->id, neighbor->id);
02188       }
02189       FOREACHvertex_(ridge->vertices) {
02190         zinc_(Zdistio);
02191         qh_distplane(vertex->point,facet, &dist);
02192         point=qh_projectpoint(vertex->point,facet, dist);
02193         for(k= 0; k < qh hull_dim; k++) {
02194           if (k != qh DROPdim)
02195             fprintf(fp, "%8.4g ", point[k]);
02196         }
02197         fprintf (fp, "\n");
02198         qh_memfree (point, qh normal_size);
02199       }
02200       if (qh DROPdim >= 0)
02201         fprintf(fp, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);
02202     }
02203   }
02204 } /* printfacet4geom_nonsimplicial */
02205 
02206 
02207 /*-<a                             href="qh-io.htm#TOC"
02208   >-------------------------------</a><a name="printfacet4geom_simplicial">-</a>
02209   
02210   qh_printfacet4geom_simplicial( fp, facet, color )
02211     print Geomview 4OFF file for a 4d simplicial facet
02212     prints triangles for unvisited neighbors (qh.visit_id)
02213 
02214   notes:
02215     must agree with printend4geom()
02216 */
02217 void qh_printfacet4geom_simplicial(FILE *fp, facetT *facet, realT color[3]) {
02218   setT *vertices;
02219   facetT *neighbor, **neighborp;
02220   vertexT *vertex, **vertexp;
02221   int k;
02222   
02223   facet->visitid= qh visit_id;
02224   if (qh PRINTnoplanes || (facet->visible && qh NEWfacets))
02225     return;
02226   FOREACHneighbor_(facet) {
02227     if (neighbor->visitid == qh visit_id)
02228       continue;
02229     if (qh PRINTtransparent && !neighbor->good)
02230       continue;  
02231     vertices= qh_setnew_delnthsorted (facet->vertices, qh hull_dim,
02232                           SETindex_(facet->neighbors, neighbor), 0);
02233     if (qh DOintersections)
02234       qh_printhyperplaneintersection(fp, facet, neighbor, vertices, color);
02235     else {
02236       if (qh DROPdim >= 0) 
02237         fprintf(fp, "OFF 3 1 1 # ridge between f%d f%d\n",
02238                 facet->id, neighbor->id);
02239       else {
02240         qh printoutvar++;
02241         fprintf (fp, "# ridge between f%d f%d\n", facet->id, neighbor->id);
02242       }
02243       FOREACHvertex_(vertices) {
02244         for(k= 0; k < qh hull_dim; k++) {
02245           if (k != qh DROPdim)
02246             fprintf(fp, "%8.4g ", vertex->point[k]);
02247         }
02248         fprintf (fp, "\n");
02249       }
02250       if (qh DROPdim >= 0) 
02251         fprintf(fp, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);
02252     }
02253     qh_setfree(&vertices);
02254   }
02255 } /* printfacet4geom_simplicial */
02256 
02257 
02258 /*-<a                             href="qh-io.htm#TOC"
02259   >-------------------------------</a><a name="printfacetNvertex_nonsimplicial">-</a>
02260   
02261   qh_printfacetNvertex_nonsimplicial( fp, facet, id, format )
02262     print vertices for an N-d non-simplicial facet
02263     triangulates each ridge to the id
02264 */
02265 void qh_printfacetNvertex_nonsimplicial(FILE *fp, facetT *facet, int id, int format) {
02266   vertexT *vertex, **vertexp;
02267   ridgeT *ridge, **ridgep;
02268 
02269   if (facet->visible && qh NEWfacets)
02270     return;
02271   FOREACHridge_(facet->ridges) {
02272     if (format == qh_PRINTtriangles)
02273       fprintf(fp, "%d ", qh hull_dim);
02274     fprintf(fp, "%d ", id);
02275     if ((ridge->top == facet) ^ qh_ORIENTclock) {
02276       FOREACHvertex_(ridge->vertices)
02277         fprintf(fp, "%d ", qh_pointid(vertex->point));
02278     }else {
02279       FOREACHvertexreverse12_(ridge->vertices)
02280         fprintf(fp, "%d ", qh_pointid(vertex->point));
02281     }
02282     fprintf(fp, "\n");
02283   }
02284 } /* printfacetNvertex_nonsimplicial */
02285 
02286 
02287 /*-<a                             href="qh-io.htm#TOC"
02288   >-------------------------------</a><a name="printfacetNvertex_simplicial">-</a>
02289   
02290   qh_printfacetNvertex_simplicial( fp, facet, format )
02291     print vertices for an N-d simplicial facet
02292     prints vertices for non-simplicial facets
02293       2-d facets (orientation preserved by qh_mergefacet2d)
02294       PRINToff ('o') for 4-d and higher
02295 */
02296 void qh_printfacetNvertex_simplicial(FILE *fp, facetT *facet, int format) {
02297   vertexT *vertex, **vertexp;
02298 
02299   if (format == qh_PRINToff || format == qh_PRINTtriangles)
02300     fprintf (fp, "%d ", qh_setsize (facet->vertices));
02301   if ((facet->toporient ^ qh_ORIENTclock) 
02302   || (qh hull_dim > 2 && !facet->simplicial)) {
02303     FOREACHvertex_(facet->vertices)
02304       fprintf(fp, "%d ", qh_pointid(vertex->point));
02305   }else {
02306     FOREACHvertexreverse12_(facet->vertices)
02307       fprintf(fp, "%d ", qh_pointid(vertex->point));
02308   }
02309   fprintf(fp, "\n");
02310 } /* printfacetNvertex_simplicial */
02311 
02312 
02313 /*-<a                             href="qh-io.htm#TOC"
02314   >-------------------------------</a><a name="printfacetheader">-</a>
02315   
02316   qh_printfacetheader( fp, facet )
02317     prints header fields of a facet to fp
02318     
02319   notes:
02320     for 'f' output and debugging
02321 */
02322 void qh_printfacetheader(FILE *fp, facetT *facet) {
02323   pointT *point, **pointp, *furthest;
02324   facetT *neighbor, **neighborp;
02325   realT dist;
02326 
02327   if (facet == qh_MERGEridge) {
02328     fprintf (fp, " MERGEridge\n");
02329     return;
02330   }else if (facet == qh_DUPLICATEridge) {
02331     fprintf (fp, " DUPLICATEridge\n");
02332     return;
02333   }else if (!facet) {
02334     fprintf (fp, " NULLfacet\n");
02335     return;
02336   }
02337   qh old_randomdist= qh RANDOMdist;
02338   qh RANDOMdist= False;
02339   fprintf(fp, "- f%d\n", facet->id);
02340   fprintf(fp, "    - flags:");
02341   if (facet->toporient) 
02342     fprintf(fp, " top");
02343   else
02344     fprintf(fp, " bottom");
02345   if (facet->simplicial)
02346     fprintf(fp, " simplicial");
02347   if (facet->upperdelaunay)
02348     fprintf(fp, " upperDelaunay");
02349   if (facet->visible)
02350     fprintf(fp, " visible");
02351   if (facet->newfacet)
02352     fprintf(fp, " new");
02353   if (facet->tested)
02354     fprintf(fp, " tested");
02355   if (!facet->good)
02356     fprintf(fp, " notG");
02357   if (facet->seen)
02358     fprintf(fp, " seen");
02359   if (facet->coplanar)
02360     fprintf(fp, " coplanar");
02361   if (facet->mergehorizon)
02362     fprintf(fp, " mergehorizon");
02363   if (facet->keepcentrum)
02364     fprintf(fp, " keepcentrum");
02365   if (facet->dupridge)
02366     fprintf(fp, " dupridge");
02367   if (facet->mergeridge && !facet->mergeridge2)
02368     fprintf(fp, " mergeridge1");
02369   if (facet->mergeridge2)
02370     fprintf(fp, " mergeridge2");
02371   if (facet->newmerge)
02372     fprintf(fp, " newmerge");
02373   if (facet->flipped) 
02374     fprintf(fp, " flipped");
02375   if (facet->notfurthest) 
02376     fprintf(fp, " notfurthest");
02377   if (facet->degenerate)
02378     fprintf(fp, " degenerate");
02379   if (facet->redundant)
02380     fprintf(fp, " redundant");
02381   fprintf(fp, "\n");
02382   if (facet->isarea)
02383     fprintf(fp, "    - area: %2.2g\n", facet->f.area);
02384   else if (qh NEWfacets && facet->visible && facet->f.replace)
02385     fprintf(fp, "    - replacement: f%d\n", facet->f.replace->id);
02386   else if (facet->newfacet) {
02387     if (facet->f.samecycle && facet->f.samecycle != facet)
02388       fprintf(fp, "    - shares same visible/horizon as f%d\n", facet->f.samecycle->id);
02389   }else if (facet->f.newcycle)
02390     fprintf(fp, "    - was horizon to f%d\n", facet->f.newcycle->id);
02391   if (facet->nummerge)
02392     fprintf(fp, "    - merges: %d\n", facet->nummerge);
02393   qh_printpointid(fp, "    - normal: ", qh hull_dim, facet->normal, -1);
02394   fprintf(fp, "    - offset: %10.7g\n", facet->offset);
02395   if (qh CENTERtype == qh_ASvoronoi || facet->center)
02396     qh_printcenter (fp, qh_PRINTfacets, "    - center: ", facet);
02397 #if qh_MAXoutside
02398   if (facet->maxoutside > qh DISTround)
02399     fprintf(fp, "    - maxoutside: %10.7g\n", facet->maxoutside);
02400 #endif
02401   if (!SETempty_(facet->outsideset)) {
02402     furthest= (pointT*)qh_setlast(facet->outsideset);
02403     if (qh_setsize (facet->outsideset) < 6) {
02404       fprintf(fp, "    - outside set (furthest p%d):\n", qh_pointid(furthest));
02405       FOREACHpoint_(facet->outsideset)
02406         qh_printpoint(fp, "     ", point);
02407     }else if (qh_setsize (facet->outsideset) < 21) {
02408       qh_printpoints(fp, "    - outside set:", facet->outsideset);
02409     }else {
02410       fprintf(fp, "    - outside set:  %d points.", qh_setsize(facet->outsideset));
02411       qh_printpoint(fp, "  Furthest", furthest);
02412     }
02413 #if !qh_COMPUTEfurthest
02414     fprintf(fp, "    - furthest distance= %2.2g\n", facet->furthestdist);
02415 #endif
02416   }
02417   if (!SETempty_(facet->coplanarset)) {
02418     furthest= (pointT*)qh_setlast(facet->coplanarset);
02419     if (qh_setsize (facet->coplanarset) < 6) {
02420       fprintf(fp, "    - coplanar set (furthest p%d):\n", qh_pointid(furthest));
02421       FOREACHpoint_(facet->coplanarset)
02422         qh_printpoint(fp, "     ", point);
02423     }else if (qh_setsize (facet->coplanarset) < 21) {
02424       qh_printpoints(fp, "    - coplanar set:", facet->coplanarset);
02425     }else {
02426       fprintf(fp, "    - coplanar set:  %d points.", qh_setsize(facet->coplanarset));
02427       qh_printpoint(fp, "  Furthest", furthest);
02428     }
02429     zinc_(Zdistio);
02430     qh_distplane (furthest, facet, &dist);
02431     fprintf(fp, "      furthest distance= %2.2g\n", dist);
02432   }
02433   qh_printvertices (fp, "    - vertices:", facet->vertices);
02434   fprintf(fp, "    - neighboring facets: ");
02435   FOREACHneighbor_(facet) {
02436     if (neighbor == qh_MERGEridge)
02437       fprintf(fp, " MERGE");
02438     else if (neighbor == qh_DUPLICATEridge)
02439       fprintf(fp, " DUP");
02440     else
02441       fprintf(fp, " f%d", neighbor->id);
02442   }
02443   fprintf(fp, "\n");
02444   qh RANDOMdist= qh old_randomdist;
02445 } /* printfacetheader */
02446 
02447 
02448 /*-<a                             href="qh-io.htm#TOC"
02449   >-------------------------------</a><a name="printfacetridges">-</a>
02450   
02451   qh_printfacetridges( fp, facet )
02452     prints ridges of a facet to fp
02453 
02454   notes:
02455     ridges printed in neighbor order
02456     assumes the ridges exist
02457     for 'f' output
02458 */
02459 void qh_printfacetridges(FILE *fp, facetT *facet) {
02460   facetT *neighbor, **neighborp;
02461   ridgeT *ridge, **ridgep;
02462   int numridges= 0;
02463 
02464 
02465   if (facet->visible && qh NEWfacets) {
02466     fprintf(fp, "    - ridges (ids may be garbage):");
02467     FOREACHridge_(facet->ridges)
02468       fprintf(fp, " r%d", ridge->id);
02469     fprintf(fp, "\n");
02470   }else {
02471     fprintf(fp, "    - ridges:\n");
02472     FOREACHridge_(facet->ridges)
02473       ridge->seen= False;
02474     if (qh hull_dim == 3) {
02475       ridge= SETfirstt_(facet->ridges, ridgeT);
02476       while (ridge && !ridge->seen) {
02477         ridge->seen= True;
02478         qh_printridge(fp, ridge);
02479         numridges++;
02480         ridge= qh_nextridge3d (ridge, facet, NULL);
02481         }
02482     }else {
02483       FOREACHneighbor_(facet) {
02484         FOREACHridge_(facet->ridges) {
02485           if (otherfacet_(ridge,facet) == neighbor) {
02486             ridge->seen= True;
02487             qh_printridge(fp, ridge);
02488             numridges++;
02489           }
02490         }
02491       }
02492     }
02493     if (numridges != qh_setsize (facet->ridges)) {
02494       fprintf (fp, "     - all ridges:");
02495       FOREACHridge_(facet->ridges) 
02496         fprintf (fp, " r%d", ridge->id);
02497         fprintf (fp, "\n");
02498     }
02499     FOREACHridge_(facet->ridges) {
02500       if (!ridge->seen) 
02501         qh_printridge(fp, ridge);
02502     }
02503   }
02504 } /* printfacetridges */
02505 
02506 /*-<a                             href="qh-io.htm#TOC"
02507   >-------------------------------</a><a name="printfacets">-</a>
02508   
02509   qh_printfacets( fp, format, facetlist, facets, printall )
02510     prints facetlist and/or facet set in output format
02511   
02512   notes:
02513     also used for specialized formats ('FO' and summary)
02514     turns off 'Rn' option since want actual numbers
02515 */
02516 void qh_printfacets(FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
02517   int numfacets, numsimplicial, numridges, totneighbors, numcoplanars;
02518   facetT *facet, **facetp;
02519   setT *vertices;
02520   coordT *center;
02521   realT outerplane, innerplane;
02522 
02523   qh old_randomdist= qh RANDOMdist;
02524   qh RANDOMdist= False;
02525   if (qh CDDoutput && (format == qh_PRINTcentrums || format == qh_PRINTpointintersect || format == qh_PRINToff))
02526     fprintf (qh ferr, "qhull warning: CDD format is not available for centrums, halfspace\nintersections, and OFF file format.\n");
02527   if (format == qh_PRINTnone)
02528     ; /* print nothing */
02529   else if (format == qh_PRINTaverage) {
02530     vertices= qh_facetvertices (facetlist, facets, printall);
02531     center= qh_getcenter (vertices);
02532     fprintf (fp, "%d 1\n", qh hull_dim);
02533     qh_printpointid (fp, NULL, qh hull_dim, center, -1);
02534     qh_memfree (center, qh normal_size);
02535     qh_settempfree (&vertices);
02536   }else if (format == qh_PRINTextremes) {
02537     if (qh DELAUNAY)
02538       qh_printextremes_d (fp, facetlist, facets, printall);
02539     else if (qh hull_dim == 2)
02540       qh_printextremes_2d (fp, facetlist, facets, printall);
02541     else 
02542       qh_printextremes (fp, facetlist, facets, printall);
02543   }else if (format == qh_PRINToptions)
02544     fprintf(fp, "Options selected for Qhull %s:\n%s\n", qh_version, qh qhull_options);
02545   else if (format == qh_PRINTpoints && !qh VORONOI)
02546     qh_printpoints_out (fp, facetlist, facets, printall);
02547   else if (format == qh_PRINTqhull)
02548     fprintf (fp, "%s | %s\n", qh rbox_command, qh qhull_command);
02549   else if (format == qh_PRINTsize) {
02550     fprintf (fp, "0\n2 ");
02551     fprintf (fp, qh_REAL_1, qh totarea);
02552     fprintf (fp, qh_REAL_1, qh totvol);
02553     fprintf (fp, "\n");
02554   }else if (format == qh_PRINTsummary) {
02555     qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial, 
02556       &totneighbors, &numridges, &numcoplanars);
02557     vertices= qh_facetvertices (facetlist, facets, printall); 
02558     fprintf (fp, "8 %d %d %d %d %d %d %d %d\n2 ", qh hull_dim, 
02559                 qh num_points + qh_setsize (qh other_points),
02560                 qh num_vertices, qh num_facets - qh num_visible,
02561                 qh_setsize (vertices), numfacets, numcoplanars, numfacets - numsimplicial);
02562     qh_settempfree (&vertices);
02563     qh_outerinner (NULL, &outerplane, &innerplane);
02564     fprintf (fp, qh_REAL_2n, outerplane, innerplane);
02565   }else if (format == qh_PRINTvneighbors)
02566     qh_printvneighbors (fp, facetlist, facets, printall);
02567   else if (qh VORONOI && format == qh_PRINToff)
02568     qh_printvoronoi (fp, format, facetlist, facets, printall);
02569   else if (qh VORONOI && format == qh_PRINTgeom) {
02570     qh_printbegin (fp, format, facetlist, facets, printall);
02571     qh_printvoronoi (fp, format, facetlist, facets, printall);
02572     qh_printend (fp, format, facetlist, facets, printall);
02573   }else if (qh VORONOI 
02574   && (format == qh_PRINTvertices || format == qh_PRINTinner || format == qh_PRINTouter))
02575     qh_printvdiagram (fp, format, facetlist, facets, printall);
02576   else {
02577     qh_printbegin (fp, format, facetlist, facets, printall);
02578     FORALLfacet_(facetlist)
02579       qh_printafacet (fp, format, facet, printall);
02580     FOREACHfacet_(facets) 
02581       qh_printafacet (fp, format, facet, printall);
02582     qh_printend (fp, format, facetlist, facets, printall);
02583   }
02584   qh RANDOMdist= qh old_randomdist;
02585 } /* printfacets */
02586 
02587 
02588 /*-<a                             href="qh-io.htm#TOC"
02589   >-------------------------------</a><a name="printhelp_degenerate">-</a>
02590   
02591   qh_printhelp_degenerate( fp )
02592     prints descriptive message for precision error
02593 
02594   notes:
02595     no message if qh_QUICKhelp
02596 */
02597 void qh_printhelp_degenerate(FILE *fp) {
02598   
02599   if (qh MERGEexact || qh PREmerge || qh JOGGLEmax < REALmax/2) 
02600     fprintf(fp, "\n\
02601 A Qhull error has occurred.  Qhull should have corrected the above\n\
02602 precision error.  Please send the input and all of the output to\n\
02603 qhull_bug@geom.umn.edu\n");
02604   else if (!qh_QUICKhelp) {
02605     fprintf(fp, "\n\
02606 Precision problems were detected during construction of the convex hull.\n\
02607 This occurs because convex hull algorithms assume that calculations are\n\
02608 exact, but floating-point arithmetic has roundoff errors.\n\
02609 \n\
02610 To correct for precision problems, do not use 'Q0'.  By default, Qhull\n\
02611 selects 'C-0' or 'Qx' and merges non-convex facets.  With option 'QJ',\n\
02612 Qhull joggles the input to prevent precision problems.  See \"Imprecision\n\
02613 in Qhull\" (qh-impre.htm).\n\
02614 \n\
02615 If you use 'Q0', the output may include\n\
02616 coplanar ridges, concave ridges, and flipped facets.  In 4-d and higher,\n\
02617 Qhull may produce a ridge with four neighbors or two facets with the same \n\
02618 vertices.  Qhull reports these events when they occur.  It stops when a\n\
02619 concave ridge, flipped facet, or duplicate facet occurs.\n");
02620 #if REALfloat
02621     fprintf (fp, "\
02622 \n\
02623 Qhull is currently using single precision arithmetic.  The following\n\
02624 will probably remove the precision problems:\n\
02625   - recompile qhull for double precision (#define REALfloat 0 in user.h).\n");
02626 #endif
02627     if (qh DELAUNAY && !qh SCALElast && qh MAXabs_coord > 1e4)
02628       fprintf( fp, "\
02629 \n\
02630 When computing the Delaunay triangulation of coordinates > 1.0,\n\
02631   - use 'Qbb' to scale the last coordinate to [0,m] (max previous coordinate)\n");
02632     if (qh DELAUNAY && !qh ATinfinity) 
02633       fprintf( fp, "\
02634 When computing the Delaunay triangulation:\n\
02635   - use 'Qz' to add a point at-infinity.  This reduces precision problems.\n");
02636  
02637     fprintf(fp, "\
02638 \n\
02639 If you need triangular output:\n\
02640   - use option 'QJ' to joggle the input points and remove precision errors\n\
02641   - or use option 'Ft' instead of 'Q0'.  It triangulates non-simplicial\n\
02642     facets with added points.\n\
02643 \n\
02644 If you must use 'Q0',\n\
02645 try one or more of the following options.  They can not guarantee an output.\n\
02646   - use 'QbB' to scale the input to a cube.\n\
02647   - use 'Po' to produce output and prevent partitioning for flipped facets\n\
02648   - use 'V0' to set min. distance to visible facet as 0 instead of roundoff\n\
02649   - use 'En' to specify a maximum roundoff error less than %2.2g.\n\
02650   - options 'Qf', 'Qbb', and 'QR0' may also help\n",
02651                qh DISTround);
02652     fprintf(fp, "\
02653 \n\
02654 To guarantee simplicial output:\n\
02655   - use option 'QJ' to joggle the input points and remove precision errors\n\
02656   - use option 'Ft' to triangulate the output by adding points\n\
02657   - use exact arithmetic (see \"Imprecision in Qhull\", qh-impre.htm)\n\
02658 ");
02659   }
02660 } /* printhelp_degenerate */
02661 
02662 
02663 /*-<a                             href="qh-io.htm#TOC"
02664   >-------------------------------</a><a name="printhelp_singular">-</a>
02665   
02666   qh_printhelp_singular( fp )
02667     prints descriptive message for singular input
02668 */
02669 void qh_printhelp_singular(FILE *fp) {
02670   facetT *facet;
02671   vertexT *vertex, **vertexp;
02672   realT min, max, *coord, dist;
02673   int i,k;
02674   
02675   fprintf(fp, "\n\
02676 The input to qhull appears to be less than %d dimensional, or a\n\
02677 computation has overflowed.\n\n\
02678 Qhull could not construct a clearly convex simplex from points:\n",
02679            qh hull_dim);
02680   qh_printvertexlist (fp, "", qh facet_list, NULL, qh_ALL);
02681   if (!qh_QUICKhelp)
02682     fprintf(fp, "\n\
02683 The center point is coplanar with a facet, or a vertex is coplanar\n\
02684 with a neighboring facet.  The maximum round off error for\n\
02685 computing distances is %2.2g.  The center point, facets and distances\n\
02686 to the center point are as follows:\n\n", qh DISTround);
02687   qh_printpointid (fp, "center point", qh hull_dim, qh interior_point, -1);
02688   fprintf (fp, "\n");
02689   FORALLfacets {
02690     fprintf (fp, "facet");
02691     FOREACHvertex_(facet->vertices)
02692       fprintf (fp, " p%d", qh_pointid(vertex->point));
02693     zinc_(Zdistio);
02694     qh_distplane(qh interior_point, facet, &dist);
02695     fprintf (fp, " distance= %4.2g\n", dist);
02696   }
02697   if (!qh_QUICKhelp) {
02698     if (qh HALFspace) 
02699       fprintf (fp, "\n\
02700 These points are the dual of the given halfspaces.  They indicate that\n\
02701 the intersection is degenerate.\n");
02702     fprintf (fp,"\n\
02703 These points either have a maximum or minimum x-coordinate, or\n\
02704 they maximize the determinant for k coordinates.  Trial points\n\
02705 are first selected from points that maximize a coordinate.\n");
02706     if (qh hull_dim >= qh_INITIALmax)
02707       fprintf (fp, "\n\
02708 Because of the high dimension, the min x-coordinate and max-coordinate\n\
02709 points are used if the determinant is non-zero.  Option 'Qs' will\n\
02710 do a better, though much slower, job.  Instead of 'Qs', you can change\n\
02711 the points by randomly rotating the input with 'QR0'.\n");
02712   }
02713   fprintf (fp, "\nThe min and max coordinates for each dimension are:\n");
02714   for (k=0; k < qh hull_dim; k++) {
02715     min= REALmax;
02716     max= -REALmin;
02717     for (i=qh num_points, coord= qh first_point+k; i--; coord += qh hull_dim) {
02718       maximize_(max, *coord);
02719       minimize_(min, *coord);
02720     }
02721     fprintf (fp, "  %d:  %8.4g  %8.4g  difference= %4.4g\n", k, min, max, max-min);
02722   }
02723   if (!qh_QUICKhelp) {
02724     fprintf (fp, "\n\
02725 If the input should be full dimensional, you have several options that\n\
02726 may determine an initial simplex:\n\
02727   - use 'QJ'  to joggle the input and make it full dimensional\n\
02728   - use 'QbB' to scale the points to the unit cube\n\
02729   - use 'QR0' to randomly rotate the input for different maximum points\n\
02730   - use 'Qs'  to search all points for the initial simplex\n\
02731   - use 'En'  to specify a maximum roundoff error less than %2.2g.\n\
02732   - trace execution with 'T3' to see the determinant for each point.\n",
02733                      qh DISTround);
02734 #if REALfloat
02735     fprintf (fp, "\
02736   - recompile qhull for double precision (#define REALfloat 0 in qhull.h).\n");
02737 #endif
02738     fprintf (fp, "\n\
02739 If the input is lower dimensional:\n\
02740   - use 'QJ' to joggle the input and make it full dimensional\n\
02741   - use 'Qbk:0Bk:0' to delete coordinate k from the input.  You should\n\
02742     pick the coordinate with the least range.  The hull will have the\n\
02743     correct topology.\n\
02744   - determine the flat containing the points, rotate the points\n\
02745     into a coordinate plane, and delete the other coordinates.\n\
02746   - add one or more points to make the input full dimensional.\n\
02747 ");
02748     if (qh DELAUNAY && !qh ATinfinity)
02749       fprintf (fp, "\n\n\
02750 This is a Delaunay triangulation and the input is co-circular or co-spherical:\n\
02751   - use 'Qz' to add a point \"at infinity\" (i.e., above the paraboloid)\n\
02752   - or use 'QJ' to joggle the input and avoid co-circular data\n");
02753   }
02754 } /* printhelp_singular */
02755 
02756 /*-<a                             href="qh-io.htm#TOC"
02757   >-------------------------------</a><a name="printhyperplaneintersection">-</a>
02758   
02759   qh_printhyperplaneintersection( fp, facet1, facet2, vertices, color )
02760     print Geomview OFF or 4OFF for the intersection of two hyperplanes in 3-d or 4-d
02761 */
02762 void qh_printhyperplaneintersection(FILE *fp, facetT *facet1, facetT *facet2,
02763                    setT *vertices, realT color[3]) {
02764   realT costheta, denominator, dist1, dist2, s, t, mindenom, p[4];
02765   vertexT *vertex, **vertexp;
02766   int i, k;
02767   boolT nearzero1, nearzero2;
02768   
02769   costheta= qh_getangle(facet1->normal, facet2->normal);
02770   denominator= 1 - costheta * costheta;
02771   i= qh_setsize(vertices);
02772   if (qh hull_dim == 3)
02773     fprintf(fp, "VECT 1 %d 1 %d 1 ", i, i);
02774   else if (qh hull_dim == 4 && qh DROPdim >= 0)
02775     fprintf(fp, "OFF 3 1 1 ");
02776   else
02777     qh printoutvar++;
02778   fprintf (fp, "# intersect f%d f%d\n", facet1->id, facet2->id);
02779   mindenom= 1 / (10.0 * qh MAXabs_coord);
02780   FOREACHvertex_(vertices) {
02781     zadd_(Zdistio, 2);
02782     qh_distplane(vertex->point, facet1, &dist1);
02783     qh_distplane(vertex->point, facet2, &dist2);
02784     s= qh_divzero (-dist1 + costheta * dist2, denominator,mindenom,&nearzero1);
02785     t= qh_divzero (-dist2 + costheta * dist1, denominator,mindenom,&nearzero2);
02786     if (nearzero1 || nearzero2)
02787       s= t= 0.0;
02788     for(k= qh hull_dim; k--; )
02789       p[k]= vertex->point[k] + facet1->normal[k] * s + facet2->normal[k] * t;
02790     if (qh PRINTdim <= 3) {
02791       qh_projectdim3 (p, p);
02792       fprintf(fp, "%8.4g %8.4g %8.4g # ", p[0], p[1], p[2]);
02793     }else 
02794       fprintf(fp, "%8.4g %8.4g %8.4g %8.4g # ", p[0], p[1], p[2], p[3]);
02795     if (nearzero1+nearzero2)
02796       fprintf (fp, "p%d (coplanar facets)\n", qh_pointid (vertex->point));
02797     else
02798       fprintf (fp, "projected p%d\n", qh_pointid (vertex->point));
02799   }
02800   if (qh hull_dim == 3)
02801     fprintf(fp, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]); 
02802   else if (qh hull_dim == 4 && qh DROPdim >= 0)  
02803     fprintf(fp, "3 0 1 2 %8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
02804 } /* printhyperplaneintersection */
02805 
02806 /*-<a                             href="qh-io.htm#TOC"
02807   >-------------------------------</a><a name="printline3geom">-</a>
02808   
02809   qh_printline3geom( fp, pointA, pointB, color )
02810     prints a line as a VECT
02811     prints 0's for qh.DROPdim
02812   
02813   notes:
02814     if pointA == pointB, 
02815       it's a 1 point VECT
02816 */
02817 void qh_printline3geom (FILE *fp, pointT *pointA, pointT *pointB, realT color[3]) {
02818   int k;
02819   realT pA[4], pB[4];
02820 
02821   qh_projectdim3(pointA, pA);
02822   qh_projectdim3(pointB, pB);
02823   if ((fabs(pA[0] - pB[0]) > 1e-3) || 
02824       (fabs(pA[1] - pB[1]) > 1e-3) || 
02825       (fabs(pA[2] - pB[2]) > 1e-3)) {
02826     fprintf (fp, "VECT 1 2 1 2 1\n");
02827     for (k= 0; k < 3; k++)
02828        fprintf (fp, "%8.4g ", pB[k]);
02829     fprintf (fp, " # p%d\n", qh_pointid (pointB));
02830   }else
02831     fprintf (fp, "VECT 1 1 1 1 1\n");
02832   for (k=0; k < 3; k++)
02833     fprintf (fp, "%8.4g ", pA[k]);
02834   fprintf (fp, " # p%d\n", qh_pointid (pointA));
02835   fprintf (fp, "%8.4g %8.4g %8.4g 1\n", color[0], color[1], color[2]);
02836 }
02837 
02838 /*-<a                             href="qh-io.htm#TOC"
02839   >-------------------------------</a><a name="printneighborhood">-</a>
02840   
02841   qh_printneighborhood( fp, format, facetA, facetB, printall )
02842     print neighborhood of one or two facets
02843 
02844   notes:
02845     calls qh_findgood_all() 
02846     bumps qh.visit_id
02847 */
02848 void qh_printneighborhood (FILE *fp, int format, facetT *facetA, facetT *facetB, boolT printall) {
02849   facetT *neighbor, **neighborp, *facet;
02850   setT *facets;
02851 
02852   if (format == qh_PRINTnone)
02853     return;
02854   qh_findgood_all (qh facet_list);
02855   if (facetA == facetB)
02856     facetB= NULL;
02857   facets= qh_settemp (2*(qh_setsize (facetA->neighbors)+1));
02858   qh visit_id++;
02859   for (facet= facetA; facet; facet= ((facet == facetA) ? facetB : NULL)) {
02860     if (facet->visitid != qh visit_id) {
02861       facet->visitid= qh visit_id;
02862       qh_setappend (&facets, facet);
02863     }
02864     FOREACHneighbor_(facet) {
02865       if (neighbor->visitid == qh visit_id)
02866         continue;
02867       neighbor->visitid= qh visit_id;
02868       if (printall || !qh_skipfacet (neighbor))
02869         qh_setappend (&facets, neighbor);
02870     }
02871   }
02872   qh_printfacets (fp, format, NULL, facets, printall);
02873   qh_settempfree (&facets);
02874 } /* printneighborhood */
02875 
02876 /*-<a                             href="qh-io.htm#TOC"
02877   >-------------------------------</a><a name="printpoint">-</a>
02878   
02879   qh_printpoint( fp, string, point )
02880   qh_printpointid( fp, string, dim, point, id )
02881     prints the coordinates of a point
02882 
02883   returns:
02884     if string is defined
02885       prints 'string p%d' (skips p%d if id=-1)
02886 
02887   notes:
02888     nop if point is NULL
02889     prints id unless it is undefined (-1)
02890 */
02891 void qh_printpoint(FILE *fp, char *string, pointT *point) {
02892   int id= qh_pointid( point);
02893 
02894   qh_printpointid( fp, string, qh hull_dim, point, id);
02895 } /* printpoint */
02896 
02897 void qh_printpointid(FILE *fp, char *string, int dim, pointT *point, int id) {
02898   int k;
02899   realT r; /*bug fix*/
02900   
02901   if (!point)
02902     return;
02903   if (string) {
02904     fputs (string, fp);
02905    if (id != -1)
02906       fprintf(fp, " p%d: ", id);
02907   }
02908   for(k= dim; k--; ) {
02909     r= *point++;
02910     if (string)
02911       fprintf(fp, " %8.4g", r);
02912     else
02913       fprintf(fp, qh_REAL_1, r);
02914   }
02915   fprintf(fp, "\n");
02916 } /* printpointid */
02917 
02918 /*-<a                             href="qh-io.htm#TOC"
02919   >-------------------------------</a><a name="printpoint3">-</a>
02920   
02921   qh_printpoint3( fp, point )
02922     prints 2-d, 3-d, or 4-d point as Geomview 3-d coordinates
02923 */
02924 void qh_printpoint3 (FILE *fp, pointT *point) {
02925   int k;
02926   realT p[4];
02927   
02928   qh_projectdim3 (point, p);
02929   for (k=0; k < 3; k++)
02930     fprintf (fp, "%8.4g ", p[k]);
02931   fprintf (fp, " # p%d\n", qh_pointid (point));
02932 } /* printpoint3 */
02933 
02934 /*----------------------------------------
02935 -printpoints- print pointids for a set of points starting at index 
02936    see geom.c
02937 */
02938 
02939 /*-<a                             href="qh-io.htm#TOC"
02940   >-------------------------------</a><a name="printpoints_out">-</a>
02941   
02942   qh_printpoints_out( fp, facetlist, facets, printall )
02943     prints vertices, coplanar/inside points, for facets by their point coordinates
02944     allows qh.CDDoutput
02945 
02946   notes:
02947     same format as qhull input
02948     if no coplanar/interior points,
02949       same order as qh_printextremes
02950 */
02951 void qh_printpoints_out (FILE *fp, facetT *facetlist, setT *facets, int printall) {
02952   int allpoints= qh num_points + qh_setsize (qh other_points);
02953   int numpoints=0, point_i, point_n;
02954   setT *vertices, *points;
02955   facetT *facet, **facetp;
02956   pointT *point, **pointp;
02957   vertexT *vertex, **vertexp;
02958   int id;
02959 
02960   points= qh_settemp (allpoints);
02961   qh_setzero (points, 0, allpoints);
02962   vertices= qh_facetvertices (facetlist, facets, printall);
02963   FOREACHvertex_(vertices) {
02964     id= qh_pointid (vertex->point);
02965     if (id >= 0)
02966       SETelem_(points, id)= vertex->point;
02967   }
02968   if (qh KEEPinside || qh KEEPcoplanar || qh KEEPnearinside) {
02969     FORALLfacet_(facetlist) {
02970       if (!printall && qh_skipfacet(facet))
02971         continue;
02972       FOREACHpoint_(facet->coplanarset) {
02973         id= qh_pointid (point);
02974         if (id >= 0)
02975           SETelem_(points, id)= point;
02976       }
02977     }
02978     FOREACHfacet_(facets) {
02979       if (!printall && qh_skipfacet(facet))
02980         continue;
02981       FOREACHpoint_(facet->coplanarset) {
02982         id= qh_pointid (point);
02983         if (id >= 0)
02984           SETelem_(points, id)= point;
02985       }
02986     }
02987   }
02988   qh_settempfree (&vertices);
02989   FOREACHpoint_i_(points) {
02990     if (point)
02991       numpoints++;
02992   }
02993   if (qh CDDoutput)
02994     fprintf (fp, "%s | %s\nbegin\n%d %d real\n", qh rbox_command,
02995              qh qhull_command, numpoints, qh hull_dim + 1);
02996   else
02997     fprintf (fp, "%d\n%d\n", qh hull_dim, numpoints);
02998   FOREACHpoint_i_(points) {
02999     if (point) {
03000       if (qh CDDoutput)
03001         fprintf (fp, "1 ");
03002       qh_printpoint (fp, NULL, point);
03003     }
03004   }
03005   if (qh CDDoutput)
03006     fprintf (fp, "end\n");
03007   qh_settempfree (&points);
03008 } /* printpoints_out */
03009   
03010 
03011 /*-<a                             href="qh-io.htm#TOC"
03012   >-------------------------------</a><a name="printpointvect">-</a>
03013   
03014   qh_printpointvect( fp, point, normal, center, radius, color )
03015     prints a 2-d, 3-d, or 4-d point as 3-d VECT's relative to normal or to center point
03016 */
03017 void qh_printpointvect (FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius, realT color[3]) {
03018   realT diff[4], pointA[4];
03019   int k;
03020   
03021   for (k= qh hull_dim; k--; ) {
03022     if (center)
03023       diff[k]= point[k]-center[k];
03024     else if (normal) 
03025       diff[k]= normal[k];
03026     else
03027       diff[k]= 0;
03028   }
03029   if (center)
03030     qh_normalize2 (diff, qh hull_dim, True, NULL, NULL);
03031   for (k= qh hull_dim; k--; ) 
03032     pointA[k]= point[k]+diff[k] * radius;
03033   qh_printline3geom (fp, point, pointA, color);
03034 } /* printpointvect */  
03035 
03036 /*-<a                             href="qh-io.htm#TOC"
03037   >-------------------------------</a><a name="printpointvect2">-</a>
03038   
03039   qh_printpointvect2( fp, point, normal, center, radius )
03040     prints a 2-d, 3-d, or 4-d point as 2 3-d VECT's for an imprecise point
03041 */
03042 void qh_printpointvect2 (FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius) {
03043   realT red[3]={1, 0, 0}, yellow[3]={1, 1, 0};
03044 
03045   qh_printpointvect (fp, point, normal, center, radius, red);
03046   qh_printpointvect (fp, point, normal, center, -radius, yellow);
03047 } /* printpointvect2 */
03048 
03049 /*-<a                             href="qh-io.htm#TOC"
03050   >-------------------------------</a><a name="printridge">-</a>
03051   
03052   qh_printridge( fp, ridge )
03053     prints the information in a ridge
03054 
03055   notes:
03056     for qh_printfacetridges()
03057 */
03058 void qh_printridge(FILE *fp, ridgeT *ridge) {
03059   
03060   fprintf(fp, "     - r%d", ridge->id);
03061   if (ridge->tested)
03062     fprintf (fp, " tested");
03063   if (ridge->nonconvex)
03064     fprintf (fp, " nonconvex");
03065   fprintf (fp, "\n");
03066   qh_printvertices (fp, "           vertices:", ridge->vertices);
03067   if (ridge->top && ridge->bottom)
03068     fprintf(fp, "           between f%d and f%d\n",
03069             ridge->top->id, ridge->bottom->id);
03070 } /* printridge */
03071 
03072 /*-<a                             href="qh-io.htm#TOC"
03073   >-------------------------------</a><a name="printspheres">-</a>
03074   
03075   qh_printspheres( fp, vertices, radius )
03076     prints 3-d vertices as OFF spheres
03077 
03078   notes:
03079     inflated octahedron from Stuart Levy earth/mksphere2
03080 */
03081 void qh_printspheres(FILE *fp, setT *vertices, realT radius) {
03082   vertexT *vertex, **vertexp;
03083 
03084   qh printoutnum++;
03085   fprintf (fp, "{appearance {-edge -normal normscale 0} {\n\
03086 INST geom {define vsphere OFF\n\
03087 18 32 48\n\
03088 \n\
03089 0 0 1\n\
03090 1 0 0\n\
03091 0 1 0\n\
03092 -1 0 0\n\
03093 0 -1 0\n\
03094 0 0 -1\n\
03095 0.707107 0 0.707107\n\
03096 0 -0.707107 0.707107\n\
03097 0.707107 -0.707107 0\n\
03098 -0.707107 0 0.707107\n\
03099 -0.707107 -0.707107 0\n\
03100 0 0.707107 0.707107\n\
03101 -0.707107 0.707107 0\n\
03102 0.707107 0.707107 0\n\
03103 0.707107 0 -0.707107\n\
03104 0 0.707107 -0.707107\n\
03105 -0.707107 0 -0.707107\n\
03106 0 -0.707107 -0.707107\n\
03107 \n\
03108 3 0 6 11\n\
03109 3 0 7 6 \n\
03110 3 0 9 7 \n\
03111 3 0 11 9\n\
03112 3 1 6 8 \n\
03113 3 1 8 14\n\
03114 3 1 13 6\n\
03115 3 1 14 13\n\
03116 3 2 11 13\n\
03117 3 2 12 11\n\
03118 3 2 13 15\n\
03119 3 2 15 12\n\
03120 3 3 9 12\n\
03121 3 3 10 9\n\
03122 3 3 12 16\n\
03123 3 3 16 10\n\
03124 3 4 7 10\n\
03125 3 4 8 7\n\
03126 3 4 10 17\n\
03127 3 4 17 8\n\
03128 3 5 14 17\n\
03129 3 5 15 14\n\
03130 3 5 16 15\n\
03131 3 5 17 16\n\
03132 3 6 13 11\n\
03133 3 7 8 6\n\
03134 3 9 10 7\n\
03135 3 11 12 9\n\
03136 3 14 8 17\n\
03137 3 15 13 14\n\
03138 3 16 12 15\n\
03139 3 17 10 16\n} transforms { TLIST\n");
03140   FOREACHvertex_(vertices) {
03141     fprintf(fp, "%8.4g 0 0 0 # v%d\n 0 %8.4g 0 0\n0 0 %8.4g 0\n",
03142       radius, vertex->id, radius, radius);
03143     qh_printpoint3 (fp, vertex->point);
03144     fprintf (fp, "1\n");
03145   }
03146   fprintf (fp, "}}}\n");
03147 } /* printspheres */
03148 
03149 
03150 /*----------------------------------------------
03151 -printsummary-
03152                 see qhull.c
03153 */
03154 
03155 /*-<a                             href="qh-io.htm#TOC"
03156   >-------------------------------</a><a name="printvdiagram">-</a>
03157   
03158   qh_printvdiagram( fp, format, facetlist, facets, printall )
03159     print voronoi diagram
03160       # of pairs of input sites
03161       #indices site1 site2 vertex1 ...
03162     
03163     sites indexed by input point id
03164       point 0 is the first input point
03165     vertices indexed by 'o' and 'p' order
03166       vertex 0 is the 'vertex-at-infinity'
03167       vertex 1 is the first Voronoi vertex
03168 
03169   see:
03170     qh_printvoronoi()
03171     qh_eachvoronoi_all()
03172 
03173   notes:
03174     if all facets are upperdelaunay, 
03175       prints upper hull (furthest-site Voronoi diagram)
03176 */
03177 void qh_printvdiagram (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
03178   setT *vertices;
03179   int totcount, numcenters;
03180   boolT islower;
03181   qh_RIDGE innerouter= qh_RIDGEall;
03182   printvridgeT printvridge= NULL;
03183 
03184   if (format == qh_PRINTvertices) {
03185     innerouter= qh_RIDGEall;
03186     printvridge= qh_printvridge;
03187   }else if (format == qh_PRINTinner) {
03188     innerouter= qh_RIDGEinner;
03189     printvridge= qh_printvnorm;
03190   }else if (format == qh_PRINTouter) {
03191     innerouter= qh_RIDGEouter;
03192     printvridge= qh_printvnorm;
03193   }else {
03194     fprintf(qh ferr, "qh_printvdiagram: unknown print format %d.\n", format);
03195     qh_errexit (qh_ERRinput, NULL, NULL);
03196   }
03197   vertices= qh_markvoronoi (facetlist, facets, printall, &islower, &numcenters);
03198   totcount= qh_printvdiagram2 (NULL, NULL, vertices, innerouter, False);
03199   fprintf (fp, "%d\n", totcount);
03200   totcount= qh_printvdiagram2 (fp, printvridge, vertices, innerouter, True /* inorder*/);
03201   qh_settempfree (&vertices);
03202 #if 0  /* for testing qh_eachvoronoi_all */
03203   fprintf (fp, "\n");
03204   totcount= qh_eachvoronoi_all(fp, printvridge, qh UPPERdelaunay, innerouter, True /* inorder*/);
03205   fprintf (fp, "%d\n", totcount);
03206 #endif
03207 } /* printvdiagram */
03208   
03209 /*-<a                             href="qh-io.htm#TOC"
03210   >-------------------------------</a><a name="printvdiagram2">-</a>
03211   
03212   qh_printvdiagram2( fp, printvridge, vertices, innerouter, inorder )
03213     visit all pairs of input sites (vertices) for selected Voronoi vertices
03214     vertices may include NULLs
03215   
03216   innerouter:
03217     qh_RIDGEall   print inner ridges (bounded) and outer ridges (unbounded)
03218     qh_RIDGEinner print only inner ridges
03219     qh_RIDGEouter print only outer ridges
03220   
03221   inorder:
03222     print 3-d Voronoi vertices in order
03223   
03224   assumes:
03225     qh_markvoronoi marked facet->visitid for Voronoi vertices
03226     all facet->seen= False
03227     all facet->seen2= True
03228   
03229   returns:
03230     total number of Voronoi ridges 
03231     if printvridge,
03232       calls printvridge( fp, vertex, vertexA, centers) for each ridge
03233       [see qh_eachvoronoi()]
03234   
03235   see:
03236     qh_eachvoronoi_all()
03237 */
03238 int qh_printvdiagram2 (FILE *fp, printvridgeT printvridge, setT *vertices, qh_RIDGE innerouter, boolT inorder) {
03239   int totcount= 0;
03240   int vertex_i, vertex_n;
03241   vertexT *vertex;
03242 
03243   FORALLvertices 
03244     vertex->seen= False;
03245   FOREACHvertex_i_(vertices) {
03246     if (vertex) {
03247       if (qh GOODvertex > 0 && qh_pointid(vertex->point)+1 != qh GOODvertex)
03248         continue;
03249       totcount += qh_eachvoronoi (fp, printvridge, vertex, !qh_ALL, innerouter, inorder);
03250     }
03251   }
03252   return totcount;
03253 } /* printvdiagram2 */
03254   
03255 /*-<a                             href="qh-io.htm#TOC"
03256   >-------------------------------</a><a name="printvertex">-</a>
03257   
03258   qh_printvertex( fp, vertex )
03259     prints the information in a vertex
03260 */
03261 void qh_printvertex(FILE *fp, vertexT *vertex) {
03262   pointT *point;
03263   int k;
03264   facetT *neighbor, **neighborp;
03265   realT r; /*bug fix*/
03266 
03267   if (!vertex) {
03268     fprintf (fp, "  NULLvertex\n");
03269     return;
03270   }
03271   fprintf(fp, "- p%d (v%d):", qh_pointid(vertex->point), vertex->id);
03272   point= vertex->point;
03273   if (point) {
03274     for(k= qh hull_dim; k--; ) {
03275       r= *point++;
03276       fprintf(fp, " %5.2g", r);
03277     }
03278   }
03279   if (vertex->deleted)
03280     fprintf(fp, " deleted");
03281   if (vertex->delridge)
03282     fprintf (fp, " ridgedeleted");
03283   fprintf(fp, "\n");
03284   if (vertex->neighbors) {
03285     fprintf(fp, "  neighbors:");
03286     FOREACHneighbor_(vertex)
03287       fprintf(fp, " f%d", neighbor->id);
03288     fprintf(fp, "\n");
03289   }
03290 } /* printvertex */
03291 
03292 
03293 /*-<a                             href="qh-io.htm#TOC"
03294   >-------------------------------</a><a name="printvertexlist">-</a>
03295   
03296   qh_printvertexlist( fp, string, facetlist, facets, printall )
03297     prints vertices used by a facetlist or facet set
03298     tests qh_skipfacet() if !printall
03299 */
03300 void qh_printvertexlist (FILE *fp, char* string, facetT *facetlist, 
03301                          setT *facets, boolT printall) {
03302   vertexT *vertex, **vertexp;
03303   setT *vertices;
03304   
03305   vertices= qh_facetvertices (facetlist, facets, printall);
03306   fputs (string, fp);
03307   FOREACHvertex_(vertices)
03308     qh_printvertex(fp, vertex);
03309   qh_settempfree (&vertices);
03310 } /* printvertexlist */
03311 
03312 
03313 /*-<a                             href="qh-io.htm#TOC"
03314   >-------------------------------</a><a name="printvertices">-</a>
03315   
03316   qh_printvertices( fp, string, vertices )
03317     prints vertices in a set
03318 */
03319 void qh_printvertices(FILE *fp, char* string, setT *vertices) {
03320   vertexT *vertex, **vertexp;
03321   
03322   fputs (string, fp);
03323   FOREACHvertex_(vertices) 
03324     fprintf (fp, " p%d (v%d)", qh_pointid(vertex->point), vertex->id);
03325   fprintf(fp, "\n");
03326 } /* printvertices */
03327 
03328 /*-<a                             href="qh-io.htm#TOC"
03329   >-------------------------------</a><a name="printvneighbors">-</a>
03330   
03331   qh_printvneighbors( fp, facetlist, facets, printall )
03332     print vertex neighbors of vertices in facetlist and facets ('FN')
03333 
03334   notes:
03335     qh_countfacets clears facet->visitid for non-printed facets
03336 
03337   design:
03338     collect facet count and related statistics
03339     if necessary, build neighbor sets for each vertex
03340     collect vertices in facetlist and facets
03341     build a point array for point->vertex and point->coplanar facet
03342     for each point
03343       list vertex neighbors or coplanar facet
03344 */
03345 void qh_printvneighbors (FILE *fp, facetT* facetlist, setT *facets, boolT printall) {
03346   int numfacets, numsimplicial, numridges, totneighbors, numneighbors, numcoplanars;
03347   setT *vertices, *vertex_points, *coplanar_points;
03348   int numpoints= qh num_points + qh_setsize (qh other_points);
03349   vertexT *vertex, **vertexp;
03350   int vertex_i, vertex_n;
03351   facetT *facet, **facetp, *neighbor, **neighborp;
03352   pointT *point, **pointp;
03353 
03354   qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial, 
03355       &totneighbors, &numridges, &numcoplanars);  /* sets facet->visitid */
03356   fprintf (fp, "%d\n", numpoints);
03357   qh_vertexneighbors();
03358   vertices= qh_facetvertices (facetlist, facets, printall);
03359   vertex_points= qh_settemp (numpoints);
03360   coplanar_points= qh_settemp (numpoints);
03361   qh_setzero (vertex_points, 0, numpoints);
03362   qh_setzero (coplanar_points, 0, numpoints);
03363   FOREACHvertex_(vertices)
03364     qh_point_add (vertex_points, vertex->point, vertex);
03365   FORALLfacet_(facetlist) {
03366     FOREACHpoint_(facet->coplanarset)
03367       qh_point_add (coplanar_points, point, facet);
03368   }
03369   FOREACHfacet_(facets) {
03370     FOREACHpoint_(facet->coplanarset)
03371       qh_point_add (coplanar_points, point, facet);
03372   }
03373   FOREACHvertex_i_(vertex_points) {
03374     if (vertex) { 
03375       numneighbors= qh_setsize (vertex->neighbors);
03376       fprintf (fp, "%d", numneighbors);
03377       if (qh hull_dim == 3)
03378         qh_order_vertexneighbors (vertex);
03379       else if (qh hull_dim >= 4)
03380         qsort (SETaddr_(vertex->neighbors, facetT), numneighbors,
03381              sizeof (facetT *), qh_compare_facetvisit);
03382       FOREACHneighbor_(vertex) 
03383         fprintf (fp, " %d", 
03384                  neighbor->visitid ? neighbor->visitid - 1 : - neighbor->id);
03385       fprintf (fp, "\n");
03386     }else if ((facet= SETelemt_(coplanar_points, vertex_i, facetT)))
03387       fprintf (fp, "1 %d\n",
03388                   facet->visitid ? facet->visitid - 1 : - facet->id);
03389     else
03390       fprintf (fp, "0\n");
03391   }
03392   qh_settempfree (&coplanar_points);
03393   qh_settempfree (&vertex_points);
03394   qh_settempfree (&vertices);
03395 } /* printvneighbors */
03396 
03397 /*-<a                             href="qh-io.htm#TOC"
03398   >-------------------------------</a><a name="printvoronoi">-</a>
03399   
03400   qh_printvoronoi( fp, format, facetlist, facets, printall )
03401     print voronoi diagram in 'o' or 'G' format
03402     for 'o' format
03403       prints voronoi centers for each facet and for infinity
03404       for each vertex, lists ids of printed facets or infinity
03405       assumes facetlist and facets are disjoint
03406     for 'G' format
03407       prints an OFF object
03408       adds a 0 coordinate to center
03409       prints infinity but does not list in vertices
03410 
03411   see:
03412     qh_printvdiagram()
03413 
03414   notes:
03415     if 'o', 
03416       prints a line for each point except "at-infinity"
03417     if all facets are upperdelaunay, 
03418       reverses lower and upper hull
03419 */
03420 void qh_printvoronoi (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
03421   int k, numcenters, numvertices= 0, numneighbors, numinf, vid=1, vertex_i, vertex_n;
03422   facetT *facet, **facetp, *neighbor, **neighborp;
03423   setT *vertices;
03424   vertexT *vertex;
03425   boolT islower;
03426   unsigned int numfacets= (unsigned int) qh num_facets;
03427 
03428   vertices= qh_markvoronoi (facetlist, facets, printall, &islower, &numcenters);
03429   FOREACHvertex_i_(vertices) {
03430     if (vertex) {
03431       numvertices++;
03432       numneighbors = numinf = 0;
03433       FOREACHneighbor_(vertex) {
03434         if (neighbor->visitid == 0)
03435           numinf= 1;
03436         else if (neighbor->visitid < numfacets)
03437           numneighbors++;
03438       }
03439       if (numinf && !numneighbors) {
03440         SETelem_(vertices, vertex_i)= NULL;
03441         numvertices--;
03442       }
03443     }
03444   }
03445   if (format == qh_PRINTgeom) 
03446     fprintf (fp, "{appearance {+edge -face} OFF %d %d 1 # Voronoi centers and cells\n", 
03447                 numcenters, numvertices);
03448   else
03449     fprintf (fp, "%d\n%d %d 1\n", qh hull_dim-1, numcenters, qh_setsize(vertices));
03450   if (format == qh_PRINTgeom) {
03451     for (k= qh hull_dim-1; k--; )
03452       fprintf (fp, qh_REAL_1, 0.0);
03453     fprintf (fp, " 0 # infinity not used\n");
03454   }else {
03455     for (k= qh hull_dim-1; k--; )
03456       fprintf (fp, qh_REAL_1, qh_INFINITE);
03457     fprintf (fp, "\n");
03458   }
03459   FORALLfacet_(facetlist) {
03460     if (facet->visitid && facet->visitid < numfacets) {
03461       if (format == qh_PRINTgeom)
03462         fprintf (fp, "# %d f%d\n", vid++, facet->id);
03463       qh_printcenter (fp, format, NULL, facet);
03464     }
03465   }
03466   FOREACHfacet_(facets) {
03467     if (facet->visitid && facet->visitid < numfacets) {
03468       if (format == qh_PRINTgeom)
03469         fprintf (fp, "# %d f%d\n", vid++, facet->id);
03470       qh_printcenter (fp, format, NULL, facet);
03471     }
03472   }
03473   FOREACHvertex_i_(vertices) {
03474     numneighbors= 0;
03475     numinf=0;
03476     if (vertex) {
03477       if (qh hull_dim == 3)
03478         qh_order_vertexneighbors(vertex);
03479       else if (qh hull_dim >= 4)
03480         qsort (SETaddr_(vertex->neighbors, vertexT), 
03481              qh_setsize (vertex->neighbors),
03482              sizeof (facetT *), qh_compare_facetvisit);
03483       FOREACHneighbor_(vertex) {
03484         if (neighbor->visitid == 0)
03485           numinf= 1;
03486         else if (neighbor->visitid < numfacets)
03487           numneighbors++;
03488       }
03489     }
03490     if (format == qh_PRINTgeom) {
03491       if (vertex) {
03492         fprintf (fp, "%d", numneighbors);
03493         if (vertex) {
03494           FOREACHneighbor_(vertex) {
03495             if (neighbor->visitid && neighbor->visitid < numfacets)
03496               fprintf (fp, " %d", neighbor->visitid);
03497           }
03498         }
03499         fprintf (fp, " # p%d (v%d)\n", vertex_i, vertex->id);
03500       }else
03501         fprintf (fp, " # p%d is coplanar or isolated\n", vertex_i);
03502     }else {
03503       if (numinf)
03504         numneighbors++;
03505       fprintf (fp, "%d", numneighbors);
03506       if (vertex) {
03507         FOREACHneighbor_(vertex) {
03508           if (neighbor->visitid == 0) {
03509             if (numinf) {
03510               numinf= 0;
03511               fprintf (fp, " %d", neighbor->visitid);
03512             }
03513           }else if (neighbor->visitid < numfacets)
03514             fprintf (fp, " %d", neighbor->visitid);
03515         }
03516       }
03517       fprintf (fp, "\n");
03518     }
03519   }
03520   if (format == qh_PRINTgeom)
03521     fprintf (fp, "}\n");
03522   qh_settempfree (&vertices);
03523 } /* printvoronoi */
03524   
03525 /*-<a                             href="qh-io.htm#TOC"
03526   >-------------------------------</a><a name="printvnorm">-</a>
03527   
03528   qh_printvnorm( fp, vertex, vertexA, centers, unbounded )
03529     print one separating plane of the Voronoi diagram for a pair of input sites
03530     unbounded==True if centers includes vertex-at-infinity
03531   
03532   assumes:
03533     qh_ASvoronoi and qh_vertexneighbors() already set
03534     
03535   see:
03536     qh_printvdiagram()
03537     qh_eachvoronoi()
03538 */
03539 void qh_printvnorm (FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {
03540   pointT *normal;
03541   realT offset;
03542   int k;
03543   
03544   normal= qh_detvnorm (vertex, vertexA, centers, &offset);
03545   fprintf (fp, "%d %d %d ", 
03546       2+qh hull_dim, qh_pointid (vertex->point), qh_pointid (vertexA->point));
03547   for (k= 0; k< qh hull_dim-1; k++)
03548     fprintf (fp, qh_REAL_1, normal[k]);
03549   fprintf (fp, qh_REAL_1, offset);
03550   fprintf (fp, "\n");
03551 } /* printvnorm */
03552 
03553 /*-<a                             href="qh-io.htm#TOC"
03554   >-------------------------------</a><a name="printvridge">-</a>
03555   
03556   qh_printvridge( fp, vertex, vertexA, centers, unbounded )
03557     print one ridge of the Voronoi diagram for a pair of input sites
03558     unbounded==True if centers includes vertex-at-infinity
03559   
03560   see:
03561     qh_printvdiagram()
03562   
03563   notes:
03564     the user may use a different function
03565 */
03566 void qh_printvridge (FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {
03567   facetT *facet, **facetp;
03568 
03569   fprintf (fp, "%d %d %d", qh_setsize (centers)+2, 
03570        qh_pointid (vertex->point), qh_pointid (vertexA->point));
03571   FOREACHfacet_(centers) 
03572     fprintf (fp, " %d", facet->visitid);
03573   fprintf (fp, "\n");
03574 } /* printvridge */
03575 
03576 /*-<a                             href="qh-io.htm#TOC"
03577   >-------------------------------</a><a name="projectdim3">-</a>
03578   
03579   qh_projectdim3( source, destination )
03580     project 2-d 3-d or 4-d point to a 3-d point
03581     uses qh.DROPdim and qh.hull_dim
03582     source and destination may be the same
03583     
03584   notes:
03585     allocate 4 elements to destination just in case
03586 */
03587 void qh_projectdim3 (pointT *source, pointT *destination) {
03588   int i,k;
03589 
03590   for (k= 0, i=0; k < qh hull_dim; k++) {
03591     if (qh hull_dim == 4) {
03592       if (k != qh DROPdim)
03593         destination[i++]= source[k];
03594     }else if (k == qh DROPdim)
03595       destination[i++]= 0;
03596     else
03597       destination[i++]= source[k];
03598   }
03599   while (i < 3)
03600     destination[i++]= 0.0;
03601 } /* projectdim3 */
03602 
03603 /*-<a                             href="qh-io.htm#TOC"
03604   >-------------------------------</a><a name="readfeasible">-</a>
03605   
03606   qh_readfeasible( dim, remainder )
03607     read feasible point from remainder string and qh.fin
03608 
03609   returns:
03610     number of lines read from qh.fin
03611     sets qh.FEASIBLEpoint with malloc'd coordinates
03612 
03613   notes:
03614     checks for qh.HALFspace
03615     assumes dim > 1
03616 
03617   see:
03618     qh_setfeasible
03619 */
03620 int qh_readfeasible (int dim, char *remainder) {
03621   boolT isfirst= True;
03622   int linecount= 0, tokcount= 0;
03623   char *s, *t, firstline[qh_MAXfirst+1];
03624   coordT *coords, value;
03625 
03626   if (!qh HALFspace) {
03627     fprintf  (qh ferr, "qhull input error: feasible point (dim 1 coords) is only valid for halfspace intersection\n");
03628     qh_errexit (qh_ERRinput, NULL, NULL);
03629   }  
03630   if (qh feasible_string)
03631     fprintf  (qh ferr, "qhull input warning: feasible point (dim 1 coords) overrides 'Hn,n,n' feasible point for halfspace intersection\n");
03632   if (!(qh feasible_point= (coordT*)malloc (dim* sizeof(coordT)))) {
03633     fprintf(qh ferr, "qhull error: insufficient memory for feasible point\n");
03634     qh_errexit(qh_ERRmem, NULL, NULL);
03635   }
03636   coords= qh feasible_point;
03637   while ((s= (isfirst ?  remainder : fgets(firstline, qh_MAXfirst, qh fin)))) {
03638     if (isfirst)
03639       isfirst= False;
03640     else
03641       linecount++;
03642     while (*s) {
03643       while (isspace(*s))
03644         s++;
03645       value= qh_strtod (s, &t);
03646       if (s == t)
03647         break;
03648       s= t;
03649       *(coords++)= value;
03650       if (++tokcount == dim) {
03651         while (isspace (*s))
03652           s++;
03653         qh_strtod (s, &t);
03654         if (s != t) {
03655           fprintf (qh ferr, "qhull input error: coordinates for feasible point do not finish out the line: %s\n",
03656                s);
03657           qh_errexit (qh_ERRinput, NULL, NULL);
03658         }
03659         return linecount;
03660       }
03661     }
03662   }
03663   fprintf (qh ferr, "qhull input error: only %d coordinates.  Could not read %d-d feasible point.\n",
03664            tokcount, dim);
03665   qh_errexit (qh_ERRinput, NULL, NULL);
03666   return 0;
03667 } /* readfeasible */
03668 
03669 /*-<a                             href="qh-io.htm#TOC"
03670   >-------------------------------</a><a name="readpoints">-</a>
03671   
03672   qh_readpoints( numpoints, dimension, ismalloc )
03673     read points from qh.fin into qh.first_point, qh.num_points
03674     qh.fin is lines of coordinates, one per vertex, first line number of points
03675     if 'rbox D4',
03676       gives message
03677     if qh.ATinfinity,
03678       adds point-at-infinity for Delaunay triangulations
03679 
03680   returns:
03681     number of points, array of point coordinates, dimension, ismalloc True
03682     if qh.DELAUNAY & !qh.PROJECTinput, projects points to paraboloid
03683         and clears qh.PROJECTdelaunay
03684     if qh.HALFspace, reads optional feasible point, reads halfspaces,
03685         converts to dual.
03686 
03687   for feasible point in "cdd format" in 3-d:
03688     3 1
03689     coordinates
03690     comments
03691     begin
03692     n 4 real/integer
03693     ...
03694     end
03695 
03696   notes:
03697     dimension will change in qh_initqhull_globals if qh.PROJECTinput
03698     uses malloc() since qh_mem not initialized
03699     FIXUP: this routine needs rewriting
03700 */
03701 coordT *qh_readpoints(int *numpoints, int *dimension, boolT *ismalloc) {
03702   coordT *points, *coords, *infinity= NULL;
03703   realT paraboloid, maxboloid= -REALmax, value;
03704   realT *coordp= NULL, *offsetp= NULL, *normalp= NULL;
03705   char *s, *t, firstline[qh_MAXfirst+1];
03706   int diminput=0, numinput=0, dimfeasible= 0, newnum, k, tempi;
03707   int firsttext=0, firstshort=0, firstlong=0, firstpoint=0;
03708   int tokcount= 0, linecount=0, maxcount, coordcount=0;
03709   boolT islong, isfirst= True, wasbegin= False;
03710   boolT isdelaunay= qh DELAUNAY && !qh PROJECTinput;
03711 
03712   if (qh CDDinput) {
03713     while ((s= fgets(firstline, qh_MAXfirst, qh fin))) {
03714       linecount++;
03715       if (qh HALFspace && linecount == 1 && isdigit(*s)) {
03716         dimfeasible= qh_strtol (s, &s); 
03717         while (isspace(*s))
03718           s++;
03719         if (qh_strtol (s, &s) == 1)
03720           linecount += qh_readfeasible (dimfeasible, s);
03721         else
03722           dimfeasible= 0;
03723       }else if (!memcmp (firstline, "begin", 5) || !memcmp (firstline, "BEGIN", 5))
03724         break;
03725       else if (!*qh rbox_command)
03726         strncat(qh rbox_command, s, sizeof (qh rbox_command)-1);
03727     }
03728     if (!s) {
03729       fprintf (qh ferr, "qhull input error: missing \"begin\" for cdd-formated input\n");
03730       qh_errexit (qh_ERRinput, NULL, NULL);
03731     }
03732   }
03733   while(!numinput && (s= fgets(firstline, qh_MAXfirst, qh fin))) {
03734     linecount++;
03735     if (!memcmp (s, "begin", 5) || !memcmp (s, "BEGIN", 5))
03736       wasbegin= True;
03737     while (*s) {
03738       while (isspace(*s))
03739         s++;
03740       if (!*s)
03741         break;
03742       if (!isdigit(*s)) {
03743         if (!*qh rbox_command) {
03744           strncat(qh rbox_command, s, sizeof (qh rbox_command)-1);
03745           firsttext= linecount;
03746         }
03747         break;
03748       }
03749       if (!diminput) 
03750         diminput= qh_strtol (s, &s);
03751       else {
03752         numinput= qh_strtol (s, &s);
03753         if (numinput == 1 && diminput >= 2 && qh HALFspace && !qh CDDinput) {
03754           linecount += qh_readfeasible (diminput, s); /* checks if ok */
03755           dimfeasible= diminput;
03756           diminput= numinput= 0;
03757         }else 
03758           break;
03759       }
03760     }
03761   }
03762   if (!s) {
03763     fprintf(qh ferr, "qhull input error: short input file.  Did not find dimension and number of points\n");
03764     qh_errexit(qh_ERRinput, NULL, NULL);
03765   }
03766   if (diminput > numinput) {
03767     tempi= diminput;    /* exchange dim and n, e.g., for cdd input format */
03768     diminput= numinput;
03769     numinput= tempi;
03770   }
03771   if (diminput < 2) {
03772     fprintf(qh ferr,"qhull input error: dimension %d (first number) should be at least 2\n",
03773             diminput);
03774     qh_errexit(qh_ERRinput, NULL, NULL);
03775   }
03776   if (isdelaunay) {
03777     qh PROJECTdelaunay= False;
03778     if (qh CDDinput)
03779       *dimension= diminput;
03780     else
03781       *dimension= diminput+1;
03782     *numpoints= numinput;
03783     if (qh ATinfinity)
03784       (*numpoints)++;
03785   }else if (qh HALFspace) {
03786     *dimension= diminput - 1;
03787     *numpoints= numinput;
03788     if (diminput < 3) {
03789       fprintf(qh ferr,"qhull input error: dimension %d (first number, includes offset) should be at least 3 for halfspaces\n",
03790             diminput);
03791       qh_errexit(qh_ERRinput, NULL, NULL);
03792     }
03793     if (dimfeasible) {
03794       if (dimfeasible != *dimension) {
03795         fprintf(qh ferr,"qhull input error: dimension %d of feasible point is not one less than dimension %d for halfspaces\n",
03796           dimfeasible, diminput);
03797         qh_errexit(qh_ERRinput, NULL, NULL);
03798       }
03799     }else 
03800       qh_setfeasible (*dimension);
03801   }else {
03802     if (qh CDDinput) 
03803       *dimension= diminput-1;
03804     else
03805       *dimension= diminput;
03806     *numpoints= numinput;
03807   }
03808   qh normal_size= *dimension * sizeof(coordT); /* for tracing with qh_printpoint */
03809   if (qh HALFspace) {
03810     qh half_space= coordp= (coordT*) malloc (qh normal_size + sizeof(coordT));
03811     if (qh CDDinput) {
03812       offsetp= qh half_space;
03813       normalp= offsetp + 1;
03814     }else {
03815       normalp= qh half_space;
03816       offsetp= normalp + *dimension;
03817     }
03818   } 
03819   qh maxline= diminput * (qh_REALdigits + 5);
03820   maximize_(qh maxline, 500);
03821   qh line= (char*)malloc ((qh maxline+1) * sizeof (char));
03822   *ismalloc= True;  /* use malloc since memory not setup */
03823   coords= points= qh temp_malloc= 
03824         (coordT*)malloc((*numpoints)*(*dimension)*sizeof(coordT));
03825   if (!coords || !qh line || (qh HALFspace && !qh half_space)) {
03826     fprintf(qh ferr, "qhull error: insufficient memory to read %d points\n",
03827             numinput);
03828     qh_errexit(qh_ERRmem, NULL, NULL);
03829   }
03830   if (isdelaunay && qh ATinfinity) {
03831     infinity= points + numinput * (*dimension);
03832     for (k= (*dimension) - 1; k--; )
03833       infinity[k]= 0.0;
03834   }
03835   maxcount= numinput * diminput;
03836   paraboloid= 0.0;
03837   while ((s= (isfirst ?  s : fgets(qh line, qh maxline, qh fin)))) {
03838     if (!isfirst) {
03839       linecount++;
03840       if (*s == 'e' || *s == 'E') {
03841         if (!memcmp (s, "end", 3) || !memcmp (s, "END", 3)) {
03842           if (qh CDDinput )
03843             break;
03844           else if (wasbegin) 
03845             fprintf (qh ferr, "qhull input warning: the input appears to be in cdd format.  If so, use 'Fd'\n");
03846         }
03847       }
03848     }
03849     islong= False;
03850     while (*s) {
03851       while (isspace(*s))
03852         s++;
03853       value= qh_strtod (s, &t);
03854       if (s == t) {
03855         if (!*qh rbox_command)
03856          strncat(qh rbox_command, s, sizeof (qh rbox_command)-1);
03857         if (*s && !firsttext) 
03858           firsttext= linecount;
03859         if (!islong && !firstshort && coordcount)
03860           firstshort= linecount;
03861         break;
03862       }
03863       if (!firstpoint)
03864         firstpoint= linecount;
03865       s= t;
03866       if (++tokcount > maxcount)
03867         continue;
03868       if (qh HALFspace) {
03869         if (qh CDDinput && !coordcount) 
03870           *(coordp++)= -value; /* offset */
03871         else
03872           *(coordp++)= value;
03873       }else {
03874         *(coords++)= value;
03875         if (qh CDDinput && !coordcount) {
03876           if (value != 1.0) {
03877             fprintf (qh ferr, "qhull input error: for cdd format, point at line %d does not start with '1'\n",
03878                    linecount);
03879             qh_errexit (qh_ERRinput, NULL, NULL);
03880           }
03881           coords--;
03882         }else if (isdelaunay) {
03883           paraboloid += value * value;
03884           if (qh ATinfinity) {
03885             if (qh CDDinput)
03886               infinity[coordcount-1] += value;
03887             else
03888               infinity[coordcount] += value;
03889           }
03890         }
03891       }
03892       if (++coordcount == diminput) {
03893         coordcount= 0;
03894         if (isdelaunay) {
03895           *(coords++)= paraboloid;
03896           maximize_(maxboloid, paraboloid);
03897           paraboloid= 0.0;
03898         }else if (qh HALFspace) {
03899           if (!qh_sethalfspace (*dimension, coords, &coords, normalp, offsetp, qh feasible_point)) {
03900             fprintf (qh ferr, "The halfspace was on line %d\n", linecount);
03901             if (wasbegin)
03902               fprintf (qh ferr, "The input appears to be in cdd format.  If so, you should use option 'Fd'\n");
03903             qh_errexit (qh_ERRinput, NULL, NULL);
03904           }
03905           coordp= qh half_space;
03906         }          
03907         while (isspace(*s))
03908           s++;
03909         if (*s) {
03910           islong= True;
03911           if (!firstlong)
03912             firstlong= linecount;
03913         }
03914       }
03915     }
03916     if (!islong && !firstshort && coordcount)
03917       firstshort= linecount;
03918     if (!isfirst && s - qh line >= qh maxline) {
03919       fprintf(qh ferr, "qhull input error: line %d contained more than %d characters\n", 
03920               linecount, (int) (s - qh line));
03921       qh_errexit(qh_ERRinput, NULL, NULL);
03922     }
03923     isfirst= False;
03924   }
03925   if (tokcount != maxcount) {
03926     newnum= fmin_(numinput, tokcount/diminput);
03927     fprintf(qh ferr,"\
03928 qhull warning: instead of %d %d-dimensional points, input contains\n\
03929 %d points and %d extra coordinates.  Line %d is the first\npoint",
03930        numinput, diminput, tokcount/diminput, tokcount % diminput, firstpoint);
03931     if (firsttext)
03932       fprintf(qh ferr, ", line %d is the first comment", firsttext);
03933     if (firstshort)
03934       fprintf(qh ferr, ", line %d is the first short\nline", firstshort);
03935     if (firstlong)
03936       fprintf(qh ferr, ", line %d is the first long line", firstlong);
03937     fprintf(qh ferr, ".  Continue with %d points.\n", newnum);
03938     numinput= newnum;
03939     if (isdelaunay && qh ATinfinity) {
03940       for (k= tokcount % diminput; k--; )
03941         infinity[k] -= *(--coords);
03942       *numpoints= newnum+1;
03943     }else {
03944       coords -= tokcount % diminput;
03945       *numpoints= newnum;
03946     }
03947   }
03948   if (isdelaunay && qh ATinfinity) {
03949     for (k= (*dimension) -1; k--; )
03950       infinity[k] /= numinput;
03951     if (coords == infinity)
03952       coords += (*dimension) -1;
03953     else {
03954       for (k= 0; k < (*dimension) -1; k++)
03955         *(coords++)= infinity[k];
03956     }
03957     *(coords++)= maxboloid * 1.1;
03958   }
03959   if (qh rbox_command[0]) {
03960     qh rbox_command[strlen(qh rbox_command)-1]= '\0';
03961     if (!strcmp (qh rbox_command, "./rbox D4")) 
03962       fprintf (qh ferr, "\n\
03963 This is the qhull test case.  If any errors or core dumps occur,\n\
03964 recompile qhull with 'make new'.  If errors still occur, there is\n\
03965 an incompatibility.  You should try a different compiler.  You can also\n\
03966 change the choices in user.h.  If you discover the source of the problem,\n\
03967 please send mail to qhull_bug@geom.umn.edu.\n\
03968 \n\
03969 Type 'qhull' for a short list of options.\n");
03970   }
03971   free (qh line);
03972   qh line= NULL;
03973   if (qh half_space) {
03974     free (qh half_space);
03975     qh half_space= NULL;
03976   }
03977   qh temp_malloc= NULL;
03978   trace1((qh ferr,"qh_readpoints: read in %d %d-dimensional points\n",
03979           numinput, diminput));
03980   return(points);
03981 } /* readpoints */
03982 
03983 
03984 /*-<a                             href="qh-io.htm#TOC"
03985   >-------------------------------</a><a name="setfeasible">-</a>
03986   
03987   qh_setfeasible( dim )
03988     set qh.FEASIBLEpoint from qh.feasible_string in "n,n,n" or "n n n" format
03989 
03990   notes:
03991     "n,n,n" already checked by qh_initflags()
03992     see qh_readfeasible()
03993 */
03994 void qh_setfeasible (int dim) {
03995   int tokcount= 0;
03996   char *s;
03997   coordT *coords, value;
03998 
03999   if (!(s= qh feasible_string)) {
04000     fprintf(qh ferr, "\
04001 qhull input error: halfspace intersection needs a feasible point.\n\
04002 Either prepend the input with 1 point or use 'Hn,n,n'.  See manual.\n");
04003     qh_errexit (qh_ERRinput, NULL, NULL);
04004   }
04005   if (!(qh feasible_point= (pointT*)malloc (dim* sizeof(coordT)))) {
04006     fprintf(qh ferr, "qhull error: insufficient memory for 'Hn,n,n'\n");
04007     qh_errexit(qh_ERRmem, NULL, NULL);
04008   }
04009   coords= qh feasible_point;
04010   while (*s) {
04011     value= qh_strtod (s, &s);
04012     if (++tokcount > dim) {
04013       fprintf (qh ferr, "qhull input warning: more coordinates for 'H%s' than dimension %d\n",
04014           qh feasible_string, dim);
04015       break;
04016     }
04017     *(coords++)= value;
04018     if (*s)
04019       s++;
04020   }
04021   while (++tokcount <= dim)    
04022     *(coords++)= 0.0;
04023 } /* setfeasible */
04024 
04025 /*-<a                             href="qh-io.htm#TOC"
04026   >-------------------------------</a><a name="skipfacet">-</a>
04027   
04028   qh_skipfacet( facet )
04029     returns 'True' if this facet is not to be printed 
04030 
04031   notes:
04032     based on the user provided slice thresholds and 'good' specifications
04033 */
04034 boolT qh_skipfacet(facetT *facet) {
04035   facetT *neighbor, **neighborp;
04036 
04037   if (qh PRINTneighbors) {
04038     if (facet->good)
04039       return !qh PRINTgood;
04040     FOREACHneighbor_(facet) {
04041       if (neighbor->good)
04042         return False;
04043     }
04044     return True;
04045   }else if (qh PRINTgood)
04046     return !facet->good;
04047   else if (!facet->normal)
04048     return True;
04049   return (!qh_inthresholds (facet->normal, NULL));
04050 } /* skipfacet */
04051 
 

Powered by Plone

This site conforms to the following standards: