io.c 93 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906
  1. /* io.c - Input/Output routines of qhull application
  2. see README and io.h
  3. see user.c for qh_errprint and qh_printfacetlist
  4. unix.c calls qh_readpoints and qh_produce_output
  5. unix.c and user.c are the only callers of io.c functions
  6. This allows the user to avoid loading io.o from qhull.a
  7. copyright (c) 1993, 1997 The Geometry Center
  8. */
  9. #include "qhull_a.h"
  10. static int qh_compare_facetarea(const void *p1, const void *p2);
  11. static int qh_compare_facetmerge(const void *p1, const void *p2);
  12. static int qh_compare_facetvisit(const void *p1, const void *p2);
  13. int qh_compare_vertexpoint(const void *p1, const void *p2); /* not used */
  14. /*========= -functions in alphabetical order after produce_output ========= */
  15. /*-------------------------------------------
  16. -produce_output- prints out the result of qhull in desired format
  17. */
  18. void qh_produce_output(void) {
  19. int i, tempsize= qh_setsize ((setT*)qhmem.tempstack), d_1;
  20. if (qh VORONOI) {
  21. qh_clearcenters (qh_ASvoronoi);
  22. qh_vertexneighbors();
  23. }
  24. if (qh GETarea)
  25. qh_getarea(qh facet_list);
  26. qh_findgood_all (qh facet_list);
  27. if (qh KEEParea || qh KEEPmerge || qh KEEPminArea < REALmax/2)
  28. qh_markkeep (qh facet_list);
  29. if (qh PRINTsummary)
  30. qh_printsummary(qh ferr);
  31. else if (qh PRINTout[0] == qh_PRINTnone)
  32. qh_printsummary(qh fout);
  33. for (i= 0; i< qh_PRINTEND; i++)
  34. qh_printfacets (qh fout, qh PRINTout[i], qh facet_list, NULL, !qh_ALL);
  35. qh_allstatistics();
  36. if (qh PRINTprecision && !qh MERGING)
  37. qh_printstats (qh ferr, qhstat precision, NULL);
  38. if (qh PRINTstatistics) {
  39. qh_collectstatistics();
  40. qh_printstatistics(qh ferr, "");
  41. qh_memstatistics (qh ferr);
  42. d_1= sizeof(setT) + (qh hull_dim - 1) * SETelemsize;
  43. fprintf(qh ferr, "\
  44. size in bytes: hashentry %d merge %d ridge %d vertex %d facet %d\n\
  45. normal %d ridge vertices %d facet vertices or neighbors %d\n",
  46. sizeof(hashentryT), sizeof(mergeT), sizeof(ridgeT),
  47. sizeof(vertexT), sizeof(facetT),
  48. qh normal_size, d_1, d_1 + SETelemsize);
  49. }
  50. if (qh_setsize ((setT*)qhmem.tempstack) != tempsize) {
  51. fprintf (qh ferr, "qhull internal error (qh_produce_output): temporary sets not empty (%d)\n",
  52. qh_setsize ((setT*)qhmem.tempstack));
  53. qh_errexit (qh_ERRqhull, NULL, NULL);
  54. }
  55. } /* produce_output */
  56. /*-------------------------------------------------
  57. -compare_vertexpoint- used by qsort() to order vertices by point id
  58. them
  59. */
  60. int qh_compare_vertexpoint(const void *p1, const void *p2) {
  61. vertexT *a= *((vertexT **)p1), *b= *((vertexT **)p2);
  62. return ((qh_pointid(a->point) > qh_pointid(b->point)?1:-1));
  63. } /* compare_vertexpoint */
  64. /*-------------------------------------------------
  65. -compare_facetarea- used by qsort() to order facets by area
  66. */
  67. static int qh_compare_facetarea(const void *p1, const void *p2) {
  68. facetT *a= *((facetT **)p1), *b= *((facetT **)p2);
  69. if (!a->isarea)
  70. return -1;
  71. if (!b->isarea)
  72. return 1;
  73. if (a->f.area > b->f.area)
  74. return 1;
  75. else if (a->f.area == b->f.area)
  76. return 0;
  77. return -1;
  78. } /* compare_facetarea */
  79. /*-------------------------------------------------
  80. -compare_facetmerge- used by qsort() to order facets by number of merges
  81. */
  82. static int qh_compare_facetmerge(const void *p1, const void *p2) {
  83. facetT *a= *((facetT **)p1), *b= *((facetT **)p2);
  84. return (a->nummerge - b->nummerge);
  85. } /* compare_facetvisit */
  86. /*-------------------------------------------------
  87. -compare_facetvisit- used by qsort() to order facets by visit id or id
  88. */
  89. static int qh_compare_facetvisit(const void *p1, const void *p2) {
  90. facetT *a= *((facetT **)p1), *b= *((facetT **)p2);
  91. int i,j;
  92. if (!(i= a->visitid))
  93. i= - a->id; /* do not convert to int */
  94. if (!(j= b->visitid))
  95. j= - b->id;
  96. return (i - j);
  97. } /* compare_facetvisit */
  98. /*-------------------------------------------------
  99. -countfacets- count good facets for printing and set visitid
  100. returns:
  101. each facet with ->visitid indicating 1-relative position
  102. ->visitid==0 indicates not good
  103. numfacets, numsimplicial, total neighbors, numridges, coplanars
  104. if NEWfacets, does not count visible facets (matches qh_printafacet)
  105. */
  106. void qh_countfacets (facetT *facetlist, setT *facets, boolT printall,
  107. int *numfacetsp, int *numsimplicialp, int *totneighborsp, int *numridgesp, int *numcoplanarsp) {
  108. facetT *facet, **facetp;
  109. int numfacets= 0, numsimplicial= 0, numridges= 0, totneighbors= 0, numcoplanars= 0;
  110. FORALLfacet_(facetlist) {
  111. if ((facet->visible && qh NEWfacets)
  112. || (!printall && qh_skipfacet(facet)))
  113. facet->visitid= 0;
  114. else {
  115. facet->visitid= ++numfacets;
  116. totneighbors += qh_setsize (facet->neighbors);
  117. if (facet->simplicial)
  118. numsimplicial++;
  119. else
  120. numridges += qh_setsize (facet->ridges);
  121. if (facet->coplanarset)
  122. numcoplanars += qh_setsize (facet->coplanarset);
  123. }
  124. }
  125. FOREACHfacet_(facets) {
  126. if ((facet->visible && qh NEWfacets)
  127. || (!printall && qh_skipfacet(facet)))
  128. facet->visitid= 0;
  129. else {
  130. facet->visitid= ++numfacets;
  131. totneighbors += qh_setsize (facet->neighbors);
  132. if (facet->simplicial)
  133. numsimplicial++;
  134. else
  135. numridges += qh_setsize (facet->ridges);
  136. if (facet->coplanarset)
  137. numcoplanars += qh_setsize (facet->coplanarset);
  138. }
  139. }
  140. qh visit_id += numfacets+1;
  141. *numfacetsp= numfacets;
  142. *numsimplicialp= numsimplicial;
  143. *totneighborsp= totneighbors;
  144. *numridgesp= numridges;
  145. *numcoplanarsp= numcoplanars;
  146. } /* countfacets */
  147. /*---------------------------------------
  148. -dfacet- print facet by id, for debugging
  149. */
  150. void dfacet (unsigned id) {
  151. facetT *facet;
  152. FORALLfacets {
  153. if (facet->id == id) {
  154. qh_printfacet (qh fout, facet);
  155. break;
  156. }
  157. }
  158. } /* dfacet */
  159. /*---------------------------------------
  160. -dvertex- print vertex by id, for debugging
  161. */
  162. void dvertex (unsigned id) {
  163. vertexT *vertex;
  164. FORALLvertices {
  165. if (vertex->id == id) {
  166. qh_printvertex (qh fout, vertex);
  167. break;
  168. }
  169. }
  170. } /* dvertex */
  171. /*----------------------------------------
  172. -facet2point- return two temporary projected points for a 2-d facet
  173. may be non-simplicial, returns mindist
  174. */
  175. void qh_facet2point(facetT *facet, pointT **point0, pointT **point1, realT *mindist) {
  176. vertexT *vertex0, *vertex1;
  177. realT dist;
  178. if (facet->toporient ^ qh_ORIENTclock) {
  179. vertex0= SETfirstt_(facet->vertices, vertexT);
  180. vertex1= SETsecondt_(facet->vertices, vertexT);
  181. }else {
  182. vertex1= SETfirstt_(facet->vertices, vertexT);
  183. vertex0= SETsecondt_(facet->vertices, vertexT);
  184. }
  185. zadd_(Zdistio, 2);
  186. qh_distplane(vertex0->point, facet, &dist);
  187. *mindist= dist;
  188. *point0= qh_projectpoint(vertex0->point, facet, dist);
  189. qh_distplane(vertex1->point, facet, &dist);
  190. minimize_(*mindist, dist);
  191. *point1= qh_projectpoint(vertex1->point, facet, dist);
  192. } /* facet2point */
  193. /*-------------------------------------------
  194. -facetvertices- returns temporary set of vertices in a set or list of facets
  195. optimized for allfacets of facet_list
  196. */
  197. setT *qh_facetvertices (facetT *facetlist, setT *facets, boolT allfacets) {
  198. setT *vertices;
  199. facetT *facet, **facetp;
  200. vertexT *vertex, **vertexp;
  201. if (facetlist == qh facet_list && allfacets && !facets) {
  202. vertices= qh_settemp (qh num_vertices);
  203. FORALLvertices
  204. qh_setappend (&vertices, vertex);
  205. }else {
  206. vertices= qh_settemp (qh TEMPsize);
  207. qh vertex_visit++;
  208. FORALLfacet_(facetlist) {
  209. if (!allfacets && qh_skipfacet (facet))
  210. continue;
  211. FOREACHvertex_(facet->vertices) {
  212. if (vertex->visitid != qh vertex_visit) {
  213. vertex->visitid= qh vertex_visit;
  214. qh_setappend (&vertices, vertex);
  215. }
  216. }
  217. }
  218. }
  219. FOREACHfacet_(facets) {
  220. if (!allfacets && qh_skipfacet (facet))
  221. continue;
  222. FOREACHvertex_(facet->vertices) {
  223. if (vertex->visitid != qh vertex_visit) {
  224. vertex->visitid= qh vertex_visit;
  225. qh_setappend (&vertices, vertex);
  226. }
  227. }
  228. }
  229. return vertices;
  230. } /* facetvertices */
  231. /*-----------------------------------------
  232. -markkeep- mark facets that meet qh KEEParea, qh KEEPmerge, and qh KEEPminArea
  233. clears ->good
  234. recomputes qh num_good
  235. */
  236. void qh_markkeep (facetT *facetlist) {
  237. facetT *facet, **facetp;
  238. setT *facets= qh_settemp (qh num_facets);
  239. int size, count;
  240. trace2((qh ferr, "qh_markkeep: only keep %d largest and/or %d most merged facets and/or min area %.2g\n",
  241. qh KEEParea, qh KEEPmerge, qh KEEPminArea));
  242. FORALLfacet_(facetlist) {
  243. if (!facet->visible && facet->good)
  244. qh_setappend (&facets, facet);
  245. }
  246. size= qh_setsize (facets);
  247. if (qh KEEParea) {
  248. qsort (SETaddr_(facets, facetT), size,
  249. sizeof (facetT *), qh_compare_facetarea);
  250. if ((count= size - qh KEEParea) > 0) {
  251. FOREACHfacet_(facets) {
  252. facet->good= False;
  253. if (--count == 0)
  254. break;
  255. }
  256. }
  257. }
  258. if (qh KEEPmerge) {
  259. qsort (SETaddr_(facets, facetT), size,
  260. sizeof (facetT *), qh_compare_facetmerge);
  261. if ((count= size - qh KEEPmerge) > 0) {
  262. FOREACHfacet_(facets) {
  263. facet->good= False;
  264. if (--count == 0)
  265. break;
  266. }
  267. }
  268. }
  269. if (qh KEEPminArea < REALmax/2) {
  270. FOREACHfacet_(facets) {
  271. if (!facet->isarea || facet->f.area < qh KEEPminArea)
  272. facet->good= False;
  273. }
  274. }
  275. qh_settempfree (&facets);
  276. count= 0;
  277. FORALLfacet_(facetlist) {
  278. if (facet->good)
  279. count++;
  280. }
  281. qh num_good= count;
  282. } /* markkeep */
  283. /*-----------------------------------------
  284. -order_vertexneighbors- order neighbors for a 2-d or 3-d vertex by adjacency
  285. does not orient the neighbors
  286. */
  287. void qh_order_vertexneighbors(vertexT *vertex) {
  288. setT *newset;
  289. facetT *facet, *neighbor, **neighborp;
  290. trace4((qh ferr, "qh_order_vertexneighbors: order neighbors of v%d for 3-d\n", vertex->id));
  291. newset= qh_settemp (qh_setsize (vertex->neighbors));
  292. facet= (facetT*)qh_setdellast (vertex->neighbors);
  293. qh_setappend (&newset, facet);
  294. while (qh_setsize (vertex->neighbors)) {
  295. FOREACHneighbor_(vertex) {
  296. if (qh_setin (facet->neighbors, neighbor)) {
  297. qh_setdel(vertex->neighbors, neighbor);
  298. qh_setappend (&newset, neighbor);
  299. facet= neighbor;
  300. break;
  301. }
  302. }
  303. if (!neighbor) {
  304. fprintf (qh ferr, "qhull internal error (qh_order_vertexneighbors): no neighbor of v%d for f%d\n",
  305. vertex->id, facet->id);
  306. qh_errexit (qh_ERRqhull, facet, NULL);
  307. }
  308. }
  309. qh_setfree (&vertex->neighbors);
  310. qh_settemppop ();
  311. vertex->neighbors= newset;
  312. } /* order_vertexneighbors */
  313. /*-----------------------------------------
  314. -printafacet- print facet in given output format (see qh PRINTout)
  315. nop if skipfacet() unless printall
  316. nop if visible facet and NEWfacets and format != PRINTfacets
  317. must match qh_countfacets
  318. preserves qh visit_id
  319. facet->normal may be null if PREmerge/MERGEexact and STOPcone before merge
  320. */
  321. void qh_printafacet(FILE *fp, int format, facetT *facet, boolT printall) {
  322. realT color[4], mindist, offset, dist;
  323. boolT zerodiv;
  324. coordT *point, *normp, *coordp, **pointp, *feasiblep;
  325. int k;
  326. vertexT *vertex, **vertexp;
  327. facetT *neighbor, **neighborp;
  328. if (!printall && qh_skipfacet (facet))
  329. return;
  330. if (facet->visible && qh NEWfacets && format != qh_PRINTfacets)
  331. return;
  332. qh printoutnum++;
  333. switch (format) {
  334. case qh_PRINTarea:
  335. if (facet->isarea) {
  336. fprintf (fp, qh_REAL_1, facet->f.area);
  337. fprintf (fp, "\n");
  338. }else
  339. fprintf (fp, "0\n");
  340. break;
  341. case qh_PRINTcoplanars:
  342. fprintf (fp, "%d", qh_setsize (facet->coplanarset));
  343. FOREACHpoint_(facet->coplanarset)
  344. fprintf (fp, " %d", qh_pointid (point));
  345. fprintf (fp, "\n");
  346. break;
  347. case qh_PRINTcentrums:
  348. qh_printcenter (fp, format, NULL, facet);
  349. break;
  350. case qh_PRINTfacets:
  351. qh_printfacet (fp, facet);
  352. break;
  353. case qh_PRINTfacets_xridge:
  354. qh_printfacetheader (fp, facet);
  355. break;
  356. case qh_PRINTgeom: /* either 2 , 3, or 4-d by qh_printbegin */
  357. if (!facet->normal)
  358. break;
  359. for (k= qh hull_dim; k--; ) {
  360. color[k]= (facet->normal[k]+1.0)/2.0;
  361. maximize_(color[k], -1.0);
  362. minimize_(color[k], +1.0);
  363. }
  364. qh_projectdim3 (color, color);
  365. if (qh PRINTdim != qh hull_dim)
  366. qh_normalize2 (color, 3, True, NULL, NULL);
  367. if (qh hull_dim <= 2)
  368. qh_printfacet2geom (fp, facet, color);
  369. else if (qh hull_dim == 3) {
  370. if (facet->simplicial)
  371. qh_printfacet3geom_simplicial (fp, facet, color);
  372. else
  373. qh_printfacet3geom_nonsimplicial (fp, facet, color);
  374. }else {
  375. if (facet->simplicial)
  376. qh_printfacet4geom_simplicial (fp, facet, color);
  377. else
  378. qh_printfacet4geom_nonsimplicial (fp, facet, color);
  379. }
  380. break;
  381. case qh_PRINTids:
  382. fprintf (fp, "%d\n", facet->id);
  383. break;
  384. case qh_PRINTincidences:
  385. case qh_PRINToff:
  386. case qh_PRINTtriangles:
  387. if (qh hull_dim == 3 && format != qh_PRINTtriangles)
  388. qh_printfacet3vertex (fp, facet, format);
  389. else if (facet->simplicial || qh hull_dim == 2 || format == qh_PRINToff)
  390. qh_printfacetNvertex_simplicial (fp, facet, format);
  391. else
  392. qh_printfacetNvertex_nonsimplicial (fp, facet, qh printoutvar++, format);
  393. break;
  394. case qh_PRINTinner:
  395. mindist= REALmax;
  396. FOREACHvertex_(facet->vertices) {
  397. qh_distplane (vertex->point, facet, &dist);
  398. minimize_(mindist, dist);
  399. }
  400. offset= facet->offset - mindist - qh DISTround;
  401. goto LABELprintnorm;
  402. break; /* prevent warning */
  403. case qh_PRINTmerges:
  404. fprintf (fp, "%d\n", facet->nummerge);
  405. break;
  406. case qh_PRINTnormals:
  407. offset= facet->offset;
  408. goto LABELprintnorm;
  409. break; /* prevent warning */
  410. case qh_PRINTouter:
  411. #if qh_MAXoutside
  412. offset= -facet->maxoutside;
  413. #endif
  414. if (!qh MERGING || !qh_MAXoutside || qh SKIPcheckmax)
  415. offset= -fmax_(qh max_outside, qh DISTround);
  416. offset -= qh DISTround; /* agrees with qh_check_points */
  417. /* 1 DISTround to actual point */
  418. offset += facet->offset;
  419. LABELprintnorm:
  420. if (!facet->normal) {
  421. fprintf (fp, "no normal for facet f%d\n", facet->id);
  422. break;
  423. }
  424. if (qh CDDoutput)
  425. fprintf (fp, qh_REAL_1, -offset);
  426. for (k=0; k<qh hull_dim; k++)
  427. fprintf (fp, qh_REAL_1, facet->normal[k]);
  428. if (!qh CDDoutput)
  429. fprintf (fp, qh_REAL_1, offset);
  430. fprintf (fp, "\n");
  431. break;
  432. case qh_PRINTmathematica: /* either 2 or 3-d by qh_printbegin */
  433. if (qh hull_dim == 2)
  434. qh_printfacet2math (fp, facet, qh printoutvar++);
  435. else
  436. qh_printfacet3math (fp, facet, qh printoutvar++);
  437. break;
  438. case qh_PRINTneighbors:
  439. fprintf (fp, "%d", qh_setsize (facet->neighbors));
  440. FOREACHneighbor_(facet)
  441. fprintf (fp, " %d",
  442. neighbor->visitid ? neighbor->visitid - 1: - neighbor->id);
  443. fprintf (fp, "\n");
  444. break;
  445. case qh_PRINTpointintersect:
  446. if (!qh feasible_point) {
  447. fprintf (fp, "qhull input error (qh_printafacet): option 'Fp' needs qh feasible_point\n");
  448. qh_errexit( qh_ERRinput, NULL, NULL);
  449. }
  450. if (facet->offset > 0)
  451. goto LABELprintinfinite;
  452. point= coordp= (coordT*)qh_memalloc (qh normal_size);
  453. normp= facet->normal;
  454. feasiblep= qh feasible_point;
  455. if (facet->offset < -qh MINdenom) {
  456. for (k= qh hull_dim; k--; )
  457. *(coordp++)= (*(normp++) / - facet->offset) + *(feasiblep++);
  458. }else {
  459. for (k= qh hull_dim; k--; ) {
  460. *(coordp++)= qh_divzero (*(normp++), facet->offset, qh MINdenom_1,
  461. &zerodiv) + *(feasiblep++);
  462. if (zerodiv) {
  463. qh_memfree (point, qh normal_size);
  464. goto LABELprintinfinite;
  465. }
  466. }
  467. }
  468. qh_printpoint (fp, NULL, point);
  469. qh_memfree (point, qh normal_size);
  470. break;
  471. LABELprintinfinite:
  472. for (k= qh hull_dim; k--; )
  473. fprintf (fp, qh_REAL_1, qh_INFINITE);
  474. fprintf (fp, "\n");
  475. break;
  476. case qh_PRINTpointnearest:
  477. FOREACHpoint_(facet->coplanarset) {
  478. int id, id2;
  479. vertex= qh_nearvertex (facet, point, &dist);
  480. id= qh_pointid (vertex->point);
  481. id2= qh_pointid (point);
  482. fprintf (fp, "%d %d %d " qh_REAL_1 "\n", id, id2, facet->id, dist);
  483. }
  484. break;
  485. case qh_PRINTpoints: /* VORONOI only by qh_printbegin */
  486. if (qh CDDoutput)
  487. fprintf (fp, "1 ");
  488. qh_printcenter (fp, format, NULL, facet);
  489. break;
  490. case qh_PRINTvertices:
  491. fprintf (fp, "%d", qh_setsize (facet->vertices));
  492. FOREACHvertex_(facet->vertices)
  493. fprintf (fp, " %d", qh_pointid (vertex->point));
  494. fprintf (fp, "\n");
  495. break;
  496. }
  497. } /* printafacet */
  498. /*-----------------------------------------
  499. -printbegin- prints header for all output formats
  500. checks for valid format
  501. uses qh visit_id for 3/4off
  502. changes qh interior_point if printing centrums
  503. */
  504. void qh_printbegin (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
  505. int numfacets, numsimplicial, numridges, totneighbors, numcoplanars;
  506. int i, num;
  507. facetT *facet, **facetp;
  508. vertexT *vertex, **vertexp;
  509. setT *vertices;
  510. pointT *point, **pointp, *pointtemp;
  511. qh printoutnum= 0;
  512. qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial,
  513. &totneighbors, &numridges, &numcoplanars);
  514. switch (format) {
  515. case qh_PRINTnone:
  516. break;
  517. case qh_PRINTarea:
  518. fprintf (fp, "%d\n", numfacets);
  519. break;
  520. case qh_PRINTcoplanars:
  521. fprintf (fp, "%d\n", numfacets);
  522. break;
  523. case qh_PRINTcentrums:
  524. if (qh CENTERtype == qh_ASnone)
  525. qh_clearcenters (qh_AScentrum);
  526. fprintf (fp, "%d\n%d\n", qh hull_dim, numfacets);
  527. break;
  528. case qh_PRINTfacets:
  529. case qh_PRINTfacets_xridge:
  530. if (facetlist)
  531. qh_printvertexlist (fp, "Vertices and facets:\n", facetlist, facets, printall);
  532. break;
  533. case qh_PRINTgeom:
  534. if (qh hull_dim > 4) /* qh_initqhull_globals also checks */
  535. goto LABELnoformat;
  536. if (qh VORONOI && qh hull_dim > 3) /* PRINTdim == DROPdim == hull_dim-1 */
  537. goto LABELnoformat;
  538. if (qh hull_dim == 2 && (qh PRINTridges || qh DOintersections))
  539. fprintf (qh ferr, "qhull warning: output for ridges and intersections not implemented in 2-d\n");
  540. if (qh hull_dim == 4 && (qh PRINTinner || qh PRINTouter ||
  541. (qh PRINTdim == 4 && qh PRINTcentrums)))
  542. fprintf (qh ferr, "qhull warning: output for outer/inner planes and centrums not implemented in 4-d\n");
  543. if (qh PRINTdim == 4 && (qh PRINTspheres))
  544. fprintf (qh ferr, "qhull warning: output for vertices not implemented in 4-d\n");
  545. if (qh PRINTdim == 4 && qh DOintersections && qh PRINTnoplanes)
  546. fprintf (qh ferr, "qhull warning: 'Gnh' generates no output in 4-d\n");
  547. if (qh PRINTdim == 2) {
  548. fprintf(fp, "{appearance {linewidth 3} LIST # %s | %s\n",
  549. qh rbox_command, qh qhull_command);
  550. }else if (qh PRINTdim == 3) {
  551. fprintf(fp, "{appearance {+edge -evert linewidth 2} LIST # %s | %s\n",
  552. qh rbox_command, qh qhull_command);
  553. }else if (qh PRINTdim == 4) {
  554. qh visit_id++;
  555. num= 0;
  556. FORALLfacet_(facetlist) /* get number of ridges to be printed */
  557. qh_printend4geom (NULL, facet, &num, printall);
  558. FOREACHfacet_(facets)
  559. qh_printend4geom (NULL, facet, &num, printall);
  560. qh ridgeoutnum= num;
  561. qh printoutvar= 0; /* counts number of ridges in output */
  562. fprintf (fp, "LIST # %s | %s\n", qh rbox_command, qh qhull_command);
  563. }
  564. if (qh PRINTdots) {
  565. qh printoutnum++;
  566. num= qh num_points + qh_setsize (qh other_points);
  567. if (qh DELAUNAY && qh ATinfinity)
  568. num--;
  569. if (qh PRINTdim == 4)
  570. fprintf (fp, "4VECT %d %d 1\n", num, num);
  571. else
  572. fprintf (fp, "VECT %d %d 1\n", num, num);
  573. for (i= num; i--; ) {
  574. if (i % 20 == 0)
  575. fprintf (fp, "\n");
  576. fprintf (fp, "1 ");
  577. }
  578. fprintf (fp, "# 1 point per line\n1 ");
  579. for (i= num-1; i--; ) {
  580. if (i % 20 == 0)
  581. fprintf (fp, "\n");
  582. fprintf (fp, "0 ");
  583. }
  584. fprintf (fp, "# 1 color for all\n");
  585. FORALLpoints {
  586. if (!qh DELAUNAY || !qh ATinfinity || qh_pointid(point) != qh num_points-1) {
  587. if (qh PRINTdim == 4)
  588. qh_printpoint (fp, NULL, point);
  589. else
  590. qh_printpoint3 (fp, point);
  591. }
  592. }
  593. FOREACHpoint_(qh other_points) {
  594. if (qh PRINTdim == 4)
  595. qh_printpoint (fp, NULL, point);
  596. else
  597. qh_printpoint3 (fp, point);
  598. }
  599. fprintf (fp, "0 1 1 1 # color of points\n");
  600. }
  601. if (qh PRINTdim == 4 && !qh PRINTnoplanes)
  602. /* 4dview loads up multiple 4OFF objects slowly */
  603. fprintf(fp, "4OFF %d %d 1\n", 3*qh ridgeoutnum, qh ridgeoutnum);
  604. qh PRINTcradius= 2 * qh DISTround; /* include test DISTround */
  605. if (qh PREmerge) {
  606. maximize_(qh PRINTcradius, qh premerge_centrum + qh DISTround);
  607. }else if (qh POSTmerge)
  608. maximize_(qh PRINTcradius, qh postmerge_centrum + qh DISTround);
  609. qh PRINTradius= qh PRINTcradius;
  610. if (qh PRINTspheres + qh PRINTcoplanar)
  611. maximize_(qh PRINTradius, qh maxmaxcoord * qh_MINradius);
  612. if (qh premerge_cos < REALmax/2) {
  613. maximize_(qh PRINTradius, (1- qh premerge_cos) * qh maxmaxcoord);
  614. }else if (!qh PREmerge && qh POSTmerge && qh postmerge_cos < REALmax/2) {
  615. maximize_(qh PRINTradius, (1- qh postmerge_cos) * qh maxmaxcoord);
  616. }
  617. maximize_(qh PRINTradius, qh MINvisible);
  618. if (qh PRINTdim != 4 &&
  619. (qh PRINTcoplanar || qh PRINTspheres || qh PRINTcentrums)) {
  620. vertices= qh_facetvertices (facetlist, facets, printall);
  621. if (qh PRINTspheres && qh PRINTdim <= 3)
  622. qh_printspheres (fp, vertices, qh PRINTradius);
  623. if (qh PRINTcoplanar || qh PRINTcentrums) {
  624. qh firstcentrum= True;
  625. if (qh PRINTcoplanar&& !qh PRINTspheres) {
  626. FOREACHvertex_(vertices)
  627. qh_printpointvect2 (fp, vertex->point, NULL,
  628. qh interior_point, qh PRINTradius);
  629. }
  630. FORALLfacet_(facetlist) {
  631. if (!printall && qh_skipfacet(facet))
  632. continue;
  633. if (!facet->normal)
  634. continue;
  635. if (qh PRINTcentrums && qh PRINTdim <= 3)
  636. qh_printcentrum (fp, facet, qh PRINTcradius);
  637. if (!qh PRINTcoplanar)
  638. continue;
  639. FOREACHpoint_(facet->coplanarset)
  640. qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
  641. FOREACHpoint_(facet->outsideset)
  642. qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
  643. }
  644. FOREACHfacet_(facets) {
  645. if (!printall && qh_skipfacet(facet))
  646. continue;
  647. if (!facet->normal)
  648. continue;
  649. if (qh PRINTcentrums && qh PRINTdim <= 3)
  650. qh_printcentrum (fp, facet, qh PRINTcradius);
  651. if (!qh PRINTcoplanar)
  652. continue;
  653. FOREACHpoint_(facet->coplanarset)
  654. qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
  655. FOREACHpoint_(facet->outsideset)
  656. qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
  657. }
  658. }
  659. qh_settempfree (&vertices);
  660. }
  661. qh visit_id++; /* for printing hyperplane intersections */
  662. break;
  663. case qh_PRINTids:
  664. fprintf (fp, "%d\n", numfacets);
  665. break;
  666. case qh_PRINTincidences:
  667. if (qh VORONOI)
  668. fprintf (qh ferr, "qhull warning: writing Delaunay. Use 'p' or 'o' for Voronoi centers\n");
  669. qh printoutvar= qh vertex_id; /* centrum id for non-simplicial facets */
  670. if (qh hull_dim <= 3)
  671. fprintf(fp, "%d\n", numfacets);
  672. else
  673. fprintf(fp, "%d\n", numsimplicial+numridges);
  674. break;
  675. case qh_PRINTinner:
  676. case qh_PRINTnormals:
  677. case qh_PRINTouter:
  678. if (qh CDDoutput)
  679. fprintf (fp, "%s | %s\nbegin\n %d %d real\n", qh rbox_command,
  680. qh qhull_command, numfacets, qh hull_dim+1);
  681. else
  682. fprintf (fp, "%d\n%d\n", qh hull_dim+1, numfacets);
  683. break;
  684. case qh_PRINTmathematica:
  685. if (qh hull_dim > 3) /* qh_initbuffers also checks */
  686. goto LABELnoformat;
  687. if (qh VORONOI)
  688. fprintf (qh ferr, "qhull warning: output is the Delaunay triangulation\n");
  689. fprintf(fp, "{\n");
  690. qh printoutvar= 0; /* counts number of facets for notfirst */
  691. break;
  692. case qh_PRINTmerges:
  693. fprintf (fp, "%d\n", numfacets);
  694. break;
  695. case qh_PRINTpointintersect:
  696. fprintf (fp, "%d\n%d\n", qh hull_dim, numfacets);
  697. break;
  698. case qh_PRINTneighbors:
  699. fprintf (fp, "%d\n", numfacets);
  700. break;
  701. case qh_PRINToff:
  702. case qh_PRINTtriangles:
  703. if (qh VORONOI)
  704. goto LABELnoformat;
  705. num = qh hull_dim;
  706. if (format == qh_PRINToff)
  707. fprintf (fp, "%d\n%d %d %d\n", num,
  708. qh num_points+qh_setsize (qh other_points), numfacets, totneighbors/2);
  709. else { /* qh_PRINTtriangles */
  710. qh printoutvar= qh num_points+qh_setsize (qh other_points); /* first centrum */
  711. if (qh DELAUNAY)
  712. num--; /* drop last dimension */
  713. fprintf (fp, "%d\n%d %d %d\n", num, qh printoutvar
  714. + numfacets - numsimplicial, numsimplicial + numridges, totneighbors/2);
  715. }
  716. FORALLpoints
  717. qh_printpointid (qh fout, NULL, num, point, -1);
  718. FOREACHpoint_(qh other_points)
  719. qh_printpointid (qh fout, NULL, num, point, -1);
  720. if (format == qh_PRINTtriangles) {
  721. FORALLfacets {
  722. if (!facet->simplicial && facet->visitid)
  723. qh_printcenter (qh fout, format, NULL, facet);
  724. }
  725. }
  726. break;
  727. case qh_PRINTpointnearest:
  728. fprintf (fp, "%d\n", numcoplanars);
  729. break;
  730. case qh_PRINTpoints:
  731. if (!qh VORONOI)
  732. goto LABELnoformat;
  733. if (qh CDDoutput)
  734. fprintf (fp, "%s | %s\nbegin\n%d %d real\n", qh rbox_command,
  735. qh qhull_command, numfacets, qh hull_dim);
  736. else
  737. fprintf (fp, "%d\n%d\n", qh hull_dim-1, numfacets);
  738. break;
  739. case qh_PRINTvertices:
  740. fprintf (fp, "%d\n", numfacets);
  741. break;
  742. case qh_PRINTsummary:
  743. default:
  744. LABELnoformat:
  745. fprintf (qh ferr, "qhull internal error (qh_printbegin): can not use this format for dimension %d\n",
  746. qh hull_dim);
  747. qh_errexit (qh_ERRqhull, NULL, NULL);
  748. }
  749. } /* printbegin */
  750. /*-----------------------------------------
  751. -printcenter- print facet center as either centrum or Voronoi center
  752. nop if qh CENTERtype neither CENTERvoronoi nor CENTERcentrum
  753. if upper envelope of Delaunay triangulation and point at-infinity
  754. prints qh_INFINITE instead;
  755. defines facet->center if needed
  756. string may be NULL or include %d for id. Don't include other '%' codes.
  757. if format=PRINTgeom, adds a 0 if otherwise 2-d
  758. */
  759. void qh_printcenter (FILE *fp, int format, char *string, facetT *facet) {
  760. int k, num;
  761. if (qh CENTERtype != qh_ASvoronoi && qh CENTERtype != qh_AScentrum)
  762. return;
  763. if (string)
  764. fprintf (fp, string, facet->id);
  765. if (qh CENTERtype == qh_ASvoronoi) {
  766. num= qh hull_dim-1;
  767. if (!facet->normal || !facet->upperdelaunay || !qh ATinfinity) {
  768. if (!facet->center)
  769. facet->center= qh_facetcenter (facet->vertices);
  770. for (k=0; k<num; k++)
  771. fprintf (fp, qh_REAL_1, facet->center[k]);
  772. }else {
  773. for (k=0; k<num; k++)
  774. fprintf (fp, qh_REAL_1, qh_INFINITE);
  775. }
  776. }else /* qh CENTERtype == qh_AScentrum */ {
  777. num= qh hull_dim;
  778. if (format == qh_PRINTtriangles && qh DELAUNAY)
  779. num--;
  780. if (!facet->center)
  781. facet->center= qh_getcentrum (facet);
  782. for (k=0; k<num; k++)
  783. fprintf (fp, qh_REAL_1, facet->center[k]);
  784. }
  785. if (format == qh_PRINTgeom && num == 2)
  786. fprintf (fp, " 0\n");
  787. else
  788. fprintf (fp, "\n");
  789. } /* printcenter */
  790. /*-----------------------------------------
  791. -printcentrum- print centrum for a facet in OOGL format 2-d or 3-d only
  792. defines ->center if needed
  793. */
  794. void qh_printcentrum (FILE *fp, facetT *facet, realT radius) {
  795. pointT *centrum, *projpt;
  796. boolT tempcentrum= False;
  797. realT xaxis[4], yaxis[4], normal[4], dist;
  798. realT green[3]={0, 1, 0};
  799. vertexT *apex;
  800. int k;
  801. if (qh CENTERtype == qh_AScentrum) {
  802. if (!facet->center)
  803. facet->center= qh_getcentrum (facet);
  804. centrum= facet->center;
  805. }else {
  806. centrum= qh_getcentrum (facet);
  807. tempcentrum= True;
  808. }
  809. fprintf (fp, "{appearance {-normal -edge normscale 0} ");
  810. if (qh firstcentrum) {
  811. qh firstcentrum= False;
  812. fprintf (fp, "{INST geom { define centrum CQUAD # f%d\n\
  813. -0.3 -0.3 0.0001 0 0 1 1\n\
  814. 0.3 -0.3 0.0001 0 0 1 1\n\
  815. 0.3 0.3 0.0001 0 0 1 1\n\
  816. -0.3 0.3 0.0001 0 0 1 1 } transform { \n", facet->id);
  817. }else
  818. fprintf (fp, "{INST geom { : centrum } transform { # f%d\n", facet->id);
  819. apex= SETfirstt_(facet->vertices, vertexT);
  820. qh_distplane(apex->point, facet, &dist);
  821. projpt= qh_projectpoint(apex->point, facet, dist);
  822. for (k= qh hull_dim; k--; ) {
  823. xaxis[k]= projpt[k] - centrum[k];
  824. normal[k]= facet->normal[k];
  825. }
  826. if (qh hull_dim == 2) {
  827. xaxis[2]= 0;
  828. normal[2]= 0;
  829. }else if (qh hull_dim == 4) {
  830. qh_projectdim3 (xaxis, xaxis);
  831. qh_projectdim3 (normal, normal);
  832. qh_normalize2 (normal, qh PRINTdim, True, NULL, NULL);
  833. }
  834. qh_crossproduct (3, xaxis, normal, yaxis);
  835. fprintf (fp, "%8.4g %8.4g %8.4g 0\n", xaxis[0], xaxis[1], xaxis[2]);
  836. fprintf (fp, "%8.4g %8.4g %8.4g 0\n", yaxis[0], yaxis[1], yaxis[2]);
  837. fprintf (fp, "%8.4g %8.4g %8.4g 0\n", normal[0], normal[1], normal[2]);
  838. qh_printpoint3 (fp, centrum);
  839. fprintf (fp, "1 }}}\n");
  840. qh_memfree (projpt, qh normal_size);
  841. qh_printpointvect (fp, centrum, facet->normal, NULL, radius, green);
  842. if (tempcentrum)
  843. qh_memfree (centrum, qh normal_size);
  844. } /* printcentrum */
  845. /*-----------------------------------------
  846. -printend- prints trailer for all output formats
  847. */
  848. void qh_printend (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
  849. int num;
  850. facetT *facet, **facetp;
  851. if (!qh printoutnum)
  852. fprintf (qh ferr, "qhull warning: no facets printed\n");
  853. switch (format) {
  854. case qh_PRINTgeom:
  855. if (qh hull_dim == 4 && qh DROPdim < 0 && !qh PRINTnoplanes) {
  856. qh visit_id++;
  857. num= 0;
  858. FORALLfacet_(facetlist)
  859. qh_printend4geom (fp, facet,&num, printall);
  860. FOREACHfacet_(facets)
  861. qh_printend4geom (fp, facet, &num, printall);
  862. if (num != qh ridgeoutnum || qh printoutvar != qh ridgeoutnum) {
  863. 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);
  864. qh_errexit (qh_ERRqhull, NULL, NULL);
  865. }
  866. }else
  867. fprintf(fp, "}\n");
  868. break;
  869. case qh_PRINTinner:
  870. case qh_PRINTnormals:
  871. case qh_PRINTouter:
  872. if (qh CDDoutput)
  873. fprintf (fp, "end\n");
  874. break;
  875. case qh_PRINTmathematica:
  876. fprintf(fp, "}\n");
  877. break;
  878. case qh_PRINTpoints:
  879. if (qh CDDoutput)
  880. fprintf (fp, "end\n");
  881. break;
  882. }
  883. } /* printend */
  884. /*------------------------------------------
  885. -printend4geom- helper function for printbegin/printend
  886. just counts printed ridges if fp=NULL
  887. uses visitid
  888. must agree with printfacet4geom...
  889. */
  890. void qh_printend4geom (FILE *fp, facetT *facet, int *nump, boolT printall) {
  891. realT color[3];
  892. int i, num= *nump;
  893. facetT *neighbor, **neighborp;
  894. ridgeT *ridge, **ridgep;
  895. if (!printall && qh_skipfacet(facet))
  896. return;
  897. if (qh PRINTnoplanes || (facet->visible && qh NEWfacets))
  898. return;
  899. if (!facet->normal)
  900. return;
  901. if (fp) {
  902. for (i=0; i<3; i++) {
  903. color[i]= (facet->normal[i]+1.0)/2.0;
  904. maximize_(color[i], -1.0);
  905. minimize_(color[i], +1.0);
  906. }
  907. }
  908. facet->visitid= qh visit_id;
  909. if (facet->simplicial) {
  910. FOREACHneighbor_(facet) {
  911. if (neighbor->visitid != qh visit_id) {
  912. if (fp)
  913. fprintf (fp, "3 %d %d %d %8.4g %8.4g %8.4g 1 # f%d f%d\n",
  914. 3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],
  915. facet->id, neighbor->id);
  916. num++;
  917. }
  918. }
  919. }else {
  920. FOREACHridge_(facet->ridges) {
  921. neighbor= otherfacet_(ridge, facet);
  922. if (neighbor->visitid != qh visit_id) {
  923. if (fp)
  924. fprintf (fp, "3 %d %d %d %8.4g %8.4g %8.4g 1 #r%d f%d f%d\n",
  925. 3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],
  926. ridge->id, facet->id, neighbor->id);
  927. num++;
  928. }
  929. }
  930. }
  931. *nump= num;
  932. } /* printend4geom */
  933. /*-----------------------------------------
  934. -printfacet- prints all fields of a facet to fp
  935. ridges printed in neighbor order
  936. */
  937. void qh_printfacet(FILE *fp, facetT *facet) {
  938. qh_printfacetheader (fp, facet);
  939. if (facet->ridges)
  940. qh_printfacetridges (fp, facet);
  941. } /* printfacet */
  942. /*----------------------------------------
  943. -printfacet2geom- print facet as part of a 2-d VECT for Geomview
  944. */
  945. void qh_printfacet2geom(FILE *fp, facetT *facet, realT color[3]) {
  946. pointT *point0, *point1;
  947. realT mindist, maxdist;
  948. int k;
  949. qh_facet2point (facet, &point0, &point1, &mindist);
  950. /*
  951. assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
  952. mindist is calculated within io.c. maxoutside is calculated elsewhere
  953. so a DISTround error may have occured.
  954. */
  955. if (qh MERGING) {
  956. mindist -= qh PRINTradius;
  957. #if qh_MAXoutside
  958. maxdist= facet->maxoutside+qh PRINTradius+ qh DISTround;
  959. #else
  960. maxdist= qh max_outside+qh PRINTradius+ qh DISTround;
  961. #endif
  962. if (qh PRINTcoplanar || qh PRINTspheres)
  963. maxdist += qh maxmaxcoord * qh_GEOMepsilon;
  964. }else
  965. mindist= maxdist= 0;
  966. if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner))
  967. qh_printfacet2geom_points(fp, point0, point1, facet, maxdist, color);
  968. if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter &&
  969. maxdist - mindist > 2 * qh maxmaxcoord * qh_GEOMepsilon)) {
  970. for(k= 3; k--; )
  971. color[k]= 1.0 - color[k];
  972. qh_printfacet2geom_points(fp, point0, point1, facet, mindist, color);
  973. }
  974. qh_memfree (point1, qh normal_size);
  975. qh_memfree (point0, qh normal_size);
  976. } /* printfacet2geom */
  977. /*-----------------------------------------
  978. -printfacet2geom_points- prints a 2-d facet as a VECT with 2 points at
  979. some offset. The points are on the facet's plane.
  980. */
  981. void qh_printfacet2geom_points(FILE *fp, pointT *point1, pointT *point2,
  982. facetT *facet, realT offset, realT color[3]) {
  983. pointT *p1= point1, *p2= point2;
  984. fprintf(fp, "VECT 1 2 1 2 1 # f%d\n", facet->id);
  985. if (offset != 0.0) {
  986. p1= qh_projectpoint (p1, facet, -offset);
  987. p2= qh_projectpoint (p2, facet, -offset);
  988. }
  989. fprintf(fp, "%8.4g %8.4g %8.4g\n%8.4g %8.4g %8.4g\n",
  990. p1[0], p1[1], 0.0, p2[0], p2[1], 0.0);
  991. if (offset != 0.0) {
  992. qh_memfree (p1, qh normal_size);
  993. qh_memfree (p2, qh normal_size);
  994. }
  995. fprintf(fp, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
  996. } /* printfacet2geom_points */
  997. /*----------------------------------------
  998. -printfacet2math- print 2-d Mathematica output for a facet
  999. may be non-simplicial
  1000. */
  1001. void qh_printfacet2math(FILE *fp, facetT *facet, int notfirst) {
  1002. pointT *point0, *point1;
  1003. realT mindist;
  1004. qh_facet2point (facet, &point0, &point1, &mindist);
  1005. if (notfirst)
  1006. fprintf(fp, ",");
  1007. fprintf(fp, "Line[{{%10.8g, %10.8g}, {%10.8g, %10.8g}}]\n",
  1008. point0[0], point0[1], point1[0], point1[1]);
  1009. qh_memfree (point1, qh normal_size);
  1010. qh_memfree (point0, qh normal_size);
  1011. } /* printfacet2math */
  1012. /*-----------------------------------------
  1013. -printfacet3geom_nonsimplicial- print Geomview OFF for a 3-d nonsimplicial facet.
  1014. if DOintersections, prints ridges to unvisited neighbors (qh visit_id)
  1015. uses visitid for intersections and ridges
  1016. */
  1017. void qh_printfacet3geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]) {
  1018. ridgeT *ridge, **ridgep;
  1019. setT *projectedpoints, *vertices;
  1020. vertexT *vertex, **vertexp, *vertexA, *vertexB;
  1021. pointT *projpt, *point, **pointp;
  1022. facetT *neighbor;
  1023. realT dist, mindist= REALmax, maxdist;
  1024. int cntvertices, k;
  1025. realT black[3]={0, 0, 0}, green[3]={0, 1, 0};
  1026. vertices= qh_facet3vertex (facet); /* oriented */
  1027. cntvertices= qh_setsize(vertices);
  1028. projectedpoints= qh_settemp(cntvertices);
  1029. FOREACHvertex_(vertices) {
  1030. zinc_(Zdistio);
  1031. qh_distplane(vertex->point, facet, &dist);
  1032. projpt= qh_projectpoint(vertex->point, facet, dist);
  1033. qh_setappend (&projectedpoints, projpt);
  1034. minimize_(mindist, dist);
  1035. }
  1036. /*
  1037. assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
  1038. mindist is calculated within io.c. maxoutside is calculated elsewhere
  1039. so a DISTround error may have occured.
  1040. */
  1041. if (qh MERGING) {
  1042. mindist -= qh PRINTradius;
  1043. #if qh_MAXoutside
  1044. maxdist= facet->maxoutside+qh PRINTradius+ qh DISTround;
  1045. #else
  1046. maxdist= qh max_outside+qh PRINTradius+ qh DISTround;
  1047. #endif
  1048. if (qh PRINTcoplanar || qh PRINTspheres)
  1049. maxdist += qh maxmaxcoord * qh_GEOMepsilon;
  1050. }else
  1051. mindist= maxdist= 0;
  1052. if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner))
  1053. qh_printfacet3geom_points(fp, projectedpoints, facet, maxdist, color);
  1054. if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter &&
  1055. maxdist - mindist > 2 * qh maxmaxcoord * qh_GEOMepsilon)) {
  1056. for (k=3; k--; )
  1057. color[k]= 1.0 - color[k];
  1058. qh_printfacet3geom_points(fp, projectedpoints, facet, mindist, color);
  1059. }
  1060. FOREACHpoint_(projectedpoints)
  1061. qh_memfree (point, qh normal_size);
  1062. qh_settempfree(&projectedpoints);
  1063. qh_settempfree(&vertices);
  1064. if ((qh DOintersections || qh PRINTridges)
  1065. && (!facet->visible || !qh NEWfacets)) {
  1066. facet->visitid= qh visit_id;
  1067. FOREACHridge_(facet->ridges) {
  1068. neighbor= otherfacet_(ridge, facet);
  1069. if (neighbor->visitid != qh visit_id) {
  1070. if (qh DOintersections)
  1071. qh_printhyperplaneintersection(fp, facet, neighbor, ridge->vertices, black);
  1072. if (qh PRINTridges) {
  1073. vertexA= SETfirstt_(ridge->vertices, vertexT);
  1074. vertexB= SETsecondt_(ridge->vertices, vertexT);
  1075. qh_printline3geom (fp, vertexA->point, vertexB->point, green);
  1076. }
  1077. }
  1078. }
  1079. }
  1080. } /* printfacet3geom_nonsimplicial */
  1081. /*-----------------------------------------
  1082. -printfacet3geom_points- prints a 3-d facet as OFF Geomview object.
  1083. Facet is determined as a list of points
  1084. */
  1085. void qh_printfacet3geom_points(FILE *fp, setT *points, facetT *facet, realT offset, realT color[3]) {
  1086. int k, n= qh_setsize(points), i;
  1087. pointT *point, **pointp;
  1088. setT *printpoints;
  1089. fprintf(fp, "{ OFF %d 1 1 # f%d\n", n, facet->id);
  1090. if (offset != 0.0) {
  1091. printpoints= qh_settemp (n);
  1092. FOREACHpoint_(points)
  1093. qh_setappend (&printpoints, qh_projectpoint(point, facet, -offset));
  1094. }else
  1095. printpoints= points;
  1096. FOREACHpoint_(printpoints) {
  1097. for (k=0; k<qh hull_dim; k++) {
  1098. if (k == qh DROPdim)
  1099. fprintf(fp, "0 ");
  1100. else
  1101. fprintf(fp, "%8.4g ", point[k]);
  1102. }
  1103. if (printpoints != points)
  1104. qh_memfree (point, qh normal_size);
  1105. fprintf (fp, "\n");
  1106. }
  1107. if (printpoints != points)
  1108. qh_settempfree (&printpoints);
  1109. fprintf(fp, "%d ", n);
  1110. for(i= 0; i < n; i++)
  1111. fprintf(fp, "%d ", i);
  1112. fprintf(fp, "%8.4g %8.4g %8.4g 1.0 }\n", color[0], color[1], color[2]);
  1113. } /* printfacet3geom_points */
  1114. /*-----------------------------------------
  1115. -printfacet3geom_simplicial- print Geomview OFF for a 3-d simplicial facet.
  1116. may flip color
  1117. uses visitid for intersections and ridges
  1118. */
  1119. void qh_printfacet3geom_simplicial(FILE *fp, facetT *facet, realT color[3]) {
  1120. setT *points, *vertices;
  1121. vertexT *vertex, **vertexp, *vertexA, *vertexB;
  1122. facetT *neighbor, **neighborp;
  1123. realT maxdist, mindist;
  1124. realT black[3]={0, 0, 0}, green[3]={0, 1, 0};
  1125. int k;
  1126. vertices= qh_facet3vertex (facet);
  1127. points= qh_settemp (qh TEMPsize);
  1128. FOREACHvertex_(vertices)
  1129. qh_setappend(&points, vertex->point);
  1130. /*
  1131. assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
  1132. mindist may be off by qh DISTround. Maxoutside is calculated elsewhere
  1133. so a DISTround error may have occured.
  1134. */
  1135. if (qh MERGING) {
  1136. #if qh_MAXoutside
  1137. maxdist= facet->maxoutside+qh PRINTradius+ qh DISTround;
  1138. #else
  1139. maxdist= qh max_outside+qh PRINTradius+ qh DISTround;
  1140. #endif
  1141. if (qh PRINTcoplanar || qh PRINTspheres)
  1142. maxdist += qh maxmaxcoord * qh_GEOMepsilon;
  1143. }else
  1144. maxdist= 0;
  1145. if (qh MERGING)
  1146. mindist= -qh PRINTradius - qh DISTround;
  1147. else
  1148. mindist= 0;
  1149. if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner))
  1150. qh_printfacet3geom_points(fp, points, facet, maxdist, color);
  1151. if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter &&
  1152. maxdist - mindist > 2 * qh maxmaxcoord * qh_GEOMepsilon)) {
  1153. for (k= 3; k--; )
  1154. color[k]= 1.0 - color[k];
  1155. qh_printfacet3geom_points(fp, points, facet, mindist, color);
  1156. }
  1157. qh_settempfree(&points);
  1158. qh_settempfree(&vertices);
  1159. if ((qh DOintersections || qh PRINTridges)
  1160. && (!facet->visible || !qh NEWfacets)) {
  1161. facet->visitid= qh visit_id;
  1162. FOREACHneighbor_(facet) {
  1163. if (neighbor->visitid != qh visit_id) {
  1164. vertices= qh_setnew_delnthsorted (facet->vertices, qh hull_dim,
  1165. SETindex_(facet->neighbors, neighbor), 0);
  1166. if (qh DOintersections)
  1167. qh_printhyperplaneintersection(fp, facet, neighbor, vertices, black);
  1168. if (qh PRINTridges) {
  1169. vertexA= SETfirstt_(vertices, vertexT);
  1170. vertexB= SETsecondt_(vertices, vertexT);
  1171. qh_printline3geom (fp, vertexA->point, vertexB->point, green);
  1172. }
  1173. qh_setfree(&vertices);
  1174. }
  1175. }
  1176. }
  1177. } /* printfacet3geom_simplicial */
  1178. /*-----------------------------------------
  1179. -printfacet3vertex- print vertex->point for a 3-d facet (may be non-simplicial)
  1180. prints number of vertices first if format == qh_PRINToff
  1181. */
  1182. void qh_printfacet3vertex(FILE *fp, facetT *facet, int format) {
  1183. vertexT *vertex, **vertexp;
  1184. setT *vertices;
  1185. vertices= qh_facet3vertex (facet);
  1186. if (format == qh_PRINToff)
  1187. fprintf (fp, "%d ", qh_setsize (vertices));
  1188. FOREACHvertex_(vertices)
  1189. fprintf (fp, "%d ", qh_pointid(vertex->point));
  1190. fprintf (fp, "\n");
  1191. qh_settempfree(&vertices);
  1192. } /* printfacet3vertex */
  1193. /*----------------------------------------
  1194. -printfacet3math- print 3-d Mathematica output for a facet
  1195. may be non-simplicial
  1196. */
  1197. void qh_printfacet3math (FILE *fp, facetT *facet, int notfirst) {
  1198. vertexT *vertex, **vertexp;
  1199. setT *points, *vertices;
  1200. pointT *point, **pointp;
  1201. boolT firstpoint= True;
  1202. realT dist;
  1203. if (notfirst)
  1204. fprintf(fp, ",\n");
  1205. vertices= qh_facet3vertex (facet);
  1206. points= qh_settemp (qh_setsize (vertices));
  1207. FOREACHvertex_(vertices) {
  1208. zinc_(Zdistio);
  1209. qh_distplane(vertex->point, facet, &dist);
  1210. point= qh_projectpoint(vertex->point, facet, dist);
  1211. qh_setappend (&points, point);
  1212. }
  1213. fprintf(fp, "Polygon[{");
  1214. FOREACHpoint_(points) {
  1215. if (firstpoint)
  1216. firstpoint= False;
  1217. else
  1218. fprintf(fp, ",\n");
  1219. fprintf(fp, "{%10.8g, %10.8g, %10.8g}", point[0], point[1], point[2]);
  1220. }
  1221. FOREACHpoint_(points)
  1222. qh_memfree (point, qh normal_size);
  1223. qh_settempfree(&points);
  1224. qh_settempfree(&vertices);
  1225. fprintf(fp, "}]");
  1226. } /* printfacet3math */
  1227. /*-----------------------------------------
  1228. -printfacet4geom_nonsimplicial- print Geomview 4OFF file for a 4d nonsimplicial facet
  1229. prints all ridges to unvisited neighbors (qh visit_id)
  1230. must agree with printend4geom()
  1231. prints in OFF format if DROPdim
  1232. */
  1233. void qh_printfacet4geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]) {
  1234. facetT *neighbor;
  1235. ridgeT *ridge, **ridgep;
  1236. vertexT *vertex, **vertexp;
  1237. pointT *point;
  1238. int k;
  1239. realT dist;
  1240. facet->visitid= qh visit_id;
  1241. if (qh PRINTnoplanes || (facet->visible && qh NEWfacets))
  1242. return;
  1243. FOREACHridge_(facet->ridges) {
  1244. neighbor= otherfacet_(ridge, facet);
  1245. if (neighbor->visitid == qh visit_id)
  1246. continue;
  1247. if (qh PRINTtransparent && !neighbor->good)
  1248. continue;
  1249. if (qh DOintersections)
  1250. qh_printhyperplaneintersection(fp, facet, neighbor, ridge->vertices, color);
  1251. else {
  1252. if (qh DROPdim >= 0)
  1253. fprintf(fp, "OFF 3 1 1 # f%d\n", facet->id);
  1254. else {
  1255. qh printoutvar++;
  1256. fprintf (fp, "# r%d between f%d f%d\n", ridge->id, facet->id, neighbor->id);
  1257. }
  1258. FOREACHvertex_(ridge->vertices) {
  1259. zinc_(Zdistio);
  1260. qh_distplane(vertex->point,facet, &dist);
  1261. point=qh_projectpoint(vertex->point,facet, dist);
  1262. for(k= 0; k < qh hull_dim; k++) {
  1263. if (k != qh DROPdim)
  1264. fprintf(fp, "%8.4g ", point[k]);
  1265. }
  1266. fprintf (fp, "\n");
  1267. qh_memfree (point, qh normal_size);
  1268. }
  1269. if (qh DROPdim >= 0)
  1270. fprintf(fp, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);
  1271. }
  1272. }
  1273. } /* printfacet4geom_nonsimplicial */
  1274. /*-----------------------------------------
  1275. -printfacet4geom_simplicial- print Geomview 4OFF file for a 4d simplicial facet
  1276. prints triangles for unvisited neighbors (qh visit_id)
  1277. must agree with printend4geom()
  1278. */
  1279. void qh_printfacet4geom_simplicial(FILE *fp, facetT *facet, realT color[3]) {
  1280. setT *vertices;
  1281. facetT *neighbor, **neighborp;
  1282. vertexT *vertex, **vertexp;
  1283. int k;
  1284. facet->visitid= qh visit_id;
  1285. if (qh PRINTnoplanes || (facet->visible && qh NEWfacets))
  1286. return;
  1287. FOREACHneighbor_(facet) {
  1288. if (neighbor->visitid == qh visit_id)
  1289. continue;
  1290. if (qh PRINTtransparent && !neighbor->good)
  1291. continue;
  1292. vertices= qh_setnew_delnthsorted (facet->vertices, qh hull_dim,
  1293. SETindex_(facet->neighbors, neighbor), 0);
  1294. if (qh DOintersections)
  1295. qh_printhyperplaneintersection(fp, facet, neighbor, vertices, color);
  1296. else {
  1297. if (qh DROPdim >= 0)
  1298. fprintf(fp, "OFF 3 1 1 # ridge between f%d f%d\n",
  1299. facet->id, neighbor->id);
  1300. else {
  1301. qh printoutvar++;
  1302. fprintf (fp, "# ridge between f%d f%d\n", facet->id, neighbor->id);
  1303. }
  1304. FOREACHvertex_(vertices) {
  1305. for(k= 0; k < qh hull_dim; k++) {
  1306. if (k != qh DROPdim)
  1307. fprintf(fp, "%8.4g ", vertex->point[k]);
  1308. }
  1309. fprintf (fp, "\n");
  1310. }
  1311. if (qh DROPdim >= 0)
  1312. fprintf(fp, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);
  1313. }
  1314. qh_setfree(&vertices);
  1315. }
  1316. } /* printfacet4geom_simplicial */
  1317. /*-----------------------------------------
  1318. -printfacetNvertex_nonsimplicial- print vertices for an N-d non-simplicial facet
  1319. triangulates each ridge to the id
  1320. */
  1321. void qh_printfacetNvertex_nonsimplicial(FILE *fp, facetT *facet, int id, int format) {
  1322. vertexT *vertex, **vertexp;
  1323. ridgeT *ridge, **ridgep;
  1324. if (facet->visible && qh NEWfacets)
  1325. return;
  1326. FOREACHridge_(facet->ridges) {
  1327. if (format == qh_PRINTtriangles)
  1328. fprintf(fp, "%d ", qh hull_dim);
  1329. fprintf(fp, "%d ", id);
  1330. if ((ridge->top == facet) ^ qh_ORIENTclock) {
  1331. FOREACHvertex_(ridge->vertices)
  1332. fprintf(fp, "%d ", qh_pointid(vertex->point));
  1333. }else {
  1334. FOREACHvertexreverse12_(ridge->vertices)
  1335. fprintf(fp, "%d ", qh_pointid(vertex->point));
  1336. }
  1337. fprintf(fp, "\n");
  1338. }
  1339. } /* printfacetNvertex_nonsimplicial */
  1340. /*-----------------------------------------
  1341. -printfacetNvertex_simplicial- print vertices for an N-d simplicial facet
  1342. also prints PRINToff format for non-simplicial facets
  1343. */
  1344. void qh_printfacetNvertex_simplicial(FILE *fp, facetT *facet, int format) {
  1345. vertexT *vertex, **vertexp;
  1346. if (format == qh_PRINToff || format == qh_PRINTtriangles)
  1347. fprintf (fp, "%d ", qh_setsize (facet->vertices));
  1348. if ((facet->toporient ^ qh_ORIENTclock) || !facet->simplicial) {
  1349. FOREACHvertex_(facet->vertices)
  1350. fprintf(fp, "%d ", qh_pointid(vertex->point));
  1351. }else {
  1352. FOREACHvertexreverse12_(facet->vertices)
  1353. fprintf(fp, "%d ", qh_pointid(vertex->point));
  1354. }
  1355. fprintf(fp, "\n");
  1356. } /* printfacetNvertex_simplicial */
  1357. /*-----------------------------------------
  1358. -printfacetheader- prints header fields of a facet to fp
  1359. */
  1360. void qh_printfacetheader(FILE *fp, facetT *facet) {
  1361. pointT *point, **pointp, *furthest;
  1362. facetT *neighbor, **neighborp;
  1363. realT dist;
  1364. if (facet == qh_MERGEridge) {
  1365. fprintf (fp, " MERGEridge\n");
  1366. return;
  1367. }else if (facet == qh_DUPLICATEridge) {
  1368. fprintf (fp, " DUPLICATEridge\n");
  1369. return;
  1370. }else if (!facet) {
  1371. fprintf (fp, " NULLfacet\n");
  1372. return;
  1373. }
  1374. fprintf(fp, "- f%d\n", facet->id);
  1375. fprintf(fp, " - flags:");
  1376. if (facet->toporient)
  1377. fprintf(fp, " top");
  1378. else
  1379. fprintf(fp, " bottom");
  1380. if (facet->simplicial)
  1381. fprintf(fp, " simplicial");
  1382. if (facet->upperdelaunay)
  1383. fprintf(fp, " upperDelaunay");
  1384. if (facet->visible)
  1385. fprintf(fp, " visible");
  1386. if (facet->newfacet)
  1387. fprintf(fp, " new");
  1388. if (facet->tested)
  1389. fprintf(fp, " tested");
  1390. if (!facet->good)
  1391. fprintf(fp, " notG");
  1392. if (facet->seen)
  1393. fprintf(fp, " seen");
  1394. if (facet->coplanar)
  1395. fprintf(fp, " coplanar");
  1396. if (facet->mergehorizon)
  1397. fprintf(fp, " mergehorizon");
  1398. if (facet->keepcentrum)
  1399. fprintf(fp, " keepcentrum");
  1400. if (facet->dupridge)
  1401. fprintf(fp, " dupridge");
  1402. if (facet->mergeridge && !facet->mergeridge2)
  1403. fprintf(fp, " mergeridge1");
  1404. if (facet->mergeridge2)
  1405. fprintf(fp, " mergeridge2");
  1406. if (facet->newmerge)
  1407. fprintf(fp, " newmerge");
  1408. if (facet->flipped)
  1409. fprintf(fp, " flipped");
  1410. if (facet->notfurthest)
  1411. fprintf(fp, " notfurthest");
  1412. if (facet->degenerate)
  1413. fprintf(fp, " degenerate");
  1414. if (facet->redundant)
  1415. fprintf(fp, " redundant");
  1416. fprintf(fp, "\n");
  1417. if (facet->isarea)
  1418. fprintf(fp, " - area: %2.2g\n", facet->f.area);
  1419. else if (qh NEWfacets && facet->visible && facet->f.replace)
  1420. fprintf(fp, " - replacement: f%d\n", facet->f.replace->id);
  1421. else if (facet->newfacet) {
  1422. if (facet->f.samecycle && facet->f.samecycle != facet)
  1423. fprintf(fp, " - shares same visible/horizon as f%d\n", facet->f.samecycle->id);
  1424. }else if (facet->f.newcycle)
  1425. fprintf(fp, " - was horizon to f%d\n", facet->f.newcycle->id);
  1426. if (facet->nummerge)
  1427. fprintf(fp, " - merges: %d\n", facet->nummerge);
  1428. qh_printpointid(fp, " - normal: ", qh hull_dim, facet->normal, -1);
  1429. fprintf(fp, " - offset: %10.7g\n", facet->offset);
  1430. if (qh CENTERtype == qh_ASvoronoi || facet->center)
  1431. qh_printcenter (fp, qh_PRINTfacets, " - center: ", facet);
  1432. #if qh_MAXoutside
  1433. if (facet->maxoutside > qh DISTround)
  1434. fprintf(fp, " - maxoutside: %10.7g\n", facet->maxoutside);
  1435. #endif
  1436. if (!SETempty_(facet->outsideset)) {
  1437. furthest= (pointT*)qh_setlast(facet->outsideset);
  1438. if (qh_setsize (facet->outsideset) < 6) {
  1439. fprintf(fp, " - outside set (furthest p%d):\n", qh_pointid(furthest));
  1440. FOREACHpoint_(facet->outsideset)
  1441. qh_printpoint(fp, " ", point);
  1442. }else if (qh_setsize (facet->outsideset) < 21) {
  1443. qh_printpoints(fp, " - outside set:", facet->outsideset);
  1444. }else {
  1445. fprintf(fp, " - outside set: %d points.", qh_setsize(facet->outsideset));
  1446. qh_printpoint(fp, " Furthest", furthest);
  1447. }
  1448. #if !qh_COMPUTEfurthest
  1449. fprintf(fp, " - furthest distance= %2.2g\n", facet->furthestdist);
  1450. #endif
  1451. }
  1452. if (!SETempty_(facet->coplanarset)) {
  1453. furthest= (pointT*)qh_setlast(facet->coplanarset);
  1454. if (qh_setsize (facet->coplanarset) < 6) {
  1455. fprintf(fp, " - coplanar set (furthest p%d):\n", qh_pointid(furthest));
  1456. FOREACHpoint_(facet->coplanarset)
  1457. qh_printpoint(fp, " ", point);
  1458. }else if (qh_setsize (facet->coplanarset) < 21) {
  1459. qh_printpoints(fp, " - coplanar set:", facet->coplanarset);
  1460. }else {
  1461. fprintf(fp, " - coplanar set: %d points.", qh_setsize(facet->coplanarset));
  1462. qh_printpoint(fp, " Furthest", furthest);
  1463. }
  1464. zinc_(Zdistio);
  1465. qh_distplane (furthest, facet, &dist);
  1466. fprintf(fp, " furthest distance= %2.2g\n", dist);
  1467. }
  1468. qh_printvertices (fp, " - vertices:", facet->vertices);
  1469. fprintf(fp, " - neighboring facets: ");
  1470. FOREACHneighbor_(facet) {
  1471. if (neighbor == qh_MERGEridge)
  1472. fprintf(fp, " MERGE");
  1473. else if (neighbor == qh_DUPLICATEridge)
  1474. fprintf(fp, " DUP");
  1475. else
  1476. fprintf(fp, " f%d", neighbor->id);
  1477. }
  1478. fprintf(fp, "\n");
  1479. } /* printfacetheader */
  1480. /*-----------------------------------------
  1481. -printfacetridges- prints ridges of a facet to fp
  1482. ridges printed in neighbor order
  1483. assumes the ridges exist
  1484. */
  1485. void qh_printfacetridges(FILE *fp, facetT *facet) {
  1486. facetT *neighbor, **neighborp;
  1487. ridgeT *ridge, **ridgep;
  1488. int numridges= 0;
  1489. if (facet->visible && qh NEWfacets) {
  1490. fprintf(fp, " - ridges (ids may be garbage):");
  1491. FOREACHridge_(facet->ridges)
  1492. fprintf(fp, " r%d", ridge->id);
  1493. fprintf(fp, "\n");
  1494. }else {
  1495. fprintf(fp, " - ridges:\n");
  1496. FOREACHridge_(facet->ridges)
  1497. ridge->seen= False;
  1498. if (qh hull_dim == 3) {
  1499. ridge= SETfirstt_(facet->ridges, ridgeT);
  1500. while (ridge && !ridge->seen) {
  1501. ridge->seen= True;
  1502. qh_printridge(fp, ridge);
  1503. numridges++;
  1504. ridge= qh_nextridge3d (ridge, facet, NULL);
  1505. }
  1506. }else {
  1507. FOREACHneighbor_(facet) {
  1508. FOREACHridge_(facet->ridges) {
  1509. if (otherfacet_(ridge,facet) == neighbor) {
  1510. ridge->seen= True;
  1511. qh_printridge(fp, ridge);
  1512. numridges++;
  1513. }
  1514. }
  1515. }
  1516. }
  1517. if (numridges != qh_setsize (facet->ridges)) {
  1518. fprintf (fp, " - all ridges:");
  1519. FOREACHridge_(facet->ridges)
  1520. fprintf (fp, " r%d", ridge->id);
  1521. fprintf (fp, "\n");
  1522. }
  1523. FOREACHridge_(facet->ridges) {
  1524. if (!ridge->seen)
  1525. qh_printridge(fp, ridge);
  1526. }
  1527. }
  1528. } /* printfacetridges */
  1529. /*-----------------------------------------
  1530. -printfacets- prints facetlist and/or facet set in output format
  1531. */
  1532. void qh_printfacets(FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
  1533. int numfacets, numsimplicial, numridges, totneighbors, numcoplanars;
  1534. facetT *facet, **facetp;
  1535. setT *vertices;
  1536. coordT *center;
  1537. qh old_randomdist= qh RANDOMdist;
  1538. qh RANDOMdist= False;
  1539. if (qh CDDoutput && (format == qh_PRINTcentrums || format == qh_PRINTpointintersect || format == qh_PRINToff))
  1540. fprintf (qh ferr, "qhull warning: CDD format is not available for centrums, halfspace\nintersections, and OFF file format.\n");
  1541. if (format == qh_PRINTnone)
  1542. ; /* print nothing */
  1543. else if (format == qh_PRINTaverage) {
  1544. vertices= qh_facetvertices (facetlist, facets, printall);
  1545. center= qh_getcenter (vertices);
  1546. fprintf (fp, "%d 1\n", qh hull_dim);
  1547. qh_printpointid (fp, NULL, qh hull_dim, center, -1);
  1548. qh_memfree (center, qh normal_size);
  1549. qh_settempfree (&vertices);
  1550. }else if (format == qh_PRINToptions)
  1551. fprintf(fp, "Options selected for qhull %s:\n%s\n", qh_version, qh qhull_options);
  1552. else if (format == qh_PRINTpoints && !qh VORONOI)
  1553. qh_printpoints_out (fp, facetlist, facets, printall);
  1554. else if (format == qh_PRINTqhull)
  1555. fprintf (fp, "%s | %s\n", qh rbox_command, qh qhull_command);
  1556. else if (format == qh_PRINTsize) {
  1557. fprintf (fp, "0\n2 ");
  1558. fprintf (fp, qh_REAL_1, qh totarea);
  1559. fprintf (fp, qh_REAL_1, qh totvol);
  1560. fprintf (fp, "\n");
  1561. }else if (format == qh_PRINTsummary) {
  1562. qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial,
  1563. &totneighbors, &numridges, &numcoplanars);
  1564. vertices= qh_facetvertices (facetlist, facets, printall);
  1565. fprintf (fp, "7 %d %d %d %d %d %d %d\n2 ", qh hull_dim,
  1566. qh num_points + qh_setsize (qh other_points),
  1567. qh num_vertices, qh num_facets - qh num_visible,
  1568. qh_setsize (vertices), numfacets, numcoplanars);
  1569. fprintf (fp, qh_REAL_2n, qh max_outside + qh DISTround,
  1570. qh min_vertex - qh DISTround); /* agrees with qh_check_points */
  1571. qh_settempfree (&vertices);
  1572. }else if (format == qh_PRINTvneighbors)
  1573. qh_printvneighbors (fp, facetlist, facets, printall);
  1574. else if (qh VORONOI && format == qh_PRINToff)
  1575. qh_printvoronoi (fp, format, facetlist, facets, printall);
  1576. else if (qh VORONOI && format == qh_PRINTgeom) {
  1577. qh_printbegin (fp, format, facetlist, facets, printall);
  1578. qh_printvoronoi (fp, format, facetlist, facets, printall);
  1579. qh_printend (fp, format, facetlist, facets, printall);
  1580. }else {
  1581. qh_printbegin (fp, format, facetlist, facets, printall);
  1582. FORALLfacet_(facetlist)
  1583. qh_printafacet (fp, format, facet, printall);
  1584. FOREACHfacet_(facets)
  1585. qh_printafacet (fp, format, facet, printall);
  1586. qh_printend (fp, format, facetlist, facets, printall);
  1587. }
  1588. qh RANDOMdist= qh old_randomdist;
  1589. } /* printfacets */
  1590. /*-----------------------------------------
  1591. -printhelp_degenerate- prints descriptive message
  1592. no message if qh_QUICKhelp
  1593. */
  1594. void qh_printhelp_degenerate(FILE *fp) {
  1595. if (qh MERGEexact || qh PREmerge)
  1596. fprintf(fp, "\n\
  1597. A Qhull error has occurred. It should have corrected the above\n\
  1598. precision error. Please report the error to qhull_bug@geom.umn.edu\n");
  1599. else if (!qh_QUICKhelp) {
  1600. fprintf(fp, "\n\
  1601. Precision problems were detected during construction of the convex hull.\n\
  1602. This occurs because convex hull algorithms assume that calculations are\n\
  1603. exact, but floating-point arithmetic has roundoff errors.\n\
  1604. \n\
  1605. To correct for precision problems, do not use 'Q0'. By default, Qhull\n\
  1606. selects 'C-0' or 'Qx' and merges non-convex facets. See \"Imprecision\n\
  1607. in Qhull\" (qh-impre.htm).\n\
  1608. \n\
  1609. If you use 'Q0', the output may include\n\
  1610. coplanar ridges, concave ridges, and flipped facets. In 4-d and higher,\n\
  1611. Qhull may produce a ridge with four neighbors or two facets with the same \n\
  1612. vertices. Qhull reports these events when they occur. It stops when a\n\
  1613. concave ridge, flipped facet, or duplicate facet occurs.\n");
  1614. #if REALfloat
  1615. fprintf (fp, "\
  1616. \n\
  1617. Qhull is currently using single precision arithmetic. The following\n\
  1618. will probably remove the precision problems:\n\
  1619. - recompile qhull for double precision (#define REALfloat 0 in user.h).\n");
  1620. #endif
  1621. if (qh DELAUNAY && !qh SCALElast && qh maxmaxcoord > 1e4)
  1622. fprintf( fp, "\
  1623. \n\
  1624. When computing the Delaunay triangulation of coordinates > 1.0,\n\
  1625. - use 'Qbb' to scale the last coordinate to [0,m] (max previous coordinate)\n");
  1626. if (qh DELAUNAY && !qh ATinfinity)
  1627. fprintf( fp, "\
  1628. When computing the Delaunay triangulation:\n\
  1629. - use 'Qz' to add a point at-infinity. This reduces precision problems.\n");
  1630. fprintf(fp, "\
  1631. \n\
  1632. If you need triangular output:\n\
  1633. - use option 'Ft' instead of 'Q0'.\n\
  1634. It triangulates non-simplicial facets with added points.\n\
  1635. \n\
  1636. If you must use 'Q0',\n\
  1637. try one or more of the following options. They can not guarantee an output.\n\
  1638. - use 'QbB' to scale the input to a cube.\n\
  1639. - use 'Po' to produce output and prevent partitioning for flipped facets\n\
  1640. - use 'V0' to set min. distance to visible facet as 0 instead of roundoff\n\
  1641. - use 'En' to specify a maximum roundoff error less than %2.2g.\n\
  1642. - options 'Qf', 'Qbb', and 'QR0' may also help\n",
  1643. qh DISTround);
  1644. fprintf(fp, "\
  1645. \n\
  1646. To guarantee simplicial output:\n\
  1647. - use option 'Ft' instead of 'Q0'\n\
  1648. - use exact arithmetic (see \"Imprecision in Qhull\", qh-impre.htm)\n\
  1649. ");
  1650. }
  1651. } /* printhelp_degenerate */
  1652. /*-----------------------------------------
  1653. -printhelp_singular- prints descriptive message
  1654. qh_QUICKhelp just prints the numbers.
  1655. */
  1656. void qh_printhelp_singular(FILE *fp) {
  1657. facetT *facet;
  1658. vertexT *vertex, **vertexp;
  1659. realT min, max, *coord, dist;
  1660. int i,k;
  1661. fprintf(fp, "\n\
  1662. The input to qhull appears to be less than %d dimensional, or a\n\
  1663. computation has overflowed.\n\n\
  1664. Qhull could not construct a clearly convex simplex from points:\n",
  1665. qh hull_dim);
  1666. qh_printvertexlist (fp, "", qh facet_list, NULL, qh_ALL);
  1667. if (!qh_QUICKhelp)
  1668. fprintf(fp, "\n\
  1669. The center point is coplanar with a facet, or a vertex is coplanar\n\
  1670. with a neighboring facet. The maximum round off error for\n\
  1671. computing distances is %2.2g. The center point, facets and distances\n\
  1672. to the center point are as follows:\n\n", qh DISTround);
  1673. qh_printpointid (fp, "center point", qh hull_dim, qh interior_point, -1);
  1674. fprintf (fp, "\n");
  1675. FORALLfacets {
  1676. fprintf (fp, "facet");
  1677. FOREACHvertex_(facet->vertices)
  1678. fprintf (fp, " p%d", qh_pointid(vertex->point));
  1679. zinc_(Zdistio);
  1680. qh_distplane(qh interior_point, facet, &dist);
  1681. fprintf (fp, " distance= %4.2g\n", dist);
  1682. }
  1683. if (!qh_QUICKhelp) {
  1684. if (qh HALFspace)
  1685. fprintf (fp, "\n\
  1686. These points are the dual of the given halfspaces. They indicate that\n\
  1687. the intersection is degenerate.\n");
  1688. fprintf (fp,"\n\
  1689. These points either have a maximum or minimum x-coordinate, or\n\
  1690. they maximize the determinant for k coordinates. Trial points\n\
  1691. are first selected from points that maximize a coordinate.\n");
  1692. if (qh hull_dim >= qh_INITIALmax)
  1693. fprintf (fp, "\n\
  1694. Because of the high dimension, the min x-coordinate and max-coordinate\n\
  1695. points are used if the determinant is non-zero. The option 'Qs' will\n\
  1696. do a better, though much slower, job. Instead of 'Qs', you can change\n\
  1697. the points by randomly rotating the input with 'QR0'.\n");
  1698. }
  1699. fprintf (fp, "\nThe min and max coordinates for each dimension are:\n");
  1700. for (k=0; k<qh hull_dim; k++) {
  1701. min= REALmax;
  1702. max= -REALmin;
  1703. for (i=qh num_points, coord= qh first_point+k; i--; coord += qh hull_dim) {
  1704. maximize_(max, *coord);
  1705. minimize_(min, *coord);
  1706. }
  1707. fprintf (fp, " %d: %8.4g %8.4g difference= %4.4g\n", k, min, max, max-min);
  1708. }
  1709. if (!qh_QUICKhelp) {
  1710. fprintf (fp, "\n\
  1711. If the input should be full dimensional, you have several options that\n\
  1712. may determine an initial simplex:\n\
  1713. - use 'QbB' to scale the points to the unit cube\n\
  1714. - use 'QR0' to randomly rotate the input for different maximum points\n\
  1715. - use the 'Qs' flag to search all points for the initial simplex\n\
  1716. - use 'En' to specify a maximum roundoff error less than %2.2g.\n\
  1717. - trace execution with 'T3' to see the determinant for each point.\n",
  1718. qh DISTround);
  1719. #if REALfloat
  1720. fprintf (fp, "\
  1721. - recompile qhull for double precision (#define REALfloat 0 in qhull.h).\n");
  1722. #endif
  1723. fprintf (fp, "\n\
  1724. If the input is lower dimensional:\n\
  1725. - use 'Qbk:0Bk:0' to delete coordinate k from the input. You should\n\
  1726. pick the coordinate with the least range. The hull will have the\n\
  1727. correct topology.\n\
  1728. - determine the flat containing the points, rotate the points\n\
  1729. into a coordinate plane, and delete the other coordinates.\n\
  1730. - add one or more points to make the input full dimensional.\n\
  1731. ");
  1732. if (qh DELAUNAY && !qh ATinfinity)
  1733. fprintf (fp, "\n\
  1734. This is a Delaunay triangulation and the input is co-circular or co-spherical:\n\
  1735. - use 'Qz' to add a point \"at infinity\" (i.e., above the paraboloid)\n");
  1736. }
  1737. } /* printhelp_singular */
  1738. /*-----------------------------------------
  1739. -printhyperplaneintersection- print Geomview OFF or 4OFF for
  1740. the intersection of two hyperplanes in 3-d or 4-d
  1741. */
  1742. void qh_printhyperplaneintersection(FILE *fp, facetT *facet1, facetT *facet2,
  1743. setT *vertices, realT color[3]) {
  1744. realT costheta, denominator, dist1, dist2, s, t, mindenom, p[4];
  1745. vertexT *vertex, **vertexp;
  1746. int i, k;
  1747. boolT nearzero1, nearzero2;
  1748. costheta= qh_getangle(facet1->normal, facet2->normal);
  1749. denominator= 1 - costheta * costheta;
  1750. i= qh_setsize(vertices);
  1751. if (qh hull_dim == 3)
  1752. fprintf(fp, "VECT 1 %d 1 %d 1 ", i, i);
  1753. else if (qh hull_dim == 4 && qh DROPdim >= 0)
  1754. fprintf(fp, "OFF 3 1 1 ");
  1755. else
  1756. qh printoutvar++;
  1757. fprintf (fp, "# intersect f%d f%d\n", facet1->id, facet2->id);
  1758. mindenom= 1 / (10.0 * qh maxmaxcoord);
  1759. FOREACHvertex_(vertices) {
  1760. zadd_(Zdistio, 2);
  1761. qh_distplane(vertex->point, facet1, &dist1);
  1762. qh_distplane(vertex->point, facet2, &dist2);
  1763. s= qh_divzero (-dist1 + costheta * dist2, denominator,mindenom,&nearzero1);
  1764. t= qh_divzero (-dist2 + costheta * dist1, denominator,mindenom,&nearzero2);
  1765. if (nearzero1 || nearzero2)
  1766. s= t= 0.0;
  1767. for(k= qh hull_dim; k--; )
  1768. p[k]= vertex->point[k] + facet1->normal[k] * s + facet2->normal[k] * t;
  1769. if (qh PRINTdim <= 3) {
  1770. qh_projectdim3 (p, p);
  1771. fprintf(fp, "%8.4g %8.4g %8.4g # ", p[0], p[1], p[2]);
  1772. }else
  1773. fprintf(fp, "%8.4g %8.4g %8.4g %8.4g # ", p[0], p[1], p[2], p[3]);
  1774. if (nearzero1+nearzero2)
  1775. fprintf (fp, "p%d (coplanar facets)\n", qh_pointid (vertex->point));
  1776. else
  1777. fprintf (fp, "projected p%d\n", qh_pointid (vertex->point));
  1778. }
  1779. if (qh hull_dim == 3)
  1780. fprintf(fp, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
  1781. else if (qh hull_dim == 4 && qh DROPdim >= 0)
  1782. fprintf(fp, "3 0 1 2 %8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
  1783. } /* printhyperplaneintersection */
  1784. /*----------------------------------------
  1785. -printline3geom- prints a line as a VECT
  1786. 0's for DROPdim
  1787. if pointA == pointB, it's a 1 point VECT
  1788. */
  1789. void qh_printline3geom (FILE *fp, pointT *pointA, pointT *pointB, realT color[3]) {
  1790. int k;
  1791. realT pA[4], pB[4];
  1792. qh_projectdim3(pointA, pA);
  1793. qh_projectdim3(pointB, pB);
  1794. if ((fabs(pA[0] - pB[0]) > 1e-3) ||
  1795. (fabs(pA[1] - pB[1]) > 1e-3) ||
  1796. (fabs(pA[2] - pB[2]) > 1e-3)) {
  1797. fprintf (fp, "VECT 1 2 1 2 1\n");
  1798. for (k= 0; k < 3; k++)
  1799. fprintf (fp, "%8.4g ", pB[k]);
  1800. fprintf (fp, " # p%d\n", qh_pointid (pointB));
  1801. }else
  1802. fprintf (fp, "VECT 1 1 1 1 1\n");
  1803. for (k=0; k< 3; k++)
  1804. fprintf (fp, "%8.4g ", pA[k]);
  1805. fprintf (fp, " # p%d\n", qh_pointid (pointA));
  1806. fprintf (fp, "%8.4g %8.4g %8.4g 1\n", color[0], color[1], color[2]);
  1807. }
  1808. /*----------------------------------------
  1809. -printneighborhood- print neighborhood of one or two facets
  1810. calls findgood_all if active and !printall
  1811. bumps qh visit_id
  1812. */
  1813. void qh_printneighborhood (FILE *fp, int format, facetT *facetA, facetT *facetB, boolT printall) {
  1814. facetT *neighbor, **neighborp, *facet;
  1815. setT *facets;
  1816. if (format == qh_PRINTnone)
  1817. return;
  1818. qh_findgood_all (qh facet_list);
  1819. if (facetA == facetB)
  1820. facetB= NULL;
  1821. facets= qh_settemp (2*(qh_setsize (facetA->neighbors)+1));
  1822. qh visit_id++;
  1823. for (facet= facetA; facet; facet= ((facet == facetA) ? facetB : NULL)) {
  1824. if (facet->visitid != qh visit_id) {
  1825. facet->visitid= qh visit_id;
  1826. qh_setappend (&facets, facet);
  1827. }
  1828. FOREACHneighbor_(facet) {
  1829. if (neighbor->visitid == qh visit_id)
  1830. continue;
  1831. neighbor->visitid= qh visit_id;
  1832. if (printall || !qh_skipfacet (neighbor))
  1833. qh_setappend (&facets, neighbor);
  1834. }
  1835. }
  1836. qh_printfacets (fp, format, NULL, facets, printall);
  1837. qh_settempfree (&facets);
  1838. } /* printneighborhood */
  1839. /*----------------------------------------
  1840. -printpoint- prints the coordinates of a point
  1841. prints point id if string and valid point (id != -1)
  1842. nop if point is NULL
  1843. */
  1844. void qh_printpoint(FILE *fp, char *string, pointT *point) {
  1845. int id= qh_pointid( point);
  1846. qh_printpointid( fp, string, qh hull_dim, point, id);
  1847. } /* printpoint */
  1848. void qh_printpointid(FILE *fp, char *string, int dim, pointT *point, int id) {
  1849. int k;
  1850. realT r; /*bug fix*/
  1851. if (!point)
  1852. return;
  1853. if (string) {
  1854. fputs (string, fp);
  1855. if (id != -1)
  1856. fprintf(fp, " p%d: ", id);
  1857. }
  1858. for(k= dim; k--; ) {
  1859. r= *point++;
  1860. if (string)
  1861. fprintf(fp, " %8.4g", r);
  1862. else
  1863. fprintf(fp, qh_REAL_1, r);
  1864. }
  1865. fprintf(fp, "\n");
  1866. } /* printpointid */
  1867. /*------------------------------------
  1868. -printpoint3- prints 2-d , 3-d, or 4-d point as Geomview 3-d coordinates
  1869. */
  1870. void qh_printpoint3 (FILE *fp, pointT *point) {
  1871. int k;
  1872. realT p[4];
  1873. qh_projectdim3 (point, p);
  1874. for (k=0; k< 3; k++)
  1875. fprintf (fp, "%8.4g ", p[k]);
  1876. fprintf (fp, " # p%d\n", qh_pointid (point));
  1877. } /* printpoint3 */
  1878. /*----------------------------------------
  1879. -printpoints- print pointids for a set of points starting at index
  1880. see geom.c
  1881. */
  1882. /*----------------------------------------
  1883. -printpoints_out- prints vertices for facets by their point coordinates
  1884. same format as qhull input
  1885. allows CDDoutput
  1886. */
  1887. void qh_printpoints_out (FILE *fp, facetT *facetlist, setT *facets, int printall) {
  1888. int allpoints= qh num_points + qh_setsize (qh other_points);
  1889. int numpoints=0, point_i, point_n;
  1890. setT *vertices, *points;
  1891. facetT *facet, **facetp;
  1892. pointT *point, **pointp;
  1893. vertexT *vertex, **vertexp;
  1894. int id;
  1895. points= qh_settemp (allpoints);
  1896. qh_setzero (points, 0, allpoints);
  1897. vertices= qh_facetvertices (facetlist, facets, printall);
  1898. FOREACHvertex_(vertices) {
  1899. id= qh_pointid (vertex->point);
  1900. if (id >= 0)
  1901. SETelem_(points, id)= vertex->point;
  1902. }
  1903. if (qh KEEPinside || qh KEEPcoplanar || qh KEEPnearinside) {
  1904. FORALLfacet_(facetlist) {
  1905. FOREACHpoint_(facet->coplanarset) {
  1906. id= qh_pointid (point);
  1907. if (id >= 0)
  1908. SETelem_(points, id)= point;
  1909. }
  1910. }
  1911. FOREACHfacet_(facets) {
  1912. FOREACHpoint_(facet->coplanarset) {
  1913. id= qh_pointid (point);
  1914. if (id >= 0)
  1915. SETelem_(points, id)= point;
  1916. }
  1917. }
  1918. }
  1919. qh_settempfree (&vertices);
  1920. FOREACHpoint_i_(points) {
  1921. if (point)
  1922. numpoints++;
  1923. }
  1924. if (qh CDDoutput)
  1925. fprintf (fp, "%s | %s\nbegin\n%d %d real\n", qh rbox_command,
  1926. qh qhull_command, numpoints, qh hull_dim + 1);
  1927. else
  1928. fprintf (fp, "%d\n%d\n", qh hull_dim, numpoints);
  1929. FOREACHpoint_i_(points) {
  1930. if (point) {
  1931. if (qh CDDoutput)
  1932. fprintf (fp, "1 ");
  1933. qh_printpoint (fp, NULL, point);
  1934. }
  1935. }
  1936. if (qh CDDoutput)
  1937. fprintf (fp, "end\n");
  1938. qh_settempfree (&points);
  1939. } /* printpoints_out */
  1940. /*----------------------------------------
  1941. -printpointvect2- prints a 2-d, 3-d, or 4-d point as 2 3-d VECT's\
  1942. for an imprecise point,
  1943. */
  1944. void qh_printpointvect2 (FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius) {
  1945. realT red[3]={1, 0, 0}, yellow[3]={1, 1, 0};
  1946. qh_printpointvect (fp, point, normal, center, radius, red);
  1947. qh_printpointvect (fp, point, normal, center, -radius, yellow);
  1948. } /* printpointvect2 */
  1949. /*----------------------------------------
  1950. -printpointvect- prints a 2-d, 3-d, or 4-d point as 3-d VECT's
  1951. relative to normal or to center point
  1952. */
  1953. void qh_printpointvect (FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius, realT color[3]) {
  1954. realT diff[4], pointA[4];
  1955. int k;
  1956. for (k= qh hull_dim; k--; ) {
  1957. if (center)
  1958. diff[k]= point[k]-center[k];
  1959. else if (normal)
  1960. diff[k]= normal[k];
  1961. else
  1962. diff[k]= 0;
  1963. }
  1964. if (center)
  1965. qh_normalize2 (diff, qh hull_dim, True, NULL, NULL);
  1966. for (k= qh hull_dim; k--; )
  1967. pointA[k]= point[k]+diff[k] * radius;
  1968. qh_printline3geom (fp, point, pointA, color);
  1969. } /* printpointvect */
  1970. /*----------------------------------------
  1971. -printridge- prints the information in a ridge
  1972. */
  1973. void qh_printridge(FILE *fp, ridgeT *ridge) {
  1974. fprintf(fp, " - r%d", ridge->id);
  1975. if (ridge->tested)
  1976. fprintf (fp, " tested");
  1977. if (ridge->nonconvex)
  1978. fprintf (fp, " nonconvex");
  1979. fprintf (fp, "\n");
  1980. qh_printvertices (fp, " vertices:", ridge->vertices);
  1981. if (ridge->top && ridge->bottom)
  1982. fprintf(fp, " between f%d and f%d\n",
  1983. ridge->top->id, ridge->bottom->id);
  1984. } /* printridge */
  1985. /*-----------------------------------------
  1986. -printspheres- prints 3-d vertices as OFF spheres
  1987. inflated octahedron from Stuart Levy earth/mksphere2
  1988. */
  1989. void qh_printspheres(FILE *fp, setT *vertices, realT radius) {
  1990. vertexT *vertex, **vertexp;
  1991. qh printoutnum++;
  1992. fprintf (fp, "{appearance {-edge -normal normscale 0} {\n\
  1993. INST geom {define vsphere OFF\n\
  1994. 18 32 48\n\
  1995. \n\
  1996. 0 0 1\n\
  1997. 1 0 0\n\
  1998. 0 1 0\n\
  1999. -1 0 0\n\
  2000. 0 -1 0\n\
  2001. 0 0 -1\n\
  2002. 0.707107 0 0.707107\n\
  2003. 0 -0.707107 0.707107\n\
  2004. 0.707107 -0.707107 0\n\
  2005. -0.707107 0 0.707107\n\
  2006. -0.707107 -0.707107 0\n\
  2007. 0 0.707107 0.707107\n\
  2008. -0.707107 0.707107 0\n\
  2009. 0.707107 0.707107 0\n\
  2010. 0.707107 0 -0.707107\n\
  2011. 0 0.707107 -0.707107\n\
  2012. -0.707107 0 -0.707107\n\
  2013. 0 -0.707107 -0.707107\n\
  2014. \n\
  2015. 3 0 6 11\n\
  2016. 3 0 7 6 \n\
  2017. 3 0 9 7 \n\
  2018. 3 0 11 9\n\
  2019. 3 1 6 8 \n\
  2020. 3 1 8 14\n\
  2021. 3 1 13 6\n\
  2022. 3 1 14 13\n\
  2023. 3 2 11 13\n\
  2024. 3 2 12 11\n\
  2025. 3 2 13 15\n\
  2026. 3 2 15 12\n\
  2027. 3 3 9 12\n\
  2028. 3 3 10 9\n\
  2029. 3 3 12 16\n\
  2030. 3 3 16 10\n\
  2031. 3 4 7 10\n\
  2032. 3 4 8 7\n\
  2033. 3 4 10 17\n\
  2034. 3 4 17 8\n\
  2035. 3 5 14 17\n\
  2036. 3 5 15 14\n\
  2037. 3 5 16 15\n\
  2038. 3 5 17 16\n\
  2039. 3 6 13 11\n\
  2040. 3 7 8 6\n\
  2041. 3 9 10 7\n\
  2042. 3 11 12 9\n\
  2043. 3 14 8 17\n\
  2044. 3 15 13 14\n\
  2045. 3 16 12 15\n\
  2046. 3 17 10 16\n} transforms { TLIST\n");
  2047. FOREACHvertex_(vertices) {
  2048. fprintf(fp, "%8.4g 0 0 0 # v%d\n 0 %8.4g 0 0\n0 0 %8.4g 0\n",
  2049. radius, vertex->id, radius, radius);
  2050. qh_printpoint3 (fp, vertex->point);
  2051. fprintf (fp, "1\n");
  2052. }
  2053. fprintf (fp, "}}}\n");
  2054. } /* printspheres */
  2055. /*----------------------------------------------
  2056. -printsummary-
  2057. see qhull.c
  2058. */
  2059. /*-------------------------------------------
  2060. -printvertex- prints the information in a vertex
  2061. */
  2062. void qh_printvertex(FILE *fp, vertexT *vertex) {
  2063. pointT *point;
  2064. int k;
  2065. facetT *neighbor, **neighborp;
  2066. realT r; /*bug fix*/
  2067. if (!vertex) {
  2068. fprintf (fp, " NULLvertex\n");
  2069. return;
  2070. }
  2071. fprintf(fp, "- p%d (v%d):", qh_pointid(vertex->point), vertex->id);
  2072. point= vertex->point;
  2073. if (point) {
  2074. for(k= qh hull_dim; k--; ) {
  2075. r= *point++;
  2076. fprintf(fp, " %5.2g", r);
  2077. }
  2078. }
  2079. if (vertex->deleted)
  2080. fprintf(fp, " deleted");
  2081. if (vertex->delridge)
  2082. fprintf (fp, " ridgedeleted");
  2083. fprintf(fp, "\n");
  2084. if (vertex->neighbors) {
  2085. fprintf(fp, " neighbors:");
  2086. FOREACHneighbor_(vertex)
  2087. fprintf(fp, " f%d", neighbor->id);
  2088. fprintf(fp, "\n");
  2089. }
  2090. } /* printvertex */
  2091. /*-------------------------------------------
  2092. -printvertexlist- prints vertices used by a facetlist or facet set
  2093. all facets if printall, else !qh_skipfacet
  2094. */
  2095. void qh_printvertexlist (FILE *fp, char* string, facetT *facetlist,
  2096. setT *facets, boolT printall) {
  2097. vertexT *vertex, **vertexp;
  2098. setT *vertices;
  2099. vertices= qh_facetvertices (facetlist, facets, printall);
  2100. fputs (string, fp);
  2101. FOREACHvertex_(vertices)
  2102. qh_printvertex(fp, vertex);
  2103. qh_settempfree (&vertices);
  2104. } /* printvertexlist */
  2105. /*-------------------------------------------
  2106. -printvertices- prints vertices in a set
  2107. */
  2108. void qh_printvertices(FILE *fp, char* string, setT *vertices) {
  2109. vertexT *vertex, **vertexp;
  2110. fputs (string, fp);
  2111. FOREACHvertex_(vertices)
  2112. fprintf (fp, " p%d (v%d)", qh_pointid(vertex->point), vertex->id);
  2113. fprintf(fp, "\n");
  2114. } /* printvertices */
  2115. /*-------------------------------------------
  2116. -printvneighbors- print vertex neighbors of vertices in facetlist and facets
  2117. */
  2118. void qh_printvneighbors (FILE *fp, facetT* facetlist, setT *facets, boolT printall) {
  2119. int numfacets, numsimplicial, numridges, totneighbors, numneighbors, numcoplanars;
  2120. setT *vertices, *vertex_points, *coplanar_points;
  2121. int numpoints= qh num_points + qh_setsize (qh other_points);
  2122. vertexT *vertex, **vertexp;
  2123. int vertex_i, vertex_n;
  2124. facetT *facet, **facetp, *neighbor, **neighborp;
  2125. pointT *point, **pointp;
  2126. qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial,
  2127. &totneighbors, &numridges, &numcoplanars); /* sets facet->visitid */
  2128. fprintf (fp, "%d\n", numpoints);
  2129. qh_vertexneighbors();
  2130. vertices= qh_facetvertices (facetlist, facets, printall);
  2131. vertex_points= qh_settemp (numpoints);
  2132. coplanar_points= qh_settemp (numpoints);
  2133. qh_setzero (vertex_points, 0, numpoints);
  2134. qh_setzero (coplanar_points, 0, numpoints);
  2135. FOREACHvertex_(vertices)
  2136. qh_point_add (vertex_points, vertex->point, vertex);
  2137. FORALLfacet_(facetlist) {
  2138. FOREACHpoint_(facet->coplanarset)
  2139. qh_point_add (coplanar_points, point, facet);
  2140. }
  2141. FOREACHfacet_(facets) {
  2142. FOREACHpoint_(facet->coplanarset)
  2143. qh_point_add (coplanar_points, point, facet);
  2144. }
  2145. FOREACHvertex_i_(vertex_points) {
  2146. if (vertex) {
  2147. numneighbors= qh_setsize (vertex->neighbors);
  2148. fprintf (fp, "%d", numneighbors);
  2149. if (qh hull_dim == 3)
  2150. qh_order_vertexneighbors (vertex);
  2151. else if (qh hull_dim >= 4)
  2152. qsort (SETaddr_(vertex->neighbors, vertexT), numneighbors,
  2153. sizeof (facetT *), qh_compare_facetvisit);
  2154. FOREACHneighbor_(vertex)
  2155. fprintf (fp, " %d",
  2156. neighbor->visitid ? neighbor->visitid - 1 : - neighbor->id);
  2157. fprintf (fp, "\n");
  2158. }else if ((facet= SETelemt_(coplanar_points, vertex_i, facetT)))
  2159. fprintf (fp, "1 %d\n",
  2160. facet->visitid ? facet->visitid - 1 : - facet->id);
  2161. else
  2162. fprintf (fp, "0\n");
  2163. }
  2164. qh_settempfree (&coplanar_points);
  2165. qh_settempfree (&vertex_points);
  2166. qh_settempfree (&vertices);
  2167. } /* printvneighbors */
  2168. /*----------------------------------------
  2169. -printvoronoi- print voronoi diagram in 'o' or 'G' format
  2170. for 'o' format
  2171. prints voronoi centers for each facet and for infinity
  2172. for each vertex, lists ids of printed facets or infinity
  2173. assumes facetlist and facets are disjoint
  2174. for 'G' format
  2175. prints an OFF object
  2176. adds a 0 coordinate to center
  2177. prints infinity but does not list in vertices
  2178. notes:
  2179. if 'o', prints a line for each point except "at-infinity"
  2180. if all facets are upperdelaunay, reverses lower and upper hull
  2181. */
  2182. void qh_printvoronoi (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
  2183. int k, numcenters=0, numvertices= 0, numneighbors, numinf, vid=1, vertex_i, vertex_n;
  2184. facetT *facet, **facetp, *neighbor, **neighborp;
  2185. setT *vertices;
  2186. vertexT *vertex;
  2187. boolT islower= False;
  2188. qh printoutnum++;
  2189. qh_vertexneighbors();
  2190. vertices= qh_pointvertex();
  2191. if (qh ATinfinity)
  2192. SETelem_(vertices, qh num_points-1)= NULL;
  2193. qh visit_id++;
  2194. maximize_(qh visit_id, (unsigned) qh num_facets);
  2195. FORALLfacet_(facetlist) { /* FIXUP: could merge with below */
  2196. if (printall || !qh_skipfacet (facet)) {
  2197. if (!facet->upperdelaunay)
  2198. islower= True;
  2199. }
  2200. }
  2201. FOREACHfacet_(facets) {
  2202. if (printall || !qh_skipfacet (facet)) {
  2203. if (!facet->upperdelaunay)
  2204. islower= True;
  2205. }
  2206. }
  2207. FORALLfacets {
  2208. if (facet->normal && (facet->upperdelaunay == islower))
  2209. facet->visitid= 0; /* facetlist or facets may overwrite */
  2210. else
  2211. facet->visitid= qh visit_id;
  2212. facet->seen= False;
  2213. }
  2214. numcenters++; /* qh_INFINITE */
  2215. FORALLfacet_(facetlist) {
  2216. if (printall || !qh_skipfacet (facet)) {
  2217. facet->visitid= numcenters++;
  2218. facet->seen= True;
  2219. }
  2220. }
  2221. FOREACHfacet_(facets) {
  2222. if (printall || !qh_skipfacet (facet)) {
  2223. facet->visitid= numcenters++;
  2224. facet->seen= True;
  2225. }
  2226. }
  2227. FOREACHvertex_i_(vertices) {
  2228. if (vertex) {
  2229. numvertices++;
  2230. numneighbors = numinf = 0;
  2231. FOREACHneighbor_(vertex) {
  2232. if (neighbor->seen)
  2233. numneighbors++;
  2234. else if (neighbor->visitid == 0)
  2235. numinf= 1;
  2236. }
  2237. if (numinf && !numneighbors) {
  2238. SETelem_(vertices, vertex_i)= NULL;
  2239. numvertices--;
  2240. }
  2241. }
  2242. }
  2243. if (format == qh_PRINTgeom)
  2244. fprintf (fp, "{appearance {+edge -face} OFF %d %d 1 # Voronoi centers and cells\n",
  2245. numcenters, numvertices);
  2246. else
  2247. fprintf (fp, "%d\n%d %d 1\n", qh hull_dim-1, numcenters, qh_setsize(vertices));
  2248. if (format == qh_PRINTgeom) {
  2249. for (k= qh hull_dim-1; k--; )
  2250. fprintf (fp, qh_REAL_1, 0.0);
  2251. fprintf (fp, " 0 # infinity not used\n");
  2252. }else {
  2253. for (k= qh hull_dim-1; k--; )
  2254. fprintf (fp, qh_REAL_1, qh_INFINITE);
  2255. fprintf (fp, "\n");
  2256. }
  2257. FORALLfacet_(facetlist) {
  2258. if (facet->seen) {
  2259. if (format == qh_PRINTgeom)
  2260. fprintf (fp, "# %d f%d\n", vid++, facet->id);
  2261. qh_printcenter (fp, format, NULL, facet);
  2262. }
  2263. }
  2264. FOREACHfacet_(facets) {
  2265. if (facet->seen) {
  2266. if (format == qh_PRINTgeom)
  2267. fprintf (fp, "# %d f%d\n", vid++, facet->id);
  2268. qh_printcenter (fp, format, NULL, facet);
  2269. }
  2270. }
  2271. FOREACHvertex_i_(vertices) {
  2272. numneighbors= 0;
  2273. numinf=0;
  2274. if (vertex) {
  2275. if (qh hull_dim == 3)
  2276. qh_order_vertexneighbors(vertex);
  2277. else if (qh hull_dim >= 4)
  2278. qsort (SETaddr_(vertex->neighbors, vertexT),
  2279. qh_setsize (vertex->neighbors),
  2280. sizeof (facetT *), qh_compare_facetvisit);
  2281. FOREACHneighbor_(vertex) {
  2282. if (neighbor->seen)
  2283. numneighbors++;
  2284. else if (neighbor->visitid == 0)
  2285. numinf= 1;
  2286. }
  2287. }
  2288. if (format == qh_PRINTgeom) {
  2289. if (vertex) {
  2290. fprintf (fp, "%d", numneighbors);
  2291. if (vertex) {
  2292. FOREACHneighbor_(vertex) {
  2293. if (neighbor->seen)
  2294. fprintf (fp, " %d", neighbor->visitid);
  2295. }
  2296. }
  2297. fprintf (fp, " # p%d (v%d)\n", vertex_i, vertex->id);
  2298. }else
  2299. fprintf (fp, " # p%d is coplanar or isolated\n", vertex_i);
  2300. }else {
  2301. if (numinf)
  2302. numneighbors++;
  2303. fprintf (fp, "%d", numneighbors);
  2304. if (vertex) {
  2305. FOREACHneighbor_(vertex) {
  2306. if (neighbor->seen)
  2307. fprintf (fp, " %d", neighbor->visitid);
  2308. else if (numinf && neighbor->visitid == 0) {
  2309. numinf= 0;
  2310. fprintf (fp, " %d", neighbor->visitid);
  2311. }
  2312. }
  2313. }
  2314. fprintf (fp, "\n");
  2315. }
  2316. }
  2317. if (format == qh_PRINTgeom)
  2318. fprintf (fp, "}\n");
  2319. qh_settempfree (&vertices);
  2320. } /* printvoronoi */
  2321. /*-------------------------------------------
  2322. -projectdim3 -- project 2-d 3-d or 4-d point to a 3-d point
  2323. uses DROPdim and hull_dim
  2324. source and destination may be the same
  2325. allocate 4 elements just in case
  2326. */
  2327. void qh_projectdim3 (pointT *source, pointT *destination) {
  2328. int i,k;
  2329. for (k= 0, i=0; k<qh hull_dim; k++) {
  2330. if (qh hull_dim == 4) {
  2331. if (k != qh DROPdim)
  2332. destination[i++]= source[k];
  2333. }else if (k == qh DROPdim)
  2334. destination[i++]= 0;
  2335. else
  2336. destination[i++]= source[k];
  2337. }
  2338. while (i < 3)
  2339. destination[i++]= 0.0;
  2340. } /* projectdim3 */
  2341. /*-------------------------------------------
  2342. -readfeasible- read feasible point from remainder and qh fin
  2343. checks for qh HALFspace
  2344. assumes dim > 1
  2345. returns:
  2346. number of lines read from qh fin
  2347. sets qh FEASIBLEpoint with malloc'd coordinates
  2348. see qh_setfeasible
  2349. */
  2350. int qh_readfeasible (int dim, char *remainder) {
  2351. boolT isfirst= True;
  2352. int linecount= 0, tokcount= 0;
  2353. char *s, *t, firstline[qh_MAXfirst+1];
  2354. coordT *coords, value;
  2355. if (!qh HALFspace) {
  2356. fprintf (qh ferr, "qhull input error: feasible point (dim 1 coords) is only valid for halfspace intersection\n");
  2357. qh_errexit (qh_ERRinput, NULL, NULL);
  2358. }
  2359. if (qh feasible_string)
  2360. fprintf (qh ferr, "qhull input warning: feasible point (dim 1 coords) overrides 'Hn,n,n' feasible point for halfspace intersection\n");
  2361. if (!(qh feasible_point= (coordT*)malloc (dim* sizeof(coordT)))) {
  2362. fprintf(qh ferr, "qhull error: insufficient memory for feasible point\n");
  2363. qh_errexit(qh_ERRmem, NULL, NULL);
  2364. }
  2365. coords= qh feasible_point;
  2366. while ((s= (isfirst ? remainder : fgets(firstline, qh_MAXfirst, qh fin)))) {
  2367. if (isfirst)
  2368. isfirst= False;
  2369. else
  2370. linecount++;
  2371. while (*s) {
  2372. while (isspace(*s))
  2373. s++;
  2374. value= qh_strtod (s, &t);
  2375. if (s == t)
  2376. break;
  2377. s= t;
  2378. *(coords++)= value;
  2379. if (++tokcount == dim) {
  2380. while (isspace (*s))
  2381. s++;
  2382. qh_strtod (s, &t);
  2383. if (s != t) {
  2384. fprintf (qh ferr, "qhull input error: coordinates for feasible point do not finish out the line: %s\n",
  2385. s);
  2386. qh_errexit (qh_ERRinput, NULL, NULL);
  2387. }
  2388. return linecount;
  2389. }
  2390. }
  2391. }
  2392. fprintf (qh ferr, "qhull input error: only %d coordinates. Could not read %d-d feasible point.\n",
  2393. tokcount, dim);
  2394. qh_errexit (qh_ERRinput, NULL, NULL);
  2395. return 0;
  2396. } /* readfeasible */
  2397. /*-------------------------------------------
  2398. -readpoints- read points from qh fin into all_points
  2399. qh fin is lines of coordinates, one per vertex, first line number of points
  2400. if 'rbox D4' gives message
  2401. if qh ATinfinity, adds point-at-infinity for Delaunay triangulations
  2402. returns:
  2403. number of points, array of point coordinates, dimension, ismalloc True
  2404. if DELAUNAY & !PROJECTinput, projects points to paraboloid
  2405. and clears PROJECTdelaunay
  2406. if HALFspace, reads optional feasible point, reads half-spaces,
  2407. converts to dual.
  2408. for feasible point in "cdd format" in 3-d:
  2409. 3 1
  2410. coordinates
  2411. comments
  2412. begin
  2413. n 4 real/integer
  2414. ...
  2415. end
  2416. notes:
  2417. dimension will change in qh_initqhull_globals if PROJECTinput
  2418. uses malloc since qh_mem not initialized
  2419. FIXUP: this routine needs rewriting
  2420. */
  2421. coordT *qh_readpoints(int *numpoints, int *dimension, boolT *ismalloc) {
  2422. coordT *points, *coords, *infinity= NULL;
  2423. realT paraboloid, maxboloid= -REALmax, value;
  2424. realT *coordp= NULL, *offsetp= NULL, *normalp= NULL;
  2425. char *s, *t, firstline[qh_MAXfirst+1];
  2426. int diminput=0, numinput=0, dimfeasible= 0, newnum, k, tempi;
  2427. int firsttext=0, firstshort=0, firstlong=0, firstpoint=0;
  2428. int tokcount= 0, linecount=0, maxcount, coordcount=0;
  2429. boolT islong, isfirst= True, wasbegin= False;
  2430. boolT isdelaunay= qh DELAUNAY && !qh PROJECTinput;
  2431. if (qh CDDinput) {
  2432. while ((s= fgets(firstline, qh_MAXfirst, qh fin))) {
  2433. linecount++;
  2434. if (qh HALFspace && linecount == 1 && isdigit(*s)) {
  2435. dimfeasible= qh_strtol (s, &s);
  2436. while (isspace(*s))
  2437. s++;
  2438. if (qh_strtol (s, &s) == 1)
  2439. linecount += qh_readfeasible (dimfeasible, s);
  2440. else
  2441. dimfeasible= 0;
  2442. }else if (!memcmp (firstline, "begin", 5) || !memcmp (firstline, "BEGIN", 5))
  2443. break;
  2444. else if (!*qh rbox_command)
  2445. strncat(qh rbox_command, s, sizeof (qh rbox_command)-1);
  2446. }
  2447. if (!s) {
  2448. fprintf (qh ferr, "qhull input error: missing \"begin\" for cdd-formated input\n");
  2449. qh_errexit (qh_ERRinput, NULL, NULL);
  2450. }
  2451. }
  2452. while(!numinput && (s= fgets(firstline, qh_MAXfirst, qh fin))) {
  2453. linecount++;
  2454. if (!memcmp (s, "begin", 5) || !memcmp (s, "BEGIN", 5))
  2455. wasbegin= True;
  2456. while (*s) {
  2457. while (isspace(*s))
  2458. s++;
  2459. if (!*s)
  2460. break;
  2461. if (!isdigit(*s)) {
  2462. if (!*qh rbox_command) {
  2463. strncat(qh rbox_command, s, sizeof (qh rbox_command)-1);
  2464. firsttext= linecount;
  2465. }
  2466. break;
  2467. }
  2468. if (!diminput)
  2469. diminput= qh_strtol (s, &s);
  2470. else {
  2471. numinput= qh_strtol (s, &s);
  2472. if (numinput == 1 && diminput >= 2 && qh HALFspace && !qh CDDinput) {
  2473. linecount += qh_readfeasible (diminput, s); /* checks if ok */
  2474. dimfeasible= diminput;
  2475. diminput= numinput= 0;
  2476. }else
  2477. break;
  2478. }
  2479. }
  2480. }
  2481. if (!s) {
  2482. fprintf(qh ferr, "qhull input error: short input file. Did not find dimension and number of points\n");
  2483. qh_errexit(qh_ERRinput, NULL, NULL);
  2484. }
  2485. if (diminput > numinput) {
  2486. tempi= diminput; /* exchange dim and n, e.g., for cdd input format */
  2487. diminput= numinput;
  2488. numinput= tempi;
  2489. }
  2490. if (diminput < 2) {
  2491. fprintf(qh ferr,"qhull input error: dimension %d (first number) should be at least 2\n",
  2492. diminput);
  2493. qh_errexit(qh_ERRinput, NULL, NULL);
  2494. }
  2495. if (isdelaunay) {
  2496. qh PROJECTdelaunay= False;
  2497. if (qh CDDinput)
  2498. *dimension= diminput;
  2499. else
  2500. *dimension= diminput+1;
  2501. *numpoints= numinput;
  2502. if (qh ATinfinity)
  2503. (*numpoints)++;
  2504. }else if (qh HALFspace) {
  2505. *dimension= diminput - 1;
  2506. *numpoints= numinput;
  2507. if (diminput < 3) {
  2508. fprintf(qh ferr,"qhull input error: dimension %d (first number, includes offset) should be at least 3 for halfspaces\n",
  2509. diminput);
  2510. qh_errexit(qh_ERRinput, NULL, NULL);
  2511. }
  2512. if (dimfeasible) {
  2513. if (dimfeasible != *dimension) {
  2514. fprintf(qh ferr,"qhull input error: dimension %d of feasible point is not one less than dimension %d for halfspaces\n",
  2515. dimfeasible, diminput);
  2516. qh_errexit(qh_ERRinput, NULL, NULL);
  2517. }
  2518. }else
  2519. qh_setfeasible (*dimension);
  2520. }else {
  2521. if (qh CDDinput)
  2522. *dimension= diminput-1;
  2523. else
  2524. *dimension= diminput;
  2525. *numpoints= numinput;
  2526. }
  2527. qh normal_size= *dimension * sizeof(coordT); /* for tracing with qh_printpoint */
  2528. if (qh HALFspace) {
  2529. qh half_space= coordp= (coordT*) malloc (qh normal_size + sizeof(coordT));
  2530. if (qh CDDinput) {
  2531. offsetp= qh half_space;
  2532. normalp= offsetp + 1;
  2533. }else {
  2534. normalp= qh half_space;
  2535. offsetp= normalp + *dimension;
  2536. }
  2537. }
  2538. qh maxline= diminput * (qh_REALdigits + 5);
  2539. maximize_(qh maxline, 500);
  2540. qh line= (char*)malloc ((qh maxline+1) * sizeof (char));
  2541. *ismalloc= True; /* use malloc since memory not setup */
  2542. coords= points= qh temp_malloc=
  2543. (coordT*)malloc((*numpoints)*(*dimension)*sizeof(coordT));
  2544. if (!coords || !qh line || (qh HALFspace && !qh half_space)) {
  2545. fprintf(qh ferr, "qhull error: insufficient memory to read %d points\n",
  2546. numinput);
  2547. qh_errexit(qh_ERRmem, NULL, NULL);
  2548. }
  2549. if (isdelaunay && qh ATinfinity) {
  2550. infinity= points + numinput * (*dimension);
  2551. for (k= (*dimension) - 1; k--; )
  2552. infinity[k]= 0.0;
  2553. }
  2554. maxcount= numinput * diminput;
  2555. paraboloid= 0.0;
  2556. while ((s= (isfirst ? s : fgets(qh line, qh maxline, qh fin)))) {
  2557. if (!isfirst) {
  2558. linecount++;
  2559. if (*s == 'e' || *s == 'E') {
  2560. if (!memcmp (s, "end", 3) || !memcmp (s, "END", 3)) {
  2561. if (qh CDDinput )
  2562. break;
  2563. else if (wasbegin)
  2564. fprintf (qh ferr, "qhull input warning: the input appears to be in cdd format. If so, use 'Fd'\n");
  2565. }
  2566. }
  2567. }
  2568. islong= False;
  2569. while (*s) {
  2570. while (isspace(*s))
  2571. s++;
  2572. value= qh_strtod (s, &t);
  2573. if (s == t) {
  2574. if (!*qh rbox_command)
  2575. strncat(qh rbox_command, s, sizeof (qh rbox_command)-1);
  2576. if (*s && !firsttext)
  2577. firsttext= linecount;
  2578. if (!islong && !firstshort && coordcount)
  2579. firstshort= linecount;
  2580. break;
  2581. }
  2582. if (!firstpoint)
  2583. firstpoint= linecount;
  2584. s= t;
  2585. if (++tokcount > maxcount)
  2586. continue;
  2587. if (qh HALFspace) {
  2588. if (qh CDDinput && !coordcount)
  2589. *(coordp++)= -value; /* offset */
  2590. else
  2591. *(coordp++)= value;
  2592. }else {
  2593. *(coords++)= value;
  2594. if (qh CDDinput && !coordcount) {
  2595. if (value != 1.0) {
  2596. fprintf (qh ferr, "qhull input error: for cdd format, point at line %d does not start with '1'\n",
  2597. linecount);
  2598. qh_errexit (qh_ERRinput, NULL, NULL);
  2599. }
  2600. coords--;
  2601. }else if (isdelaunay) {
  2602. paraboloid += value * value;
  2603. if (qh ATinfinity) {
  2604. if (qh CDDinput)
  2605. infinity[coordcount-1] += value;
  2606. else
  2607. infinity[coordcount] += value;
  2608. }
  2609. }
  2610. }
  2611. if (++coordcount == diminput) {
  2612. coordcount= 0;
  2613. if (isdelaunay) {
  2614. *(coords++)= paraboloid;
  2615. maximize_(maxboloid, paraboloid);
  2616. paraboloid= 0.0;
  2617. }else if (qh HALFspace) {
  2618. if (!qh_sethalfspace (*dimension, coords, &coords, normalp, offsetp, qh feasible_point)) {
  2619. fprintf (qh ferr, "The halfspace was on line %d\n", linecount);
  2620. if (wasbegin)
  2621. fprintf (qh ferr, "The input appears to be in cdd format. If so, you should use option 'Fd'\n");
  2622. qh_errexit (qh_ERRinput, NULL, NULL);
  2623. }
  2624. coordp= qh half_space;
  2625. }
  2626. while (isspace(*s))
  2627. s++;
  2628. if (*s) {
  2629. islong= True;
  2630. if (!firstlong)
  2631. firstlong= linecount;
  2632. }
  2633. }
  2634. }
  2635. if (!islong && !firstshort && coordcount)
  2636. firstshort= linecount;
  2637. if (!isfirst && s - qh line >= qh maxline) {
  2638. fprintf(qh ferr, "qhull input error: line %d contained more than %d characters\n",
  2639. linecount, (int) (s - qh line));
  2640. qh_errexit(qh_ERRinput, NULL, NULL);
  2641. }
  2642. isfirst= False;
  2643. }
  2644. if (tokcount != maxcount) {
  2645. newnum= fmin_(numinput, tokcount/diminput);
  2646. fprintf(qh ferr,"\
  2647. qhull warning: instead of %d %d-dimensional points, input contains\n\
  2648. %d points and %d extra coordinates. Line %d is the first point,\n\
  2649. line %d is the first (if any) comment, line %d is the first short line,\n\
  2650. and line %d is the first long line. Continue with %d points.\n",
  2651. numinput, diminput, tokcount/diminput, tokcount % diminput, firstpoint,
  2652. firsttext, firstshort, firstlong, newnum);
  2653. numinput= newnum;
  2654. if (isdelaunay && qh ATinfinity) {
  2655. for (k= tokcount % diminput; k--; )
  2656. infinity[k] -= *(--coords);
  2657. *numpoints= newnum+1;
  2658. }else {
  2659. coords -= tokcount % diminput;
  2660. *numpoints= newnum;
  2661. }
  2662. }
  2663. if (isdelaunay && qh ATinfinity) {
  2664. for (k= (*dimension) -1; k--; )
  2665. infinity[k] /= numinput;
  2666. if (coords == infinity)
  2667. coords += (*dimension) -1;
  2668. else {
  2669. for (k= 0; k < (*dimension) -1; k++)
  2670. *(coords++)= infinity[k];
  2671. }
  2672. *(coords++)= maxboloid * 1.1;
  2673. }
  2674. if (qh rbox_command[0]) {
  2675. qh rbox_command[strlen(qh rbox_command)-1]= '\0';
  2676. if (!strcmp (qh rbox_command, "./rbox D4"))
  2677. fprintf (qh ferr, "\n\
  2678. This is the qhull test case. If any errors or core dumps occur,\n\
  2679. recompile qhull with 'make new'. If errors still occur, there is\n\
  2680. an incompatibility. You should try a different compiler. You can also\n\
  2681. change the choices in user.h. If you discover the source of the problem,\n\
  2682. please send mail to qhull_bug@geom.umn.edu.\n\
  2683. \n\
  2684. Type 'qhull' for a short list of options.\n");
  2685. }
  2686. free (qh line);
  2687. qh line= NULL;
  2688. if (qh half_space) {
  2689. free (qh half_space);
  2690. qh half_space= NULL;
  2691. }
  2692. qh temp_malloc= NULL;
  2693. trace1((qh ferr,"qh_readpoints: read in %d %d-dimensional points\n",
  2694. numinput, diminput));
  2695. return(points);
  2696. } /* readpoints */
  2697. /*-------------------------------------------
  2698. -setfeasible- set feasible point from qh feasible_string
  2699. returns:
  2700. sets qh FEASIBLEpoint with malloc'd coordinates
  2701. notes:
  2702. "n,n,n" already checked by qh_initflags
  2703. see qh_readfeasible
  2704. */
  2705. void qh_setfeasible (int dim) {
  2706. int tokcount= 0;
  2707. char *s;
  2708. coordT *coords, value;
  2709. if (!(s= qh feasible_string)) {
  2710. fprintf(qh ferr, "\
  2711. qhull input error: halfspace intersection needs a feasible point.\n\
  2712. Either prepend the input with 1 point or use 'Hn,n,n'. See manual.\n");
  2713. qh_errexit (qh_ERRinput, NULL, NULL);
  2714. }
  2715. if (!(qh feasible_point= (pointT*)malloc (dim* sizeof(coordT)))) {
  2716. fprintf(qh ferr, "qhull error: insufficient memory for 'Hn,n,n'\n");
  2717. qh_errexit(qh_ERRmem, NULL, NULL);
  2718. }
  2719. coords= qh feasible_point;
  2720. while (*s) {
  2721. value= qh_strtod (s, &s);
  2722. if (++tokcount > dim) {
  2723. fprintf (qh ferr, "qhull input warning: more coordinates for 'H%s' than dimension %d\n",
  2724. qh feasible_string, dim);
  2725. break;
  2726. }
  2727. *(coords++)= value;
  2728. if (*s)
  2729. s++;
  2730. }
  2731. while (++tokcount <= dim)
  2732. *(coords++)= 0.0;
  2733. } /* setfeasible */
  2734. /*-------------------------------------------
  2735. -skipfacet- returns 'True' if this facet is not to be printed
  2736. (based on the user provided slice thresholds and 'good' specifications)
  2737. */
  2738. boolT qh_skipfacet(facetT *facet) {
  2739. facetT *neighbor, **neighborp;
  2740. if (qh PRINTneighbors) {
  2741. if (facet->good)
  2742. return !qh PRINTgood;
  2743. FOREACHneighbor_(facet) {
  2744. if (neighbor->good)
  2745. return False;
  2746. }
  2747. return True;
  2748. }else if (qh PRINTgood)
  2749. return !facet->good;
  2750. else if (!facet->normal)
  2751. return True;
  2752. return (!qh_inthresholds (facet->normal, NULL));
  2753. } /* skipfacet */