Skip to content

AFNI/NIfTI Server

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

Doxygen Source Code Documentation


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

merge.c

Go to the documentation of this file.
00001 /*<html><pre>  -<a                             href="qh-merge.htm#TOC"
00002   >-------------------------------</a><a name="TOP">-</a>
00003 
00004    merge.c 
00005    merges non-convex facets
00006 
00007    see qh-merge.htm and merge.h
00008 
00009    other modules call qh_premerge() and qh_postmerge()
00010 
00011    the user may call qh_postmerge() to perform additional merges.
00012 
00013    To remove deleted facets and vertices (qhull() in qhull.c):
00014      qh_partitionvisible (!qh_ALL, &numoutside);  // visible_list, newfacet_list
00015      qh_deletevisible ();         // qh.visible_list
00016      qh_resetlists (False);       // qh.visible_list newvertex_list newfacet_list 
00017 
00018    assumes qh.CENTERtype= centrum
00019 
00020    merges occur in qh_mergefacet and in qh_mergecycle
00021    vertex->neighbors not set until the first merge occurs
00022 
00023    copyright (c) 1993-2001 The Geometry Center        
00024 */
00025 
00026 #include "qhull_a.h"
00027 
00028 #ifndef qh_NOmerge
00029 
00030 /*=========== internal prototypes =========*/
00031 
00032 static int qh_compareangle(const void *p1, const void *p2);
00033 static int qh_comparemerge(const void *p1, const void *p2);
00034 static int qh_comparevisit (const void *p1, const void *p2);
00035 
00036                                                                                                                                                                                                                                                 
00037 /*===== functions (alphabetical after premerge and postmerge) ======*/
00038 
00039 /*-<a                             href="qh-merge.htm#TOC"
00040   >-------------------------------</a><a name="premerge">-</a>
00041   
00042   qh_premerge( apex, maxcentrum )
00043     pre-merge nonconvex facets in qh.newfacet_list for apex
00044     maxcentrum defines coplanar and concave (qh_test_appendmerge)
00045 
00046   returns:
00047     deleted facets added to qh.visible_list with facet->visible set
00048 
00049   notes:
00050     uses globals, qh.MERGEexact, qh.PREmerge
00051 
00052   design:
00053     mark duplicate ridges in qh.newfacet_list
00054     merge facet cycles in qh.newfacet_list
00055     merge duplicate ridges and concave facets in qh.newfacet_list
00056     check merged facet cycles for degenerate and redundant facets
00057     merge degenerate and redundant facets
00058     collect coplanar and concave facets
00059     merge concave, coplanar, degenerate, and redundant facets
00060 */
00061 void qh_premerge (vertexT *apex, realT maxcentrum, realT maxangle) {
00062   boolT othermerge= False;
00063   facetT *newfacet;
00064   
00065   if (qh ZEROcentrum && qh_checkzero(!qh_ALL))
00066     return;    
00067   trace2((qh ferr, "qh_premerge: premerge centrum %2.2g angle %2.2g for apex v%d facetlist f%d\n",
00068             maxcentrum, maxangle, apex->id, getid_(qh newfacet_list)));
00069   if (qh IStracing >= 4 && qh num_facets < 50)
00070     qh_printlists();
00071   qh centrum_radius= maxcentrum;
00072   qh cos_max= maxangle;
00073   qh degen_mergeset= qh_settemp (qh TEMPsize);
00074   qh facet_mergeset= qh_settemp (qh TEMPsize);
00075   if (qh hull_dim >=3) { 
00076     qh_mark_dupridges (qh newfacet_list); /* facet_mergeset */
00077     qh_mergecycle_all (qh newfacet_list, &othermerge);
00078     qh_forcedmerges (&othermerge /* qh facet_mergeset */); 
00079     FORALLnew_facets {  /* test samecycle merges */
00080       if (!newfacet->simplicial && !newfacet->mergeridge)
00081         qh_degen_redundant_neighbors (newfacet, NULL);
00082     }
00083     if (qh_merge_degenredundant())
00084       othermerge= True;
00085   }else /* qh hull_dim == 2 */
00086     qh_mergecycle_all (qh newfacet_list, &othermerge);
00087   qh_flippedmerges (qh newfacet_list, &othermerge);
00088   if (!qh MERGEexact || zzval_(Ztotmerge)) {
00089     zinc_(Zpremergetot);
00090     qh POSTmerging= False;
00091     qh_getmergeset_initial (qh newfacet_list);
00092     qh_all_merges (othermerge, False);
00093   }
00094   qh_settempfree(&qh facet_mergeset);
00095   qh_settempfree(&qh degen_mergeset);
00096 } /* premerge */
00097   
00098 /*-<a                             href="qh-merge.htm#TOC"
00099   >-------------------------------</a><a name="postmerge">-</a>
00100   
00101   qh_postmerge( reason, maxcentrum, maxangle, vneighbors )
00102     post-merge nonconvex facets as defined by maxcentrum and maxangle
00103     'reason' is for reporting progress
00104     if vneighbors, 
00105       calls qh_test_vneighbors at end of qh_all_merge 
00106     if firstmerge, 
00107       calls qh_reducevertices before qh_getmergeset
00108 
00109   returns:
00110     if first call (qh.visible_list != qh.facet_list), 
00111       builds qh.facet_newlist, qh.newvertex_list
00112     deleted facets added to qh.visible_list with facet->visible
00113     qh.visible_list == qh.facet_list
00114 
00115   notes:
00116 
00117 
00118   design:
00119     if first call
00120       set qh.visible_list and qh.newfacet_list to qh.facet_list
00121       add all facets to qh.newfacet_list
00122       mark non-simplicial facets, facet->newmerge
00123       set qh.newvertext_list to qh.vertex_list
00124       add all vertices to qh.newvertex_list
00125       if a pre-merge occured
00126         set vertex->delridge {will retest the ridge}
00127         if qh.MERGEexact
00128           call qh_reducevertices()
00129       if no pre-merging 
00130         merge flipped facets
00131     determine non-convex facets
00132     merge all non-convex facets
00133 */
00134 void qh_postmerge (char *reason, realT maxcentrum, realT maxangle, 
00135                       boolT vneighbors) {
00136   facetT *newfacet;
00137   boolT othermerges= False;
00138   vertexT *vertex;
00139 
00140   if (qh REPORTfreq || qh IStracing) {
00141     qh_buildtracing (NULL, NULL);
00142     qh_printsummary (qh ferr);
00143     if (qh PRINTstatistics) 
00144       qh_printallstatistics (qh ferr, "reason");
00145     fprintf (qh ferr, "\n%s with 'C%.2g' and 'A%.2g'\n", 
00146         reason, maxcentrum, maxangle);
00147   }
00148   trace2((qh ferr, "qh_postmerge: postmerge.  test vneighbors? %d\n",
00149             vneighbors));
00150   qh centrum_radius= maxcentrum;
00151   qh cos_max= maxangle;
00152   qh POSTmerging= True;
00153   qh degen_mergeset= qh_settemp (qh TEMPsize);
00154   qh facet_mergeset= qh_settemp (qh TEMPsize);
00155   if (qh visible_list != qh facet_list) {  /* first call */
00156     qh NEWfacets= True;
00157     qh visible_list= qh newfacet_list= qh facet_list;
00158     FORALLnew_facets {
00159       newfacet->newfacet= True;
00160        if (!newfacet->simplicial)
00161         newfacet->newmerge= True;
00162      zinc_(Zpostfacets);
00163     }
00164     qh newvertex_list= qh vertex_list;
00165     FORALLvertices
00166       vertex->newlist= True;
00167     if (qh VERTEXneighbors) { /* a merge has occurred */
00168       FORALLvertices
00169         vertex->delridge= True; /* test for redundant, needed? */
00170       if (qh MERGEexact) {
00171         if (qh hull_dim <= qh_DIMreduceBuild)
00172           qh_reducevertices(); /* was skipped during pre-merging */
00173       }
00174     }
00175     if (!qh PREmerge && !qh MERGEexact) 
00176       qh_flippedmerges (qh newfacet_list, &othermerges);
00177   }
00178   qh_getmergeset_initial (qh newfacet_list);
00179   qh_all_merges (False, vneighbors);
00180   qh_settempfree(&qh facet_mergeset);
00181   qh_settempfree(&qh degen_mergeset);
00182 } /* post_merge */
00183 
00184 /*-<a                             href="qh-merge.htm#TOC"
00185   >-------------------------------</a><a name="all_merges">-</a>
00186   
00187   qh_all_merges( othermerge, vneighbors )
00188     merge all non-convex facets
00189     
00190     set othermerge if already merged facets (for qh_reducevertices)
00191     if vneighbors
00192       tests vertex neighbors for convexity at end
00193     qh.facet_mergeset lists the non-convex ridges in qh_newfacet_list
00194     qh.degen_mergeset is defined
00195     if qh.MERGEexact && !qh.POSTmerging, 
00196       does not merge coplanar facets
00197 
00198   returns:
00199     deleted facets added to qh.visible_list with facet->visible
00200     deleted vertices added qh.delvertex_list with vertex->delvertex
00201   
00202   notes:
00203     unless !qh.MERGEindependent, 
00204       merges facets in independent sets
00205     uses qh.newfacet_list as argument since merges call qh_removefacet()
00206 
00207   design:
00208     while merges occur
00209       for each merge in qh.facet_mergeset
00210         unless one of the facets was already merged in this pass
00211           merge the facets
00212         test merged facets for additional merges
00213         add merges to qh.facet_mergeset
00214       if vertices record neighboring facets
00215         rename redundant vertices
00216           update qh.facet_mergeset
00217     if vneighbors ??
00218       tests vertex neighbors for convexity at end
00219 */
00220 void qh_all_merges (boolT othermerge, boolT vneighbors) {
00221   facetT *facet1, *facet2;
00222   mergeT *merge;
00223   boolT wasmerge= True, isreduce;
00224   void **freelistp;  /* used !qh_NOmem */
00225   vertexT *vertex;
00226   mergeType mergetype;
00227   int numcoplanar=0, numconcave=0, numdegenredun= 0, numnewmerges= 0;
00228   
00229   trace2((qh ferr, "qh_all_merges: starting to merge facets beginning from f%d\n",
00230             getid_(qh newfacet_list)));
00231   while (True) {
00232     wasmerge= False;
00233     while (qh_setsize (qh facet_mergeset)) {
00234       while ((merge= (mergeT*)qh_setdellast(qh facet_mergeset))) {
00235         facet1= merge->facet1;
00236         facet2= merge->facet2;
00237         mergetype= merge->type;
00238         qh_memfree_(merge, sizeof(mergeT), freelistp);
00239         if (facet1->visible || facet2->visible) /*deleted facet*/
00240           continue;  
00241         if ((facet1->newfacet && !facet1->tested)
00242                 || (facet2->newfacet && !facet2->tested)) {
00243           if (qh MERGEindependent && mergetype <= MRGanglecoplanar)
00244             continue;      /* perform independent sets of merges */
00245         }
00246         qh_merge_nonconvex (facet1, facet2, mergetype);
00247         numdegenredun += qh_merge_degenredundant();
00248         numnewmerges++;
00249         wasmerge= True;
00250         if (mergetype == MRGconcave)
00251           numconcave++;
00252         else /* MRGcoplanar or MRGanglecoplanar */
00253           numcoplanar++;
00254       } /* while setdellast */
00255       if (qh POSTmerging && qh hull_dim <= qh_DIMreduceBuild 
00256       && numnewmerges > qh_MAXnewmerges) {
00257         numnewmerges= 0;
00258         qh_reducevertices();  /* otherwise large post merges too slow */
00259       }
00260       qh_getmergeset (qh newfacet_list); /* facet_mergeset */
00261     } /* while mergeset */
00262     if (qh VERTEXneighbors) {
00263       isreduce= False;
00264       if (qh hull_dim >=4 && qh POSTmerging) {
00265         FORALLvertices  
00266           vertex->delridge= True;
00267         isreduce= True;
00268       }
00269       if ((wasmerge || othermerge) && (!qh MERGEexact || qh POSTmerging) 
00270           && qh hull_dim <= qh_DIMreduceBuild) {
00271         othermerge= False;
00272         isreduce= True;
00273       }
00274       if (isreduce) {
00275         if (qh_reducevertices()) {
00276           qh_getmergeset (qh newfacet_list); /* facet_mergeset */
00277           continue;
00278         }
00279       }
00280     }
00281     if (vneighbors && qh_test_vneighbors(/* qh newfacet_list */)) 
00282       continue;
00283     break;
00284   } /* while (True) */
00285   if (qh CHECKfrequently && !qh MERGEexact) {
00286     qh old_randomdist= qh RANDOMdist;
00287     qh RANDOMdist= False;
00288     qh_checkconvex (qh newfacet_list, qh_ALGORITHMfault);
00289     /* qh_checkconnect (); [this is slow and it changes the facet order] */
00290     qh RANDOMdist= qh old_randomdist;
00291   }
00292   trace1((qh ferr, "qh_all_merges: merged %d coplanar facets %d concave facets and %d degen or redundant facets.\n",
00293     numcoplanar, numconcave, numdegenredun));
00294   if (qh IStracing >= 4 && qh num_facets < 50)
00295     qh_printlists ();
00296 } /* all_merges */
00297 
00298 
00299 /*-<a                             href="qh-merge.htm#TOC"
00300   >-------------------------------</a><a name="appendmergeset">-</a>
00301   
00302   qh_appendmergeset( facet, neighbor, mergetype, angle )
00303     appends an entry to qh.facet_mergeset or qh.degen_mergeset
00304 
00305     angle ignored if NULL or !qh.ANGLEmerge
00306 
00307   returns:
00308     merge appended to facet_mergeset or degen_mergeset
00309       sets ->degenerate or ->redundant if degen_mergeset
00310   
00311   see:
00312     qh_test_appendmerge()
00313 
00314   design:
00315     allocate merge entry
00316     if regular merge
00317       append to qh.facet_mergeset
00318     else if degenerate merge and qh.facet_mergeset is all degenerate
00319       append to qh.degen_mergeset 
00320     else if degenerate merge
00321       prepend to qh.degen_mergeset 
00322     else if redundant merge
00323       append to qh.degen_mergeset 
00324 */
00325 void qh_appendmergeset(facetT *facet, facetT *neighbor, mergeType mergetype, realT *angle) {
00326   mergeT *merge, *lastmerge;
00327   void **freelistp; /* used !qh_NOmem */
00328 
00329   if (facet->redundant)
00330     return;
00331   if (facet->degenerate && mergetype == MRGdegen)
00332     return;
00333   qh_memalloc_(sizeof(mergeT), freelistp, merge, mergeT);
00334   merge->facet1= facet;
00335   merge->facet2= neighbor;
00336   merge->type= mergetype;
00337   if (angle && qh ANGLEmerge)
00338     merge->angle= *angle;
00339   if (mergetype < MRGdegen)
00340     qh_setappend (&(qh facet_mergeset), merge);
00341   else if (mergetype == MRGdegen) {
00342     facet->degenerate= True;
00343     if (!(lastmerge= (mergeT*)qh_setlast (qh degen_mergeset)) 
00344     || lastmerge->type == MRGdegen)
00345       qh_setappend (&(qh degen_mergeset), merge);
00346     else
00347       qh_setaddnth (&(qh degen_mergeset), 0, merge);
00348   }else { /* mergetype == MRGredundant */
00349     facet->redundant= True;
00350     qh_setappend (&(qh degen_mergeset), merge);
00351   }
00352 } /* appendmergeset */
00353 
00354 
00355 /*-<a                             href="qh-merge.htm#TOC"
00356   >-------------------------------</a><a name="basevertices">-</a>
00357   
00358   qh_basevertices( samecycle )
00359     return temporary set of base vertices for samecycle
00360     samecycle is first facet in the cycle
00361     assumes apex is SETfirst_( samecycle->vertices )
00362 
00363   returns:
00364     vertices (settemp)
00365     all ->seen are cleared
00366 
00367   notes:
00368     uses qh_vertex_visit;
00369 
00370   design:
00371     for each facet in samecycle
00372       for each unseen vertex in facet->vertices
00373         append to result  
00374 */
00375 setT *qh_basevertices (facetT *samecycle) {
00376   facetT *same;
00377   vertexT *apex, *vertex, **vertexp;
00378   setT *vertices= qh_settemp (qh TEMPsize);
00379   
00380   apex= SETfirstt_(samecycle->vertices, vertexT);
00381   apex->visitid= ++qh vertex_visit;
00382   FORALLsame_cycle_(samecycle) {
00383     if (same->mergeridge)
00384       continue;
00385     FOREACHvertex_(same->vertices) {
00386       if (vertex->visitid != qh vertex_visit) {
00387         qh_setappend (&vertices, vertex);
00388         vertex->visitid= qh vertex_visit;
00389         vertex->seen= False;
00390       }
00391     }
00392   }
00393   trace4((qh ferr, "qh_basevertices: found %d vertices\n", 
00394          qh_setsize (vertices)));
00395   return vertices;
00396 } /* basevertices */
00397 
00398 /*-<a                             href="qh-merge.htm#TOC"
00399   >-------------------------------</a><a name="checkconnect">-</a>
00400   
00401   qh_checkconnect()
00402     check that new facets are connected
00403     new facets are on qh.newfacet_list
00404     
00405   notes:
00406     this is slow and it changes the order of the facets
00407     uses qh.visit_id
00408 
00409   design:
00410     move first new facet to end of qh.facet_list
00411     for all newly appended facets
00412       append unvisited neighbors to end of qh.facet_list
00413     for all new facets
00414       report error if unvisited
00415 */
00416 void qh_checkconnect (void /* qh newfacet_list */) {
00417   facetT *facet, *newfacet, *errfacet= NULL, *neighbor, **neighborp;
00418 
00419   facet= qh newfacet_list;
00420   qh_removefacet (facet);
00421   qh_appendfacet (facet);
00422   facet->visitid= ++qh visit_id;
00423   FORALLfacet_(facet) {
00424     FOREACHneighbor_(facet) {
00425       if (neighbor->visitid != qh visit_id) {
00426         qh_removefacet (neighbor);
00427         qh_appendfacet (neighbor);
00428         neighbor->visitid= qh visit_id;
00429       }
00430     }
00431   }
00432   FORALLnew_facets {
00433     if (newfacet->visitid == qh visit_id)
00434       break;
00435     fprintf(qh ferr, "qhull error: f%d is not attached to the new facets\n",
00436          newfacet->id);
00437     errfacet= newfacet;
00438   }
00439   if (errfacet)
00440     qh_errexit (qh_ERRqhull, errfacet, NULL);
00441 } /* checkconnect */
00442 
00443 /*-<a                             href="qh-merge.htm#TOC"
00444   >-------------------------------</a><a name="checkzero">-</a>
00445   
00446   qh_checkzero( testall )
00447     check that facets are clearly convex for qh.DISTround with qh.MERGEexact
00448 
00449     if testall, 
00450       test all facets for qh.MERGEexact post-merging
00451     else 
00452       test qh.newfacet_list
00453       
00454     if qh.MERGEexact, 
00455       allows coplanar ridges
00456       skips convexity test while qh.ZEROall_ok
00457 
00458   returns:
00459     True if all facets !flipped, !dupridge, normal
00460          if all horizon facets are simplicial
00461          if all vertices are clearly below neighbor
00462          if all opposite vertices of horizon are below 
00463     clears qh.ZEROall_ok if any problems or coplanar facets
00464 
00465   notes:
00466     uses qh.vertex_visit
00467     horizon facets may define multiple new facets
00468 
00469   design:
00470     for all facets in qh.newfacet_list or qh.facet_list
00471       check for flagged faults (flipped, etc.)
00472     for all facets in qh.newfacet_list or qh.facet_list
00473       for each neighbor of facet
00474         skip horizon facets for qh.newfacet_list
00475         test the opposite vertex
00476       if qh.newfacet_list
00477         test the other vertices in the facet's horizon facet
00478 */
00479 boolT qh_checkzero (boolT testall) {
00480   facetT *facet, *neighbor, **neighborp;
00481   facetT *horizon, *facetlist;
00482   int neighbor_i;
00483   vertexT *vertex, **vertexp;
00484   realT dist;
00485 
00486   if (testall) 
00487     facetlist= qh facet_list;
00488   else {
00489     facetlist= qh newfacet_list;
00490     FORALLfacet_(facetlist) {
00491       horizon= SETfirstt_(facet->neighbors, facetT);
00492       if (!horizon->simplicial)
00493         goto LABELproblem;
00494       if (facet->flipped || facet->dupridge || !facet->normal)
00495         goto LABELproblem;
00496     }
00497     if (qh MERGEexact && qh ZEROall_ok) {
00498       trace2((qh ferr, "qh_checkzero: skip convexity check until first pre-merge\n"));
00499       return True;
00500     }
00501   }
00502   FORALLfacet_(facetlist) {
00503     qh vertex_visit++;
00504     neighbor_i= 0;
00505     horizon= NULL;
00506     FOREACHneighbor_(facet) {
00507       if (!neighbor_i && !testall) {
00508         horizon= neighbor;
00509         neighbor_i++;
00510         continue; /* horizon facet tested in qh_findhorizon */
00511       }
00512       vertex= SETelemt_(facet->vertices, neighbor_i++, vertexT);
00513       vertex->visitid= qh vertex_visit;
00514       zzinc_(Zdistzero);
00515       qh_distplane (vertex->point, neighbor, &dist);
00516       if (dist >= -qh DISTround) {
00517         qh ZEROall_ok= False;
00518         if (!qh MERGEexact || testall || dist > qh DISTround)
00519           goto LABELnonconvex;
00520       }
00521     }
00522     if (!testall) {
00523       FOREACHvertex_(horizon->vertices) {
00524         if (vertex->visitid != qh vertex_visit) {
00525           zzinc_(Zdistzero);
00526           qh_distplane (vertex->point, facet, &dist);
00527           if (dist >= -qh DISTround) {
00528             qh ZEROall_ok= False;
00529             if (!qh MERGEexact || dist > qh DISTround)
00530               goto LABELnonconvex;
00531           }
00532           break;
00533         }
00534       }
00535     }
00536   }
00537   trace2((qh ferr, "qh_checkzero: testall %d, facets are %s\n", testall,
00538         (qh MERGEexact && !testall) ? 
00539            "not concave, flipped, or duplicate ridged" : "clearly convex"));
00540   return True;
00541 
00542  LABELproblem:
00543   qh ZEROall_ok= False;
00544   trace2((qh ferr, "qh_checkzero: facet f%d needs pre-merging\n",
00545        facet->id));
00546   return False;
00547 
00548  LABELnonconvex:
00549   trace2((qh ferr, "qh_checkzero: facet f%d and f%d are not clearly convex.  v%d dist %.2g\n",
00550          facet->id, neighbor->id, vertex->id, dist));
00551   return False;
00552 } /* checkzero */
00553 
00554 /*-<a                             href="qh-merge.htm#TOC"
00555   >-------------------------------</a><a name="compareangle">-</a>
00556   
00557   qh_compareangle( angle1, angle2 )
00558     used by qsort() to order merges by angle
00559 */
00560 static int qh_compareangle(const void *p1, const void *p2) {
00561   mergeT *a= *((mergeT **)p1), *b= *((mergeT **)p2);
00562  
00563   return ((a->angle > b->angle) ? 1 : -1);
00564 } /* compareangle */
00565 
00566 /*-<a                             href="qh-merge.htm#TOC"
00567   >-------------------------------</a><a name="comparemerge">-</a>
00568   
00569   qh_comparemerge( merge1, merge2 )
00570     used by qsort() to order merges
00571 */
00572 static int qh_comparemerge(const void *p1, const void *p2) {
00573   mergeT *a= *((mergeT **)p1), *b= *((mergeT **)p2);
00574  
00575   return (a->type - b->type);
00576 } /* comparemerge */
00577 
00578 /*-<a                             href="qh-merge.htm#TOC"
00579   >-------------------------------</a><a name="comparevisit">-</a>
00580   
00581   qh_comparevisit( vertex1, vertex2 )
00582     used by qsort() to order vertices by their visitid
00583 */
00584 static int qh_comparevisit (const void *p1, const void *p2) {
00585   vertexT *a= *((vertexT **)p1), *b= *((vertexT **)p2);
00586  
00587   return (a->visitid - b->visitid);
00588 } /* comparevisit */
00589 
00590 /*-<a                             href="qh-merge.htm#TOC"
00591   >-------------------------------</a><a name="copynonconvex">-</a>
00592   
00593   qh_copynonconvex( atridge )
00594     set non-convex flag on other ridges (if any) between same neighbors
00595 
00596   notes:
00597     may be faster if use smaller ridge set
00598 
00599   design:
00600     for each ridge of atridge's top facet
00601       if ridge shares the same neighbor
00602         set nonconvex flag
00603 */
00604 void qh_copynonconvex (ridgeT *atridge) {
00605   facetT *facet, *otherfacet;
00606   ridgeT *ridge, **ridgep;
00607 
00608   facet= atridge->top;
00609   otherfacet= atridge->bottom;
00610   FOREACHridge_(facet->ridges) {
00611     if (otherfacet == otherfacet_(ridge, facet) && ridge != atridge) {
00612       ridge->nonconvex= True;
00613       trace4((qh ferr, "qh_copynonconvex: moved nonconvex flag from r%d to r%d\n",
00614               atridge->id, ridge->id));
00615       break;
00616     }
00617   }
00618 } /* copynonconvex */
00619 
00620 /*-<a                             href="qh-merge.htm#TOC"
00621   >-------------------------------</a><a name="degen_redundant_facet">-</a>
00622   
00623   qh_degen_redundant_facet( facet )
00624     check facet for degen. or redundancy
00625 
00626   notes:
00627     bumps vertex_visit
00628     called if a facet was redundant but no longer is (qh_merge_degenredundant)
00629     qh_appendmergeset() only appends first reference to facet (i.e., redundant)
00630 
00631   see:
00632     qh_degen_redundant_neighbors()
00633 
00634   design:
00635     test for redundant neighbor
00636     test for degenerate facet
00637 */
00638 void qh_degen_redundant_facet (facetT *facet) {
00639   vertexT *vertex, **vertexp;
00640   facetT *neighbor, **neighborp;
00641 
00642   trace4((qh ferr, "qh_degen_redundant_facet: test facet f%d for degen/redundant\n",
00643           facet->id));
00644   FOREACHneighbor_(facet) {
00645     qh vertex_visit++;
00646     FOREACHvertex_(neighbor->vertices)
00647       vertex->visitid= qh vertex_visit;
00648     FOREACHvertex_(facet->vertices) {
00649       if (vertex->visitid != qh vertex_visit)
00650         break;
00651     }
00652     if (!vertex) {
00653       qh_appendmergeset (facet, neighbor, MRGredundant, NULL);
00654       trace2((qh ferr, "qh_degen_redundant_facet: f%d is contained in f%d.  merge\n", facet->id, neighbor->id)); 
00655       return;
00656     }
00657   }
00658   if (qh_setsize (facet->neighbors) < qh hull_dim) {
00659     qh_appendmergeset (facet, facet, MRGdegen, NULL);
00660     trace2((qh ferr, "qh_degen_redundant_neighbors: f%d is degenerate.\n", facet->id));
00661   }
00662 } /* degen_redundant_facet */
00663 
00664 
00665 /*-<a                             href="qh-merge.htm#TOC"
00666   >-------------------------------</a><a name="degen_redundant_neighbors">-</a>
00667   
00668   qh_degen_redundant_neighbors( facet, delfacet,  )
00669     append degenerate and redundant neighbors to facet_mergeset
00670     if delfacet, 
00671       only checks neighbors of both delfacet and facet
00672     also checks current facet for degeneracy
00673 
00674   notes:
00675     bumps vertex_visit
00676     called for each qh_mergefacet() and qh_mergecycle()
00677     merge and statistics occur in merge_nonconvex
00678     qh_appendmergeset() only appends first reference to facet (i.e., redundant)
00679       it appends redundant facets after degenerate ones
00680 
00681     a degenerate facet has fewer than hull_dim neighbors
00682     a redundant facet's vertices is a subset of its neighbor's vertices
00683     tests for redundant merges first (appendmergeset is nop for others)
00684     in a merge, only needs to test neighbors of merged facet
00685   
00686   see:
00687     qh_merge_degenredundant() and qh_degen_redundant_facet()
00688 
00689   design:
00690     test for degenerate facet
00691     test for redundant neighbor
00692     test for degenerate neighbor
00693 */
00694 void qh_degen_redundant_neighbors (facetT *facet, facetT *delfacet) {
00695   vertexT *vertex, **vertexp;
00696   facetT *neighbor, **neighborp;
00697   int size;
00698 
00699   trace4((qh ferr, "qh_degen_redundant_neighbors: test neighbors of f%d with delfacet f%d\n", 
00700           facet->id, getid_(delfacet)));
00701   if ((size= qh_setsize (facet->neighbors)) < qh hull_dim) {
00702     qh_appendmergeset (facet, facet, MRGdegen, NULL);
00703     trace2((qh ferr, "qh_degen_redundant_neighbors: f%d is degenerate with %d neighbors.\n", facet->id, size));
00704   }
00705   if (!delfacet)
00706     delfacet= facet;
00707   qh vertex_visit++;
00708   FOREACHvertex_(facet->vertices)
00709     vertex->visitid= qh vertex_visit;
00710   FOREACHneighbor_(delfacet) {
00711     /* uses early out instead of checking vertex count */
00712     if (neighbor == facet)
00713       continue;
00714     FOREACHvertex_(neighbor->vertices) {
00715       if (vertex->visitid != qh vertex_visit)
00716         break;
00717     }
00718     if (!vertex) {
00719       qh_appendmergeset (neighbor, facet, MRGredundant, NULL);
00720       trace2((qh ferr, "qh_degen_redundant_neighbors: f%d is contained in f%d.  merge\n", neighbor->id, facet->id)); 
00721     }
00722   }
00723   FOREACHneighbor_(delfacet) {   /* redundant merges occur first */
00724     if (neighbor == facet)
00725       continue;
00726     if ((size= qh_setsize (neighbor->neighbors)) < qh hull_dim) {
00727       qh_appendmergeset (neighbor, neighbor, MRGdegen, NULL);
00728       trace2((qh ferr, "qh_degen_redundant_neighbors: f%d is degenerate with %d neighbors.  Neighbor of f%d.\n", neighbor->id, size, facet->id)); 
00729     }
00730   }
00731 } /* degen_redundant_neighbors */
00732 
00733 
00734 /*-<a                             href="qh-merge.htm#TOC"
00735   >-------------------------------</a><a name="find_newvertex">-</a>
00736   
00737   qh_find_newvertex( oldvertex, vertices, ridges )
00738     locate new vertex for renaming old vertex
00739     vertices is a set of possible new vertices
00740       vertices sorted by number of deleted ridges
00741 
00742   returns:
00743     newvertex or NULL
00744       each ridge includes both vertex and oldvertex
00745     vertices sorted by number of deleted ridges
00746       
00747   notes:
00748     modifies vertex->visitid
00749     new vertex is in one of the ridges
00750     renaming will not cause a duplicate ridge
00751     renaming will minimize the number of deleted ridges
00752     newvertex may not be adjacent in the dual (though unlikely)
00753 
00754   design:
00755     for each vertex in vertices
00756       set vertex->visitid to number of references in ridges
00757     remove unvisited vertices 
00758     set qh.vertex_visit above all possible values
00759     sort vertices by number of references in ridges
00760     add each ridge to qh.hash_table
00761     for each vertex in vertices
00762       look for a vertex that would not cause a duplicate ridge after a rename
00763 */
00764 vertexT *qh_find_newvertex (vertexT *oldvertex, setT *vertices, setT *ridges) {
00765   vertexT *vertex, **vertexp;
00766   setT *newridges;
00767   ridgeT *ridge, **ridgep;
00768   int size, hashsize;
00769   int hash;
00770 
00771 #ifndef qh_NOtrace
00772   if (qh IStracing >= 4) {
00773     fprintf (qh ferr, "qh_find_newvertex: find new vertex for v%d from ",
00774              oldvertex->id);
00775     FOREACHvertex_(vertices) 
00776       fprintf (qh ferr, "v%d ", vertex->id);
00777     FOREACHridge_(ridges)
00778       fprintf (qh ferr, "r%d ", ridge->id);
00779     fprintf (qh ferr, "\n");
00780   }
00781 #endif
00782   FOREACHvertex_(vertices) 
00783     vertex->visitid= 0;
00784   FOREACHridge_(ridges) {
00785     FOREACHvertex_(ridge->vertices) 
00786       vertex->visitid++;
00787   }
00788   FOREACHvertex_(vertices) {
00789     if (!vertex->visitid) {
00790       qh_setdelnth (vertices, SETindex_(vertices,vertex));
00791       vertexp--; /* repeat since deleted this vertex */
00792     }
00793   }
00794   qh vertex_visit += qh_setsize (ridges);
00795   if (!qh_setsize (vertices)) {
00796     trace4((qh ferr, "qh_find_newvertex: vertices not in ridges for v%d\n",
00797             oldvertex->id));
00798     return NULL;
00799   }
00800   qsort (SETaddr_(vertices, vertexT), qh_setsize (vertices),
00801                 sizeof (vertexT *), qh_comparevisit);
00802   /* can now use qh vertex_visit */
00803   if (qh PRINTstatistics) {
00804     size= qh_setsize (vertices);
00805     zinc_(Zintersect);
00806     zadd_(Zintersecttot, size);
00807     zmax_(Zintersectmax, size);
00808   }
00809   hashsize= qh_newhashtable (qh_setsize (ridges));
00810   FOREACHridge_(ridges)
00811     qh_hashridge (qh hash_table, hashsize, ridge, oldvertex);
00812   FOREACHvertex_(vertices) {
00813     newridges= qh_vertexridges (vertex);
00814     FOREACHridge_(newridges) {
00815       if (qh_hashridge_find (qh hash_table, hashsize, ridge, vertex, oldvertex, &hash)) {
00816         zinc_(Zdupridge);
00817         break;
00818       }
00819     }
00820     qh_settempfree (&newridges);
00821     if (!ridge)
00822       break;  /* found a rename */
00823   }
00824   if (vertex) {
00825     /* counted in qh_renamevertex */
00826     trace2((qh ferr, "qh_find_newvertex: found v%d for old v%d from %d vertices and %d ridges.\n",
00827       vertex->id, oldvertex->id, qh_setsize (vertices), qh_setsize (ridges)));
00828   }else {
00829     zinc_(Zfindfail);
00830     trace0((qh ferr, "qh_find_newvertex: no vertex for renaming v%d (all duplicated ridges) during p%d\n",
00831       oldvertex->id, qh furthest_id));
00832   }
00833   qh_setfree (&qh hash_table);
00834   return vertex;
00835 } /* find_newvertex */
00836 
00837 /*-<a                             href="qh-merge.htm#TOC"
00838   >-------------------------------</a><a name="findbest_test">-</a>
00839   
00840   qh_findbest_test( testcentrum, facet, neighbor, bestfacet, dist, mindist, maxdist )
00841     test neighbor of facet for qh_findbestneighbor()
00842     if testcentrum,
00843       tests centrum (assumes it is defined)
00844     else 
00845       tests vertices
00846 
00847   returns:
00848     if a better facet (i.e., vertices/centrum of facet closer to neighbor)
00849       updates bestfacet, dist, mindist, and maxdist
00850 */
00851 void qh_findbest_test (boolT testcentrum, facetT *facet, facetT *neighbor,
00852       facetT **bestfacet, realT *distp, realT *mindistp, realT *maxdistp) {
00853   realT dist, mindist, maxdist;
00854 
00855   if (testcentrum) {
00856     zzinc_(Zbestdist);
00857     qh_distplane(facet->center, neighbor, &dist);
00858     dist *= qh hull_dim; /* estimate furthest vertex */
00859     if (dist < 0) {
00860       maxdist= 0;
00861       mindist= dist;
00862       dist= -dist;
00863     }else
00864       maxdist= dist;
00865   }else
00866     dist= qh_getdistance (facet, neighbor, &mindist, &maxdist);
00867   if (dist < *distp) {
00868     *bestfacet= neighbor;
00869     *mindistp= mindist;
00870     *maxdistp= maxdist;
00871     *distp= dist;
00872   }
00873 } /* findbest_test */
00874 
00875 /*-<a                             href="qh-merge.htm#TOC"
00876   >-------------------------------</a><a name="findbestneighbor">-</a>
00877   
00878   qh_findbestneighbor( facet, dist, mindist, maxdist )
00879     finds best neighbor (least dist) of a facet for merging
00880 
00881   returns:
00882     returns min and max distances and their max absolute value
00883   
00884   notes:
00885     avoids merging old into new
00886     assumes ridge->nonconvex only set on one ridge between a pair of facets
00887     could use an early out predicate but not worth it
00888 
00889   design:
00890     if a large facet
00891       will test centrum
00892     else
00893       will test vertices
00894     if a large facet
00895       test nonconvex neighbors for best merge
00896     else
00897       test all neighbors for the best merge
00898     if testing centrum
00899       get distance information
00900 */
00901 facetT *qh_findbestneighbor(facetT *facet, realT *distp, realT *mindistp, realT *maxdistp) {
00902   facetT *neighbor, **neighborp, *bestfacet= NULL;
00903   ridgeT *ridge, **ridgep;
00904   boolT nonconvex= True, testcentrum= False;
00905   int size= qh_setsize (facet->vertices);
00906 
00907   *distp= REALmax;
00908   if (size > qh_BESTcentrum2 * qh hull_dim + qh_BESTcentrum) {
00909     testcentrum= True;
00910     zinc_(Zbestcentrum);
00911     if (!facet->center)
00912        facet->center= qh_getcentrum (facet);
00913   }
00914   if (size > qh hull_dim + qh_BESTnonconvex) {
00915     FOREACHridge_(facet->ridges) {
00916       if (ridge->nonconvex) {
00917         neighbor= otherfacet_(ridge, facet);
00918         qh_findbest_test (testcentrum, facet, neighbor,
00919                           &bestfacet, distp, mindistp, maxdistp);
00920       }
00921     }
00922   }
00923   if (!bestfacet) {     
00924     nonconvex= False;
00925     FOREACHneighbor_(facet)
00926       qh_findbest_test (testcentrum, facet, neighbor,
00927                         &bestfacet, distp, mindistp, maxdistp);
00928   }
00929   if (!bestfacet) {
00930     fprintf (qh ferr, "qhull internal error (qh_findbestneighbor): no neighbors for f%d\n", facet->id);
00931     
00932     qh_errexit (qh_ERRqhull, facet, NULL);
00933   }
00934   if (testcentrum) 
00935     qh_getdistance (facet, bestfacet, mindistp, maxdistp);
00936   trace3((qh ferr, "qh_findbestneighbor: f%d is best neighbor for f%d testcentrum? %d nonconvex? %d dist %2.2g min %2.2g max %2.2g\n",
00937      bestfacet->id, facet->id, testcentrum, nonconvex, *distp, *mindistp, *maxdistp));
00938   return(bestfacet);
00939 } /* findbestneighbor */
00940 
00941 
00942 /*-<a                             href="qh-merge.htm#TOC"
00943   >-------------------------------</a><a name="flippedmerges">-</a>
00944   
00945   qh_flippedmerges( facetlist, wasmerge )
00946     merge flipped facets into best neighbor
00947     assumes qh.facet_mergeset at top of temporary stack
00948 
00949   returns:
00950     no flipped facets on facetlist
00951     sets wasmerge if merge occurred
00952     degen/redundant merges passed through
00953 
00954   notes:
00955     othermerges not needed since qh.facet_mergeset is empty before & after
00956       keep it in case of change
00957 
00958   design:
00959     append flipped facets to qh.facetmergeset
00960     for each flipped merge
00961       find best neighbor
00962       merge facet into neighbor
00963       merge degenerate and redundant facets
00964     remove flipped merges from qh.facet_mergeset
00965 */
00966 void qh_flippedmerges(facetT *facetlist, boolT *wasmerge) {
00967   facetT *facet, *neighbor, *facet1;
00968   realT dist, mindist, maxdist;
00969   mergeT *merge, **mergep;
00970   setT *othermerges;
00971   int nummerge=0;
00972 
00973   trace4((qh ferr, "qh_flippedmerges: begin\n"));
00974   FORALLfacet_(facetlist) {
00975     if (facet->flipped && !facet->visible) 
00976       qh_appendmergeset (facet, facet, MRGflip, NULL);
00977   }
00978   othermerges= qh_settemppop(); /* was facet_mergeset */
00979   qh facet_mergeset= qh_settemp (qh TEMPsize);
00980   qh_settemppush (othermerges);
00981   FOREACHmerge_(othermerges) {
00982     facet1= merge->facet1;
00983     if (merge->type != MRGflip || facet1->visible) 
00984       continue;
00985     if (qh TRACEmerge-1 == zzval_(Ztotmerge))
00986       qhmem.IStracing= qh IStracing= qh TRACElevel;
00987     neighbor= qh_findbestneighbor (facet1, &dist, &mindist, &maxdist);
00988     trace0((qh ferr, "qh_flippedmerges: merge flipped f%d into f%d dist %2.2g during p%d\n",
00989       facet1->id, neighbor->id, dist, qh furthest_id));
00990     qh_mergefacet (facet1, neighbor, &mindist, &maxdist, !qh_MERGEapex);
00991     nummerge++;
00992     if (qh PRINTstatistics) {
00993       zinc_(Zflipped);
00994       wadd_(Wflippedtot, dist);
00995       wmax_(Wflippedmax, dist);
00996     }
00997     qh_merge_degenredundant();
00998   }
00999   FOREACHmerge_(othermerges) {
01000     if (merge->facet1->visible || merge->facet2->visible)
01001       qh_memfree (merge, sizeof(mergeT));
01002     else
01003       qh_setappend (&qh facet_mergeset, merge);
01004   }
01005   qh_settempfree (&othermerges);
01006   if (nummerge)
01007     *wasmerge= True;
01008   trace1((qh ferr, "qh_flippedmerges: merged %d flipped facets into a good neighbor\n", nummerge));
01009 } /* flippedmerges */
01010 
01011 
01012 /*-<a                             href="qh-merge.htm#TOC"
01013   >-------------------------------</a><a name="forcedmerges">-</a>
01014   
01015   qh_forcedmerges( wasmerge )
01016     merge duplicated ridges
01017 
01018   returns:
01019     removes all duplicate ridges on facet_mergeset
01020     wasmerge set if merge
01021     qh.facet_mergeset may include non-forced merges (none for now)
01022     qh.degen_mergeset includes degen/redun merges
01023 
01024   notes: 
01025     duplicate ridges occur when the horizon is pinched,
01026         i.e. a subridge occurs in more than two horizon ridges.
01027      could rename vertices that pinch the horizon
01028     assumes qh_merge_degenredundant() has not be called
01029     othermerges isn't needed since facet_mergeset is empty afterwards
01030       keep it in case of change
01031 
01032   design:
01033     for each duplicate ridge
01034       find current facets by chasing f.replace links
01035       determine best direction for facet
01036       merge one facet into the other
01037       remove duplicate ridges from qh.facet_mergeset
01038 */
01039 void qh_forcedmerges(boolT *wasmerge) {
01040   facetT *facet1, *facet2;
01041   mergeT *merge, **mergep;
01042   realT dist1, dist2, mindist1, mindist2, maxdist1, maxdist2;
01043   setT *othermerges;
01044   int nummerge=0, numflip=0;
01045 
01046   if (qh TRACEmerge-1 == zzval_(Ztotmerge))
01047     qhmem.IStracing= qh IStracing= qh TRACElevel;
01048   trace4((qh ferr, "qh_forcedmerges: begin\n"));  
01049   othermerges= qh_settemppop(); /* was facet_mergeset */
01050   qh facet_mergeset= qh_settemp (qh TEMPsize);
01051   qh_settemppush (othermerges);
01052   FOREACHmerge_(othermerges) {
01053     if (merge->type != MRGridge) 
01054         continue;
01055     facet1= merge->facet1;
01056     facet2= merge->facet2;
01057     while (facet1->visible)      /* must exist, no qh_merge_degenredunant */
01058       facet1= facet1->f.replace; /* previously merged facet */
01059     while (facet2->visible)
01060       facet2= facet2->f.replace; /* previously merged facet */
01061     if (facet1 == facet2)
01062       continue;
01063     if (!qh_setin (facet2->neighbors, facet1)) {
01064       fprintf (qh ferr, "qhull internal error (qh_forcedmerges): f%d and f%d had a duplicate ridge but as f%d and f%d they are no longer neighbors\n",
01065                merge->facet1->id, merge->facet2->id, facet1->id, facet2->id);
01066       qh_errexit2 (qh_ERRqhull, facet1, facet2);
01067     }
01068     if (qh TRACEmerge-1 == zzval_(Ztotmerge))
01069       qhmem.IStracing= qh IStracing= qh TRACElevel;
01070     dist1= qh_getdistance (facet1, facet2, &mindist1, &maxdist1);
01071     dist2= qh_getdistance (facet2, facet1, &mindist2, &maxdist2);
01072     trace0((qh ferr, "qh_forcedmerges: duplicate ridge between f%d and f%d, dist %2.2g and reverse dist %2.2g during p%d\n",
01073             facet1->id, facet2->id, dist1, dist2, qh furthest_id));
01074     if (dist1 < dist2) 
01075       qh_mergefacet (facet1, facet2, &mindist1, &maxdist1, !qh_MERGEapex);
01076     else {
01077       qh_mergefacet (facet2, facet1, &mindist2, &maxdist2, !qh_MERGEapex);
01078       dist1= dist2;
01079       facet1= facet2;
01080     }
01081     if (facet1->flipped) {
01082       zinc_(Zmergeflipdup);
01083       numflip++;
01084     }else
01085       nummerge++;
01086     if (qh PRINTstatistics) {
01087       zinc_(Zduplicate);
01088       wadd_(Wduplicatetot, dist1);
01089       wmax_(Wduplicatemax, dist1);
01090     }
01091   }
01092   FOREACHmerge_(othermerges) {
01093     if (merge->type == MRGridge)
01094       qh_memfree (merge, sizeof(mergeT));
01095     else
01096       qh_setappend (&qh facet_mergeset, merge);
01097   }
01098   qh_settempfree (&othermerges);
01099   if (nummerge)
01100     *wasmerge= True;
01101   trace1((qh ferr, "qh_forcedmerges: merged %d facets and %d flipped facets across duplicated ridges\n", 
01102                 nummerge, numflip));
01103 } /* forcedmerges */
01104 
01105 
01106 /*-<a                             href="qh-merge.htm#TOC"
01107   >-------------------------------</a><a name="getmergeset">-</a>
01108   
01109   qh_getmergeset( facetlist )
01110     determines nonconvex facets on facetlist
01111     tests !tested ridges and nonconvex ridges of !tested facets
01112 
01113   returns:
01114     returns sorted qh.facet_mergeset of facet-neighbor pairs to be merged
01115     all ridges tested
01116   
01117   notes:
01118     assumes no nonconvex ridges with both facets tested
01119     uses facet->tested/ridge->tested to prevent duplicate tests
01120     can not limit tests to modified ridges since the centrum changed
01121     uses qh.visit_id
01122   
01123   see:
01124     qh_getmergeset_initial()
01125 
01126   design:
01127     for each facet on facetlist
01128       for each ridge of facet
01129         if untested ridge
01130           test ridge for convexity
01131           if non-convex
01132             append ridge to qh.facet_mergeset
01133     sort qh.facet_mergeset by angle  
01134 */
01135 void qh_getmergeset(facetT *facetlist) {
01136   facetT *facet, *neighbor, **neighborp;
01137   ridgeT *ridge, **ridgep;
01138   int nummerges;
01139   
01140   nummerges= qh_setsize (qh facet_mergeset);
01141   trace4((qh ferr, "qh_getmergeset: started.\n"));
01142   qh visit_id++;
01143   FORALLfacet_(facetlist) {
01144     if (facet->tested)
01145       continue;
01146     facet->visitid= qh visit_id;
01147     facet->tested= True;  /* must be non-simplicial due to merge */
01148     FOREACHneighbor_(facet)
01149       neighbor->seen= False;
01150     FOREACHridge_(facet->ridges) {
01151       if (ridge->tested && !ridge->nonconvex)
01152         continue;
01153       /* if tested & nonconvex, need to append merge */
01154       neighbor= otherfacet_(ridge, facet);
01155       if (neighbor->seen) {
01156         ridge->tested= True;
01157         ridge->nonconvex= False;
01158       }else if (neighbor->visitid != qh visit_id) {
01159         ridge->tested= True;
01160         ridge->nonconvex= False;
01161         neighbor->seen= True;      /* only one ridge is marked nonconvex */
01162         if (qh_test_appendmerge (facet, neighbor))
01163           ridge->nonconvex= True;
01164       }
01165     }
01166   }
01167   nummerges= qh_setsize (qh facet_mergeset);
01168   if (qh ANGLEmerge)
01169     qsort(SETaddr_(qh facet_mergeset, mergeT), nummerges,sizeof(mergeT *),qh_compareangle);
01170   else
01171     qsort(SETaddr_(qh facet_mergeset, mergeT), nummerges,sizeof(mergeT *),qh_comparemerge);
01172   if (qh POSTmerging) {
01173     zadd_(Zmergesettot2, nummerges);
01174   }else {
01175     zadd_(Zmergesettot, nummerges);
01176     zmax_(Zmergesetmax, nummerges);
01177   }
01178   trace2((qh ferr, "qh_getmergeset: %d merges found\n", nummerges));
01179 } /* getmergeset */
01180 
01181 
01182 /*-<a                             href="qh-merge.htm#TOC"
01183   >-------------------------------</a><a name="getmergeset_initial">-</a>
01184   
01185   qh_getmergeset_initial( facetlist )
01186     determine initial qh.facet_mergeset for facets
01187     tests all facet/neighbor pairs on facetlist
01188 
01189   returns:
01190     sorted qh.facet_mergeset with nonconvex ridges
01191     sets facet->tested, ridge->tested, and ridge->nonconvex
01192 
01193   notes:
01194     uses visit_id, assumes ridge->nonconvex is False
01195 
01196   see:
01197     qh_getmergeset()
01198 
01199   design:
01200     for each facet on facetlist
01201       for each untested neighbor of facet
01202         test facet and neighbor for convexity
01203         if non-convex
01204           append merge to qh.facet_mergeset
01205           mark one of the ridges as nonconvex
01206     sort qh.facet_mergeset by angle
01207 */
01208 void qh_getmergeset_initial (facetT *facetlist) {
01209   facetT *facet, *neighbor, **neighborp;
01210   ridgeT *ridge, **ridgep;
01211   int nummerges;
01212 
01213   qh visit_id++;
01214   FORALLfacet_(facetlist) {
01215     facet->visitid= qh visit_id;
01216     facet->tested= True;
01217     FOREACHneighbor_(facet) {
01218       if (neighbor->visitid != qh visit_id) {
01219         if (qh_test_appendmerge (facet, neighbor)) {
01220           FOREACHridge_(neighbor->ridges) {
01221             if (facet == otherfacet_(ridge, neighbor)) {
01222               ridge->nonconvex= True;
01223               break;    /* only one ridge is marked nonconvex */
01224             }
01225           }
01226         }
01227       }
01228     }
01229     FOREACHridge_(facet->ridges)
01230       ridge->tested= True;
01231   }
01232   nummerges= qh_setsize (qh facet_mergeset);
01233   if (qh ANGLEmerge)
01234     qsort(SETaddr_(qh facet_mergeset, mergeT), nummerges,sizeof(mergeT *),qh_compareangle);
01235   else
01236     qsort(SETaddr_(qh facet_mergeset, mergeT), nummerges,sizeof(mergeT *),qh_comparemerge);
01237   if (qh POSTmerging) {
01238     zadd_(Zmergeinittot2, nummerges);
01239   }else {
01240     zadd_(Zmergeinittot, nummerges);
01241     zmax_(Zmergeinitmax, nummerges);
01242   }
01243   trace2((qh ferr, "qh_getmergeset_initial: %d merges found\n", nummerges));
01244 } /* getmergeset_initial */
01245 
01246 
01247 /*-<a                             href="qh-merge.htm#TOC"
01248   >-------------------------------</a><a name="hashridge">-</a>
01249   
01250   qh_hashridge( hashtable, hashsize, ridge, oldvertex )
01251     add ridge to hashtable without oldvertex
01252 
01253   notes:
01254     assumes hashtable is large enough
01255 
01256   design:
01257     determine hash value for ridge without oldvertex
01258     find next empty slot for ridge
01259 */
01260 void qh_hashridge (setT *hashtable, int hashsize, ridgeT *ridge, vertexT *oldvertex) {
01261   int hash;
01262   ridgeT *ridgeA;
01263 
01264   hash= (int)qh_gethash (hashsize, ridge->vertices, qh hull_dim-1, 0, oldvertex);
01265   while (True) {
01266     if (!(ridgeA= SETelemt_(hashtable, hash, ridgeT))) {
01267       SETelem_(hashtable, hash)= ridge;
01268       break;
01269     }else if (ridgeA == ridge)
01270       break;
01271     if (++hash == hashsize)
01272       hash= 0;
01273   }
01274 } /* hashridge */
01275 
01276 
01277 /*-<a                             href="qh-merge.htm#TOC"
01278   >-------------------------------</a><a name="hashridge_find">-</a>
01279   
01280   qh_hashridge_find( hashtable, hashsize, ridge, vertex, oldvertex, hashslot )
01281     returns matching ridge without oldvertex in hashtable 
01282       for ridge without vertex
01283     if oldvertex is NULL 
01284       matches with any one skip
01285 
01286   returns:
01287     matching ridge or NULL
01288     if no match,
01289       if ridge already in   table
01290         hashslot= -1 
01291       else 
01292         hashslot= next NULL index
01293         
01294   notes:
01295     assumes hashtable is large enough
01296     can't match ridge to itself
01297 
01298   design:
01299     get hash value for ridge without vertex
01300     for each hashslot
01301       return match if ridge matches ridgeA without oldvertex
01302 */
01303 ridgeT *qh_hashridge_find (setT *hashtable, int hashsize, ridgeT *ridge, 
01304               vertexT *vertex, vertexT *oldvertex, int *hashslot) {
01305   int hash;
01306   ridgeT *ridgeA;
01307 
01308   *hashslot= 0;
01309   zinc_(Zhashridge);
01310   hash= (int)qh_gethash (hashsize, ridge->vertices, qh hull_dim-1, 0, vertex);
01311   while ((ridgeA= SETelemt_(hashtable, hash, ridgeT))) {
01312     if (ridgeA == ridge)
01313       *hashslot= -1;      
01314     else {
01315       zinc_(Zhashridgetest);
01316       if (qh_setequal_except (ridge->vertices, vertex, ridgeA->vertices, oldvertex))
01317         return ridgeA;
01318     }
01319     if (++hash == hashsize)
01320       hash= 0;
01321   }
01322   if (!*hashslot)
01323     *hashslot= hash;
01324   return NULL;
01325 } /* hashridge_find */
01326 
01327 
01328 /*-<a                             href="qh-merge.htm#TOC"
01329   >-------------------------------</a><a name="makeridges">-</a>
01330   
01331   qh_makeridges( facet )
01332     creates explicit ridges between simplicial facets
01333 
01334   returns:
01335     facet with ridges and without qh_MERGEridge
01336     ->simplicial is False
01337   
01338   notes:
01339     allows qh_MERGEridge flag
01340     uses existing ridges
01341     duplicate neighbors ok if ridges already exist (qh_mergecycle_ridges)
01342 
01343   see:
01344     qh_mergecycle_ridges()
01345 
01346   design:
01347     look for qh_MERGEridge neighbors
01348     mark neighbors that already have ridges
01349     for each unprocessed neighbor of facet    
01350       create a ridge for neighbor and facet
01351     if any qh_MERGEridge neighbors
01352       delete qh_MERGEridge flags (already handled by qh_mark_dupridges)
01353 */
01354 void qh_makeridges(facetT *facet) {
01355   facetT *neighbor, **neighborp;
01356   ridgeT *ridge, **ridgep;
01357   int neighbor_i, neighbor_n;
01358   boolT toporient, mergeridge= False;
01359   
01360   if (!facet->simplicial)
01361     return;
01362   trace4((qh ferr, "qh_makeridges: make ridges for f%d\n", facet->id));
01363   facet->simplicial= False;
01364   FOREACHneighbor_(facet) {
01365     if (neighbor == qh_MERGEridge)
01366       mergeridge= True;
01367     else
01368       neighbor->seen= False;
01369   }
01370   FOREACHridge_(facet->ridges)
01371     otherfacet_(ridge, facet)->seen= True;
01372   FOREACHneighbor_i_(facet) {
01373     if (neighbor == qh_MERGEridge)
01374       continue;  /* fixed by qh_mark_dupridges */
01375     else if (!neighbor->seen) {  /* no current ridges */
01376       ridge= qh_newridge();
01377       ridge->vertices= qh_setnew_delnthsorted (facet->vertices, qh hull_dim,
01378                                                           neighbor_i, 0);
01379       toporient= facet->toporient ^ (neighbor_i & 0x1);
01380       if (toporient) {
01381         ridge->top= facet;
01382         ridge->bottom= neighbor;
01383       }else {
01384         ridge->top= neighbor;
01385         ridge->bottom= facet;
01386       }
01387 #if 0 /* this also works */
01388       flip= (facet->toporient ^ neighbor->toporient)^(skip1 & 0x1) ^ (skip2 & 0x1);
01389       if (facet->toporient ^ (skip1 & 0x1) ^ flip) {
01390         ridge->top= neighbor;
01391         ridge->bottom= facet;
01392       }else {
01393         ridge->top= facet;
01394         ridge->bottom= neighbor;
01395       }
01396 #endif
01397       qh_setappend(&(facet->ridges), ridge);
01398       qh_setappend(&(neighbor->ridges), ridge);
01399     }
01400   }
01401   if (mergeridge) {
01402     while (qh_setdel (facet->neighbors, qh_MERGEridge))
01403       ; /* delete each one */
01404   }
01405 } /* makeridges */
01406 
01407 
01408 /*-<a                             href="qh-merge.htm#TOC"
01409   >-------------------------------</a><a name="mark_dupridges">-</a>
01410   
01411   qh_mark_dupridges( facetlist )
01412     add duplicated ridges to qh.facet_mergeset
01413     facet->dupridge is true
01414 
01415   returns:
01416     duplicate ridges on qh.facet_mergeset
01417     ->mergeridge/->mergeridge2 set
01418     duplicate ridges marked by qh_MERGEridge and both sides facet->dupridge
01419     no MERGEridges in neighbor sets
01420     
01421   notes:
01422     duplicate ridges occur when the horizon is pinched,
01423         i.e. a subridge occurs in more than two horizon   ridges.
01424     could rename vertices that pinch the horizon
01425     uses qh.visit_id
01426 
01427   design:
01428     for all facets on facetlist
01429       if facet contains a duplicate ridge
01430         for each neighbor of facet
01431           if neighbor marked qh_MERGEridge (one side of the merge)
01432             set facet->mergeridge      
01433           else
01434             if neighbor contains a duplicate ridge 
01435             and the back link is qh_MERGEridge
01436               append duplicate ridge to qh.facet_mergeset
01437    for each duplicate ridge
01438      make ridge sets in preparation for merging
01439      remove qh_MERGEridge from neighbor set
01440    for each duplicate ridge
01441      restore the missing neighbor from the neighbor set that was qh_MERGEridge
01442      add the missing ridge for this neighbor
01443 */
01444 void qh_mark_dupridges(facetT *facetlist) {
01445   facetT *facet, *neighbor, **neighborp;
01446   int nummerge=0;
01447   mergeT *merge, **mergep;
01448   
01449 
01450   trace4((qh ferr, "qh_mark_dupridges: identify duplicate ridges\n"));  
01451   FORALLfacet_(facetlist) {
01452     if (facet->dupridge) {
01453       FOREACHneighbor_(facet) {
01454         if (neighbor == qh_MERGEridge) {
01455           facet->mergeridge= True;
01456           continue;
01457         }
01458         if (neighbor->dupridge
01459         && !qh_setin (neighbor->neighbors, facet)) { /* qh_MERGEridge */
01460           qh_appendmergeset (facet, neighbor, MRGridge, NULL);
01461           facet->mergeridge2= True;
01462           facet->mergeridge= True;
01463           nummerge++;
01464         }
01465       }
01466     }
01467   }
01468   if (!nummerge)
01469     return;
01470   FORALLfacet_(facetlist) {            /* gets rid of qh_MERGEridge */
01471     if (facet->mergeridge && !facet->mergeridge2)   
01472       qh_makeridges (facet);
01473   }
01474   FOREACHmerge_(qh facet_mergeset) {   /* restore the missing neighbors */
01475     if (merge->type == MRGridge) {
01476       qh_setappend (&merge->facet2->neighbors, merge->facet1);
01477       qh_makeridges (merge->facet1);   /* and the missing ridges */
01478     }
01479   }
01480   trace1((qh ferr, "qh_mark_dupridges: found %d duplicated ridges\n", 
01481                 nummerge));
01482 } /* mark_dupridges */
01483 
01484 /*-<a                             href="qh-merge.htm#TOC"
01485   >-------------------------------</a><a name="maydropneighbor">-</a>
01486   
01487   qh_maydropneighbor( facet )
01488     drop neighbor relationship if no ridge between facet and neighbor
01489 
01490   returns:
01491     neighbor sets updated
01492     appends degenerate facets to qh.facet_mergeset
01493   
01494   notes:
01495     won't cause redundant facets since vertex inclusion is the same
01496     may drop vertex and neighbor if no ridge
01497     uses qh.visit_id
01498 
01499   design:
01500     visit all neighbors with ridges
01501     for each unvisited neighbor of facet
01502       delete neighbor and facet from the neighbor sets
01503       if neighbor becomes degenerate
01504         append neighbor to qh.degen_mergeset
01505     if facet is degenerate
01506       append facet to qh.degen_mergeset
01507 */
01508 void qh_maydropneighbor (facetT *facet) {
01509   ridgeT *ridge, **ridgep;
01510   realT angledegen= qh_ANGLEdegen;
01511   facetT *neighbor, **neighborp;
01512 
01513   qh visit_id++;
01514   trace4((qh ferr, "qh_maydropneighbor: test f%d for no ridges to a neighbor\n",
01515           facet->id));
01516   FOREACHridge_(facet->ridges) {
01517     ridge->top->visitid= qh visit_id;
01518     ridge->bottom->visitid= qh visit_id;
01519   }
01520   FOREACHneighbor_(facet) {
01521     if (neighbor->visitid != qh visit_id) {
01522       trace0((qh ferr, "qh_maydropneighbor: facets f%d and f%d are no longer neighbors during p%d\n",
01523             facet->id, neighbor->id, qh furthest_id));
01524       zinc_(Zdropneighbor);
01525       qh_setdel (facet->neighbors, neighbor);
01526       neighborp--;  /* repeat, deleted a neighbor */
01527       qh_setdel (neighbor->neighbors, facet);
01528       if (qh_setsize (neighbor->neighbors) < qh hull_dim) {
01529         zinc_(Zdropdegen);
01530         qh_appendmergeset (neighbor, neighbor, MRGdegen, &angledegen);
01531         trace2((qh ferr, "qh_maydropneighbors: f%d is degenerate.\n", neighbor->id));
01532       }
01533     }
01534   }
01535   if (qh_setsize (facet->neighbors) < qh hull_dim) {
01536     zinc_(Zdropdegen);
01537     qh_appendmergeset (facet, facet, MRGdegen, &angledegen);
01538     trace2((qh ferr, "qh_maydropneighbors: f%d is degenerate.\n", facet->id));
01539   }
01540 } /* maydropneighbor */
01541 
01542 
01543 /*-<a                             href="qh-merge.htm#TOC"
01544   >-------------------------------</a><a name="merge_degenredundant">-</a>
01545   
01546   qh_merge_degenredundant()
01547     merge all degenerate and redundant facets
01548     qh.degen_mergeset contains merges from qh_degen_redundant_neighbors()
01549 
01550   returns:
01551     number of merges performed
01552     resets facet->degenerate/redundant
01553     if deleted (visible) facet has no neighbors
01554       sets ->f.replace to NULL
01555 
01556   notes:
01557     redundant merges happen before degenerate ones
01558     merging and renaming vertices can result in degen/redundant facets
01559 
01560   design:
01561     for each merge on qh.degen_mergeset
01562       if redundant merge
01563         if non-redundant facet merged into redundant facet
01564           recheck facet for redundancy
01565         else
01566           merge redundant facet into other facet
01567 */
01568 int qh_merge_degenredundant (void) {
01569   int size;
01570   mergeT *merge;
01571   facetT *bestneighbor, *facet1, *facet2;
01572   realT dist, mindist, maxdist;
01573   vertexT *vertex, **vertexp;
01574   int nummerges= 0;
01575   mergeType mergetype;
01576 
01577   while ((merge= (mergeT*)qh_setdellast (qh degen_mergeset))) {
01578     facet1= merge->facet1;
01579     facet2= merge->facet2;
01580     mergetype= merge->type;
01581     qh_memfree (merge, sizeof(mergeT));
01582     if (facet1->visible)
01583       continue;
01584     facet1->degenerate= False; 
01585     facet1->redundant= False; 
01586     if (qh TRACEmerge-1 == zzval_(Ztotmerge))
01587       qhmem.IStracing= qh IStracing= qh TRACElevel;
01588     if (mergetype == MRGredundant) {
01589       zinc_(Zneighbor);
01590       while (facet2->visible) {
01591         if (!facet2->f.replace) {
01592           fprintf (qh ferr, "qhull internal error (qh_merge_degenredunant): f%d redundant but f%d has no replacement\n",
01593                facet1->id, facet2->id);
01594           qh_errexit2 (qh_ERRqhull, facet1, facet2);
01595         }
01596         facet2= facet2->f.replace;
01597       }
01598       if (facet1 == facet2) {
01599         qh_degen_redundant_facet (facet1); /* in case of others */
01600         continue;
01601       }
01602       trace2((qh ferr, "qh_merge_degenredundant: facet f%d is contained in f%d, will merge\n",
01603             facet1->id, facet2->id));
01604       qh_mergefacet(facet1, facet2, NULL, NULL, !qh_MERGEapex);
01605       /* merge distance is already accounted for */
01606       nummerges++;
01607     }else {  /* mergetype == MRGdegen, other merges may have fixed */
01608       if (!(size= qh_setsize (facet1->neighbors))) {
01609         zinc_(Zdelfacetdup);
01610         trace2((qh ferr, "qh_merge_degenredundant: facet f%d has no neighbors.  Deleted\n", facet1->id));
01611         qh_willdelete (facet1, NULL);
01612         FOREACHvertex_(facet1->vertices) {
01613           qh_setdel (vertex->neighbors, facet1);
01614           if (!SETfirst_(vertex->neighbors)) {
01615             zinc_(Zdegenvertex);
01616             trace2((qh ferr, "qh_merge_degenredundant: deleted v%d because f%d has no neighbors\n",
01617                  vertex->id, facet1->id));
01618             vertex->deleted= True;
01619             qh_setappend (&qh del_vertices, vertex);
01620           }
01621         }
01622         nummerges++;
01623       }else if (size < qh hull_dim) {
01624         bestneighbor= qh_findbestneighbor(facet1, &dist, &mindist, &maxdist);
01625         trace2((qh ferr, "qh_merge_degenredundant: facet f%d has %d neighbors, merge into f%d dist %2.2g\n",
01626               facet1->id, size, bestneighbor->id, dist));
01627         qh_mergefacet(facet1, bestneighbor, &mindist, &maxdist, !qh_MERGEapex);
01628         nummerges++;
01629         if (qh PRINTstatistics) {
01630           zinc_(Zdegen);
01631           wadd_(Wdegentot, dist);
01632           wmax_(Wdegenmax, dist);
01633         }
01634       } /* else, another merge fixed the degeneracy and redundancy tested */
01635     }
01636   }
01637   return nummerges;
01638 } /* merge_degenredundant */
01639 
01640 /*-<a                             href="qh-merge.htm#TOC"
01641   >-------------------------------</a><a name="merge_nonconvex">-</a>
01642   
01643   qh_merge_nonconvex( facet1, facet2, mergetype )
01644     remove non-convex ridge between facet1 into facet2 
01645     mergetype gives why the facet's are non-convex
01646 
01647   returns:
01648     merges one of the facets into the best neighbor
01649     
01650   design:
01651     if one of the facets is a new facet
01652       prefer merging new facet into old facet
01653     find best neighbors for both facets
01654     merge the nearest facet into its best neighbor
01655     update the statistics
01656 */
01657 void qh_merge_nonconvex (facetT *facet1, facetT *facet2, mergeType mergetype) {
01658   facetT *bestfacet, *bestneighbor, *neighbor;
01659   realT dist, dist2, mindist, mindist2, maxdist, maxdist2;
01660 
01661   if (qh TRACEmerge-1 == zzval_(Ztotmerge))
01662     qhmem.IStracing= qh IStracing= qh TRACElevel;
01663   trace3((qh ferr, "qh_merge_nonconvex: merge #%d for f%d and f%d type %d\n",
01664       zzval_(Ztotmerge) + 1, facet1->id, facet2->id, mergetype));
01665   /* concave or coplanar */
01666   if (!facet1->newfacet) {
01667     bestfacet= facet2;   /* avoid merging old facet if new is ok */
01668     facet2= facet1;
01669     facet1= bestfacet;
01670   }else
01671     bestfacet= facet1;
01672   bestneighbor= qh_findbestneighbor(bestfacet, &dist, &mindist, &maxdist);
01673   neighbor= qh_findbestneighbor(facet2, &dist2, &mindist2, &maxdist2);
01674   if (dist < dist2) {
01675     qh_mergefacet(bestfacet, bestneighbor, &mindist, &maxdist, !qh_MERGEapex);
01676   }else if (qh AVOIDold && !facet2->newfacet
01677   && ((mindist >= -qh MAXcoplanar && maxdist <= qh max_outside)
01678        || dist * 1.5 < dist2)) {
01679     zinc_(Zavoidold);
01680     wadd_(Wavoidoldtot, dist);
01681     wmax_(Wavoidoldmax, dist);
01682     trace2((qh ferr, "qh_merge_nonconvex: avoid merging old facet f%d dist %2.2g.  Use f%d dist %2.2g instead\n",
01683            facet2->id, dist2, facet1->id, dist2));
01684     qh_mergefacet(bestfacet, bestneighbor, &mindist, &maxdist, !qh_MERGEapex);
01685   }else {
01686     qh_mergefacet(facet2, neighbor, &mindist2, &maxdist2, !qh_MERGEapex);
01687     dist= dist2;
01688   }
01689   if (qh PRINTstatistics) {
01690     if (mergetype == MRGanglecoplanar) {
01691       zinc_(Zacoplanar);
01692       wadd_(Wacoplanartot, dist);
01693       wmax_(Wacoplanarmax, dist);
01694     }else if (mergetype == MRGconcave) {
01695       zinc_(Zconcave);
01696       wadd_(Wconcavetot, dist);
01697       wmax_(Wconcavemax, dist);
01698     }else { /* MRGcoplanar */
01699       zinc_(Zcoplanar);
01700       wadd_(Wcoplanartot, dist);
01701       wmax_(Wcoplanarmax, dist);
01702     }
01703   }
01704 } /* merge_nonconvex */
01705 
01706 /*-<a                             href="qh-merge.htm#TOC"
01707   >-------------------------------</a><a name="mergecycle">-</a>
01708   
01709   qh_mergecycle( samecycle, newfacet )
01710     merge a cycle of facets starting at samecycle into a newfacet 
01711     newfacet is a horizon facet with ->normal
01712     samecycle facets are simplicial from an apex
01713 
01714   returns:
01715     initializes vertex neighbors on first merge
01716     samecycle deleted (placed on qh.visible_list)
01717     newfacet at end of qh.facet_list
01718     deleted vertices on qh.del_vertices
01719 
01720   see:
01721     qh_mergefacet()
01722     called by qh_mergecycle_all() for multiple, same cycle facets
01723 
01724   design:
01725     make vertex neighbors if necessary
01726     make ridges for newfacet
01727     merge neighbor sets of samecycle into newfacet
01728     merge ridges of samecycle into newfacet
01729     merge vertex neighbors of samecycle into newfacet
01730     make apex of samecycle the apex of newfacet
01731     if newfacet wasn't a new facet
01732       add its vertices to qh.newvertex_list
01733     delete samecycle facets a make newfacet a newfacet
01734 */
01735 void qh_mergecycle (facetT *samecycle, facetT *newfacet) {
01736   int traceonce= False, tracerestore= 0;
01737   vertexT *apex;
01738 #ifndef qh_NOtrace
01739   facetT *same;
01740 #endif
01741 
01742   if (!qh VERTEXneighbors)
01743     qh_vertexneighbors();
01744   zzinc_(Ztotmerge);
01745   if (qh REPORTfreq2 && qh POSTmerging) {
01746     if (zzval_(Ztotmerge) > qh mergereport + qh REPORTfreq2)
01747       qh_tracemerging();
01748   }
01749 #ifndef qh_NOtrace
01750   if (qh TRACEmerge == zzval_(Ztotmerge))
01751     qhmem.IStracing= qh IStracing= qh TRACElevel;
01752   trace2((qh ferr, "qh_mergecycle: merge #%d for facets from cycle f%d into coplanar horizon f%d\n", 
01753         zzval_(Ztotmerge), samecycle->id, newfacet->id));
01754   if (newfacet == qh tracefacet) {
01755     tracerestore= qh IStracing;
01756     qh IStracing= 4;
01757     fprintf (qh ferr, "qh_mergecycle: ========= trace merge %d of samecycle %d into trace f%d, furthest is p%d\n",
01758                zzval_(Ztotmerge), samecycle->id, newfacet->id,  qh furthest_id);
01759     traceonce= True;
01760   }
01761   if (qh IStracing >=4) {
01762     fprintf (qh ferr, "  same cycle:");
01763     FORALLsame_cycle_(samecycle)
01764       fprintf(qh ferr, " f%d", same->id);
01765     fprintf (qh ferr, "\n");
01766   }
01767   if (qh IStracing >=4)
01768     qh_errprint ("MERGING CYCLE", samecycle, newfacet, NULL, NULL);
01769 #endif /* !qh_NOtrace */
01770   apex= SETfirstt_(samecycle->vertices, vertexT);
01771   qh_makeridges (newfacet);
01772   qh_mergecycle_neighbors (samecycle, newfacet);
01773   qh_mergecycle_ridges (samecycle, newfacet);
01774   qh_mergecycle_vneighbors (samecycle, newfacet);
01775   if (SETfirstt_(newfacet->vertices, vertexT) != apex) 
01776     qh_setaddnth (&newfacet->vertices, 0, apex);  /* apex has last id */
01777   if (!newfacet->newfacet)
01778     qh_newvertices (newfacet->vertices);
01779   qh_mergecycle_facets (samecycle, newfacet);
01780   qh_tracemerge (samecycle, newfacet);
01781   /* check for degen_redundant_neighbors after qh_forcedmerges() */
01782   if (traceonce) {
01783     fprintf (qh ferr, "qh_mergecycle: end of trace facet\n");
01784     qh IStracing= tracerestore;
01785   }
01786 } /* mergecycle */
01787 
01788 /*-<a                             href="qh-merge.htm#TOC"
01789   >-------------------------------</a><a name="mergecycle_all">-</a>
01790   
01791   qh_mergecycle_all( facetlist, wasmerge )
01792     merge all samecycles of coplanar facets into horizon
01793     don't merge facets with ->mergeridge (these already have ->normal)
01794     all facets are simplicial from apex
01795     all facet->cycledone == False
01796 
01797   returns:
01798     all newfacets merged into coplanar horizon facets
01799     deleted vertices on  qh.del_vertices
01800     sets wasmerge if any merge
01801 
01802   see:
01803     calls qh_mergecycle for multiple, same cycle facets
01804 
01805   design:
01806     for each facet on facetlist
01807       skip facets with duplicate ridges and normals
01808       check that facet is in a samecycle (->mergehorizon)
01809       if facet only member of samecycle
01810         sets vertex->delridge for all vertices except apex
01811         merge facet into horizon
01812       else
01813         mark all facets in samecycle
01814         remove facets with duplicate ridges from samecycle
01815         merge samecycle into horizon (deletes facets from facetlist)
01816 */
01817 void qh_mergecycle_all (facetT *facetlist, boolT *wasmerge) {
01818   facetT *facet, *same, *prev, *horizon;
01819   facetT *samecycle= NULL, *nextfacet, *nextsame;
01820   vertexT *apex, *vertex, **vertexp;
01821   int cycles=0, total=0, facets, nummerge;
01822 
01823   trace2((qh ferr, "qh_mergecycle_all: begin\n"));
01824   for (facet= facetlist; facet && (nextfacet= facet->next); facet= nextfacet) {
01825     if (facet->normal)
01826       continue;
01827     if (!facet->mergehorizon) {
01828       fprintf (qh ferr, "qh_mergecycle_all: f%d without normal\n", facet->id);
01829       qh_errexit (qh_ERRqhull, facet, NULL);
01830     }
01831     horizon= SETfirstt_(facet->neighbors, facetT);
01832     if (facet->f.samecycle == facet) {
01833       zinc_(Zonehorizon);  
01834       /* merge distance done in qh_findhorizon */
01835       apex= SETfirstt_(facet->vertices, vertexT);
01836       FOREACHvertex_(facet->vertices) {
01837         if (vertex != apex)
01838           vertex->delridge= True;
01839       }
01840       horizon->f.newcycle= NULL;
01841       qh_mergefacet (facet, horizon, NULL, NULL, qh_MERGEapex);
01842     }else {
01843       samecycle= facet;
01844       facets= 0;
01845       prev= facet;
01846       for (same= facet->f.samecycle; same;  /* FORALLsame_cycle_(facet) */
01847            same= (same == facet ? NULL :nextsame)) { /* ends at facet */
01848         nextsame= same->f.samecycle;
01849         if (same->cycledone || same->visible)
01850           qh_infiniteloop (same);
01851         same->cycledone= True;
01852         if (same->normal) { 
01853           prev->f.samecycle= same->f.samecycle; /* unlink ->mergeridge */
01854           same->f.samecycle= NULL;
01855         }else {
01856           prev= same;
01857           facets++;
01858         }
01859       }
01860       while (nextfacet && nextfacet->cycledone)  /* will delete samecycle */
01861         nextfacet= nextfacet->next;
01862       horizon->f.newcycle= NULL;
01863       qh_mergecycle (samecycle, horizon);
01864       nummerge= horizon->nummerge + facets;
01865       if (nummerge > qh_MAXnummerge) 
01866         horizon->nummerge= qh_MAXnummerge;
01867       else
01868         horizon->nummerge= nummerge;
01869       zzinc_(Zcyclehorizon);
01870       total += facets;
01871       zzadd_(Zcyclefacettot, facets);
01872       zmax_(Zcyclefacetmax, facets);
01873     }
01874     cycles++;
01875   }
01876   if (cycles)
01877     *wasmerge= True;
01878   trace1((qh ferr, "qh_mergecycle_all: merged %d same cycles or facets into coplanar horizons\n", cycles));
01879 } /* mergecycle_all */
01880 
01881 /*-<a                             href="qh-merge.htm#TOC"
01882   >-------------------------------</a><a name="mergecycle_facets">-</a>
01883   
01884   qh_mergecycle_facets( samecycle, newfacet )
01885     finish merge of samecycle into newfacet
01886 
01887   returns:
01888     samecycle prepended to visible_list for later deletion and partitioning
01889       each facet->f.replace == newfacet
01890       
01891     newfacet moved to end of qh.facet_list
01892       makes newfacet a newfacet (get's facet1->id if it was old)
01893       sets newfacet->newmerge
01894       clears newfacet->center (unless merging into a large facet)
01895       clears newfacet->tested and ridge->tested for facet1
01896       
01897     adds neighboring facets to facet_mergeset if redundant or degenerate
01898 
01899   design:
01900     make newfacet a new facet and set its flags
01901     move samecycle facets to qh.visible_list for later deletion
01902     unless newfacet is large
01903       remove its centrum
01904 */
01905 void qh_mergecycle_facets (facetT *samecycle, facetT *newfacet) {
01906   facetT *same, *next;
01907   
01908   trace4((qh ferr, "qh_mergecycle_facets: make newfacet new and samecycle deleted\n"));  
01909   qh_removefacet(newfacet);  /* append as a newfacet to end of qh facet_list */
01910   qh_appendfacet(newfacet);
01911   newfacet->newfacet= True;
01912   newfacet->simplicial= False;
01913   newfacet->newmerge= True;
01914   
01915   for (same= samecycle->f.samecycle; same; same= (same == samecycle ?  NULL : next)) {
01916     next= same->f.samecycle;  /* reused by willdelete */
01917     qh_willdelete (same, newfacet);
01918   }
01919   if (newfacet->center 
01920       && qh_setsize (newfacet->vertices) <= qh hull_dim + qh_MAXnewcentrum) {
01921     qh_memfree (newfacet->center, qh normal_size);
01922     newfacet->center= NULL;
01923   }
01924   trace3((qh ferr, "qh_mergecycle_facets: merged facets from cycle f%d into f%d\n", 
01925              samecycle->id, newfacet->id));
01926 } /* mergecycle_facets */
01927 
01928 /*-<a                             href="qh-merge.htm#TOC"
01929   >-------------------------------</a><a name="mergecycle_neighbors">-</a>
01930   
01931   qh_mergecycle_neighbors( samecycle, newfacet )
01932     add neighbors for samecycle facets to newfacet
01933 
01934   returns:
01935     newfacet with updated neighbors and vice-versa
01936     newfacet has ridges
01937     all neighbors of newfacet marked with qh.visit_id
01938     samecycle facets marked with qh.visit_id-1
01939     ridges updated for simplicial neighbors of samecycle with a ridge
01940 
01941   notes:
01942     assumes newfacet not in samecycle
01943     usually, samecycle facets are new, simplicial facets without internal ridges 
01944       not so if horizon facet is coplanar to two different samecycles
01945   
01946   see:
01947     qh_mergeneighbors()
01948 
01949   design:
01950     check samecycle
01951     delete neighbors from newfacet that are also in samecycle
01952     for each neighbor of a facet in samecycle
01953       if neighbor is simplicial
01954         if first visit
01955           move the neighbor relation to newfacet
01956           update facet links for its ridges
01957         else
01958           make ridges for neighbor
01959           remove samecycle reference
01960       else
01961         update neighbor sets
01962 */
01963 void qh_mergecycle_neighbors(facetT *samecycle, facetT *newfacet) {
01964   facetT *same, *neighbor, **neighborp;
01965   int delneighbors= 0, newneighbors= 0;
01966   unsigned int samevisitid;
01967   ridgeT *ridge, **ridgep;
01968 
01969   samevisitid= ++qh visit_id;
01970   FORALLsame_cycle_(samecycle) {
01971     if (same->visitid == samevisitid || same->visible)
01972       qh_infiniteloop (samecycle);
01973     same->visitid= samevisitid;
01974   }
01975   newfacet->visitid= ++qh visit_id;
01976   trace4((qh ferr, "qh_mergecycle_neighbors: delete shared neighbors from newfacet\n"));  
01977   FOREACHneighbor_(newfacet) {
01978     if (neighbor->visitid == samevisitid) {
01979       SETref_(neighbor)= NULL;  /* samecycle neighbors deleted */
01980       delneighbors++;
01981     }else
01982       neighbor->visitid= qh visit_id;
01983   }
01984   qh_setcompact (newfacet->neighbors);
01985 
01986   trace4((qh ferr, "qh_mergecycle_neighbors: update neighbors\n"));  
01987   FORALLsame_cycle_(samecycle) {
01988     FOREACHneighbor_(same) {
01989       if (neighbor->visitid == samevisitid)
01990         continue;
01991       if (neighbor->simplicial) {
01992         if (neighbor->visitid != qh visit_id) {
01993           qh_setappend (&newfacet->neighbors, neighbor);
01994           qh_setreplace (neighbor->neighbors, same, newfacet);
01995           newneighbors++;
01996           neighbor->visitid= qh visit_id;
01997           FOREACHridge_(neighbor->ridges) { /* update ridge in case of qh_makeridges */
01998             if (ridge->top == same) {
01999               ridge->top= newfacet;
02000               break;
02001             }else if (ridge->bottom == same) {
02002               ridge->bottom= newfacet;
02003               break;
02004             }
02005           }
02006         }else {
02007           qh_makeridges (neighbor);
02008           qh_setdel (neighbor->neighbors, same);
02009           /* same can't be horizon facet for neighbor */
02010         }
02011       }else { /* non-simplicial neighbor */
02012         qh_setdel (neighbor->neighbors, same);
02013         if (neighbor->visitid != qh visit_id) {
02014           qh_setappend (&neighbor->neighbors, newfacet);
02015           qh_setappend (&newfacet->neighbors, neighbor);
02016           neighbor->visitid= qh visit_id;
02017           newneighbors++;
02018         } 
02019       }
02020     }
02021   }
02022   trace2((qh ferr, "qh_mergecycle_neighbors: deleted %d neighbors and added %d\n", 
02023              delneighbors, newneighbors));
02024 } /* mergecycle_neighbors */
02025 
02026 /*-<a                             href="qh-merge.htm#TOC"
02027   >-------------------------------</a><a name="mergecycle_ridges">-</a>
02028   
02029   qh_mergecycle_ridges( samecycle, newfacet )
02030     add ridges/neighbors for facets in samecycle to newfacet
02031     all new/old neighbors of newfacet marked with qh.visit_id
02032     facets in samecycle marked with qh.visit_id-1
02033     newfacet marked with qh.visit_id
02034 
02035   returns:
02036     newfacet has merged ridges
02037   
02038   notes:
02039     ridge already updated for simplicial neighbors of samecycle with a ridge
02040 
02041   see:
02042     qh_mergeridges()
02043     qh_makeridges()
02044 
02045   design:
02046     remove ridges between newfacet and samecycle
02047     for each facet in samecycle
02048       for each ridge in facet
02049         update facet pointers in ridge
02050         skip ridges processed in qh_mergecycle_neighors
02051         free ridges between newfacet and samecycle
02052         free ridges between facets of samecycle (on 2nd visit)
02053         append remaining ridges to newfacet
02054       if simpilicial facet
02055         for each neighbor of facet
02056           if simplicial facet
02057           and not samecycle facet or newfacet
02058             make ridge between neighbor and newfacet
02059 */
02060 void qh_mergecycle_ridges(facetT *samecycle, facetT *newfacet) {
02061   facetT *same, *neighbor= NULL;
02062   int numold=0, numnew=0;
02063   int neighbor_i, neighbor_n;
02064   unsigned int samevisitid;
02065   ridgeT *ridge, **ridgep;
02066   boolT toporient;
02067   void **freelistp; /* used !qh_NOmem */
02068 
02069   trace4((qh ferr, "qh_mergecycle_ridges: delete shared ridges from newfacet\n"));  
02070   samevisitid= qh visit_id -1;
02071   FOREACHridge_(newfacet->ridges) {
02072     neighbor= otherfacet_(ridge, newfacet);
02073     if (neighbor->visitid == samevisitid)
02074       SETref_(ridge)= NULL; /* ridge free'd below */  
02075   }
02076   qh_setcompact (newfacet->ridges);
02077   
02078   trace4((qh ferr, "qh_mergecycle_ridges: add ridges to newfacet\n"));  
02079   FORALLsame_cycle_(samecycle) {
02080     FOREACHridge_(same->ridges) {
02081       if (ridge->top == same) {
02082         ridge->top= newfacet;
02083         neighbor= ridge->bottom;
02084       }else if (ridge->bottom == same) {
02085         ridge->bottom= newfacet;
02086         neighbor= ridge->top;
02087       }else if (ridge->top == newfacet || ridge->bottom == newfacet) {
02088         qh_setappend (&newfacet->ridges, ridge);
02089         numold++;  /* already set by qh_mergecycle_neighbors */
02090         continue;  
02091       }else {
02092         fprintf (qh ferr, "qhull internal error (qh_mergecycle_ridges): bad ridge r%d\n", ridge->id);
02093         qh_errexit (qh_ERRqhull, NULL, ridge);
02094       }
02095       if (neighbor == newfacet) {
02096         qh_setfree(&(ridge->vertices)); 
02097         qh_memfree_(ridge, sizeof(ridgeT), freelistp);
02098         numold++;
02099       }else if (neighbor->visitid == samevisitid) {
02100         qh_setdel (neighbor->ridges, ridge);
02101         qh_setfree(&(ridge->vertices)); 
02102         qh_memfree_(ridge, sizeof(ridgeT), freelistp);
02103         numold++;
02104       }else {
02105         qh_setappend (&newfacet->ridges, ridge);
02106         numold++;
02107       }
02108     }
02109     if (same->ridges)
02110       qh_settruncate (same->ridges, 0);
02111     if (!same->simplicial)
02112       continue;
02113     FOREACHneighbor_i_(same) {       /* note: !newfact->simplicial */
02114       if (neighbor->visitid != samevisitid && neighbor->simplicial) {
02115         ridge= qh_newridge();
02116         ridge->vertices= qh_setnew_delnthsorted (same->vertices, qh hull_dim,
02117                                                           neighbor_i, 0);
02118         toporient= same->toporient ^ (neighbor_i & 0x1);
02119         if (toporient) {
02120           ridge->top= newfacet;
02121           ridge->bottom= neighbor;
02122         }else {
02123           ridge->top= neighbor;
02124           ridge->bottom= newfacet;
02125         }
02126         qh_setappend(&(newfacet->ridges), ridge);
02127         qh_setappend(&(neighbor->ridges), ridge);
02128         numnew++;
02129       }
02130     }
02131   }
02132 
02133   trace2((qh ferr, "qh_mergecycle_ridges: found %d old ridges and %d new ones\n", 
02134              numold, numnew));
02135 } /* mergecycle_ridges */
02136 
02137 /*-<a                             href="qh-merge.htm#TOC"
02138   >-------------------------------</a><a name="mergecycle_vneighbors">-</a>
02139   
02140   qh_mergecycle_vneighbors( samecycle, newfacet )
02141     create vertex neighbors for newfacet from vertices of facets in samecycle
02142     samecycle marked with visitid == qh.visit_id - 1
02143 
02144   returns:
02145     newfacet vertices with updated neighbors
02146     marks newfacet with qh.visit_id-1
02147     deletes vertices that are merged away
02148     sets delridge on all vertices (faster here than in mergecycle_ridges)
02149 
02150   see:
02151     qh_mergevertex_neighbors()
02152 
02153   design:
02154     for each vertex of samecycle facet
02155       set vertex->delridge
02156       delete samecycle facets from vertex neighbors
02157       append newfacet to vertex neighbors
02158       if vertex only in newfacet
02159         delete it from newfacet
02160         add it to qh.del_vertices for later deletion
02161 */
02162 void qh_mergecycle_vneighbors (facetT *samecycle, facetT *newfacet) {
02163   facetT *neighbor, **neighborp;
02164   unsigned int mergeid;
02165   vertexT *vertex, **vertexp, *apex;
02166   setT *vertices;
02167   
02168   trace4((qh ferr, "qh_mergecycle_vneighbors: update vertex neighbors for newfacet\n"));  
02169   mergeid= qh visit_id - 1;
02170   newfacet->visitid= mergeid;
02171   vertices= qh_basevertices (samecycle); /* temp */
02172   apex= SETfirstt_(samecycle->vertices, vertexT);
02173   qh_setappend (&vertices, apex);
02174   FOREACHvertex_(vertices) {
02175     vertex->delridge= True;
02176     FOREACHneighbor_(vertex) {
02177       if (neighbor->visitid == mergeid)
02178         SETref_(neighbor)= NULL;
02179     }
02180     qh_setcompact (vertex->neighbors);
02181     qh_setappend (&vertex->neighbors, newfacet);
02182     if (!SETsecond_(vertex->neighbors)) {
02183       zinc_(Zcyclevertex);
02184       trace2((qh ferr, "qh_mergecycle_vneighbors: deleted v%d when merging cycle f%d into f%d\n",
02185         vertex->id, samecycle->id, newfacet->id));
02186       qh_setdelsorted (newfacet->vertices, vertex);
02187       vertex->deleted= True;
02188       qh_setappend (&qh del_vertices, vertex);
02189     }
02190   }
02191   qh_settempfree (&vertices);
02192   trace3((qh ferr, "qh_mergecycle_vneighbors: merged vertices from cycle f%d into f%d\n", 
02193              samecycle->id, newfacet->id));
02194 } /* mergecycle_vneighbors */
02195 
02196 /*-<a                             href="qh-merge.htm#TOC"
02197   >-------------------------------</a><a name="mergefacet">-</a>
02198   
02199   qh_mergefacet( facet1, facet2, mindist, maxdist, mergeapex )
02200     merges facet1 into facet2
02201     mergeapex==qh_MERGEapex if merging new facet into coplanar horizon
02202     
02203   returns:
02204     qh.max_outside and qh.min_vertex updated
02205     initializes vertex neighbors on first merge
02206 
02207   returns:
02208     facet2 contains facet1's vertices, neighbors, and ridges
02209       facet2 moved to end of qh.facet_list
02210       makes facet2 a newfacet
02211       sets facet2->newmerge set
02212       clears facet2->center (unless merging into a large facet)
02213       clears facet2->tested and ridge->tested for facet1
02214 
02215     facet1 prepended to visible_list for later deletion and partitioning
02216       facet1->f.replace == facet2
02217 
02218     adds neighboring facets to facet_mergeset if redundant or degenerate
02219 
02220   notes: 
02221     mindist/maxdist may be NULL
02222     traces merge if fmax_(maxdist,-mindist) > TRACEdist
02223 
02224   see: 
02225     qh_mergecycle()
02226 
02227   design:
02228     trace merge and check for degenerate simplex
02229     make ridges for both facets
02230     update qh.max_outside, qh.max_vertex, qh.min_vertex
02231     update facet2->maxoutside and keepcentrum
02232     update facet2->nummerge
02233     update tested flags for facet2
02234     if facet1 is simplicial
02235       merge facet1 into facet2
02236     else
02237       merge facet1's neighbors into facet2
02238       merge facet1's ridges into facet2
02239       merge facet1's vertices into facet2
02240       merge facet1's vertex neighbors into facet2
02241       add facet2's vertices to qh.new_vertexlist
02242       unless qh_MERGEapex
02243         test facet2 for degenerate or redundant neighbors
02244       move facet1 to qh.visible_list for later deletion
02245       move facet2 to end of qh.newfacet_list
02246 */
02247 void qh_mergefacet(facetT *facet1, facetT *facet2, realT *mindist, realT *maxdist, boolT mergeapex) {
02248   boolT traceonce= False;
02249   vertexT *vertex, **vertexp;
02250   int tracerestore=0, nummerge;
02251 
02252   zzinc_(Ztotmerge);
02253   if (qh REPORTfreq2 && qh POSTmerging) {
02254     if (zzval_(Ztotmerge) > qh mergereport + qh REPORTfreq2)
02255       qh_tracemerging();
02256   }
02257 #ifndef qh_NOtrace
02258   if (qh build_cnt >= qh RERUN) {
02259     if (mindist && (-*mindist > qh TRACEdist || *maxdist > qh TRACEdist)) {
02260       tracerestore= 0;
02261       qh IStracing= qh TRACElevel;
02262       traceonce= True;
02263       fprintf (qh ferr, "qh_mergefacet: ========= trace wide merge #%d (%2.2g) for f%d into f%d, last point was p%d\n", zzval_(Ztotmerge),
02264              fmax_(-*mindist, *maxdist), facet1->id, facet2->id, qh furthest_id);
02265     }else if (facet1 == qh tracefacet || facet2 == qh tracefacet) {
02266       tracerestore= qh IStracing;
02267       qh IStracing= 4;
02268       traceonce= True;
02269       fprintf (qh ferr, "qh_mergefacet: ========= trace merge #%d involving f%d, furthest is p%d\n",
02270                  zzval_(Ztotmerge), qh tracefacet_id,  qh furthest_id);
02271     }
02272   }
02273   if (qh IStracing >= 2) {
02274     realT mergemin= -2;
02275     realT mergemax= -2;
02276     
02277     if (mindist) {
02278       mergemin= *mindist;
02279       mergemax= *maxdist;
02280     }
02281     fprintf (qh ferr, "qh_mergefacet: #%d merge f%d into f%d, mindist= %2.2g, maxdist= %2.2g\n", 
02282     zzval_(Ztotmerge), facet1->id, facet2->id, mergemin, mergemax);
02283   }
02284 #endif /* !qh_NOtrace */
02285   if (facet1 == facet2 || facet1->visible || facet2->visible) {
02286     fprintf (qh ferr, "qhull internal error (qh_mergefacet): either f%d and f%d are the same or one is a visible facet\n",
02287              facet1->id, facet2->id);
02288     qh_errexit2 (qh_ERRqhull, facet1, facet2);
02289   }
02290   if (qh num_facets - qh num_visible <= qh hull_dim + 1) {
02291     fprintf(qh ferr, "\n\
02292 qhull precision error: Only %d facets remain.  Can not merge another\n\
02293 pair.  The convexity constraints may be too strong.  Reduce the\n\
02294 magnitude of 'Cn' or increase the magnitude of 'An'.  For example,\n\
02295 try 'C-0.001' instead of 'C-0.1' or 'A-0.999' instead of 'A-0.9'.\n", 
02296                  qh hull_dim+1);
02297     if (qh hull_dim >= 5 && !qh MERGEexact)
02298       fprintf(qh ferr, "Option 'Qx' may avoid this problem.\n");
02299     qh_errexit(qh_ERRinput, NULL, NULL);
02300   }
02301   if (!qh VERTEXneighbors)
02302     qh_vertexneighbors();
02303   qh_makeridges(facet1);
02304   qh_makeridges(facet2);
02305   if (qh IStracing >=4)
02306     qh_errprint ("MERGING", facet1, facet2, NULL, NULL);
02307   if (mindist) {
02308     maximize_(qh max_outside, *maxdist);
02309     maximize_(qh max_vertex, *maxdist);
02310 #if qh_MAXoutside
02311     maximize_(facet2->maxoutside, *maxdist);
02312 #endif
02313     minimize_(qh min_vertex, *mindist);
02314     if (!facet2->keepcentrum 
02315     && (*maxdist > qh WIDEfacet || *mindist < -qh WIDEfacet)) {
02316       facet2->keepcentrum= True;
02317       zinc_(Zwidefacet);
02318     }
02319   }
02320   nummerge= facet1->nummerge + facet2->nummerge + 1;
02321   if (nummerge >= qh_MAXnummerge) 
02322     facet2->nummerge= qh_MAXnummerge;
02323   else
02324     facet2->nummerge= nummerge;
02325   facet2->newmerge= True;
02326   facet2->dupridge= False;
02327   qh_updatetested  (facet1, facet2);
02328   if (qh hull_dim > 2 && qh_setsize (facet1->vertices) == qh hull_dim)
02329     qh_mergesimplex (facet1, facet2, mergeapex);
02330   else {
02331     qh vertex_visit++;
02332     FOREACHvertex_(facet2->vertices)
02333       vertex->visitid= qh vertex_visit;
02334     if (qh hull_dim == 2) 
02335       qh_mergefacet2d(facet1, facet2);
02336     else {
02337       qh_mergeneighbors(facet1, facet2);
02338       qh_mergevertices(facet1->vertices, &facet2->vertices);
02339     }
02340     qh_mergeridges(facet1, facet2);
02341     qh_mergevertex_neighbors(facet1, facet2);
02342     if (!facet2->newfacet)
02343       qh_newvertices (facet2->vertices);
02344   }
02345   if (!mergeapex)
02346     qh_degen_redundant_neighbors (facet2, facet1);
02347   if (facet2->coplanar || !facet2->newfacet) {
02348     zinc_(Zmergeintohorizon);
02349   }else if (!facet1->newfacet && facet2->newfacet) {
02350     zinc_(Zmergehorizon);
02351   }else {
02352     zinc_(Zmergenew);
02353   }
02354   qh_willdelete (facet1, facet2);
02355   qh_removefacet(facet2);  /* append as a newfacet to end of qh facet_list */
02356   qh_appendfacet(facet2);
02357   facet2->newfacet= True;
02358   facet2->tested= False;
02359   qh_tracemerge (facet1, facet2);
02360   if (traceonce) {
02361     fprintf (qh ferr, "qh_mergefacet: end of wide tracing\n");
02362     qh IStracing= tracerestore;
02363   }
02364 } /* mergefacet */
02365 
02366 
02367 /*-<a                             href="qh-merge.htm#TOC"
02368   >-------------------------------</a><a name="mergefacet2d">-</a>
02369   
02370   qh_mergefacet2d( facet1, facet2 )
02371     in 2d, merges neighbors and vertices of facet1 into facet2
02372     
02373   returns:
02374     build ridges for neighbors if necessary
02375     facet2 looks like a simplicial facet except for centrum, ridges
02376       neighbors are opposite the corresponding vertex
02377       maintains orientation of facet2
02378 
02379   notes:
02380     qh_mergefacet() retains non-simplicial structures
02381       they are not needed in 2d, but later routines may use them
02382     preserves qh.vertex_visit for qh_mergevertex_neighbors()
02383   
02384   design:
02385     get vertices and neighbors
02386     determine new vertices and neighbors
02387     set new vertices and neighbors and adjust orientation
02388     make ridges for new neighbor if needed
02389 */
02390 void qh_mergefacet2d (facetT *facet1, facetT *facet2) {
02391   vertexT *vertex1A, *vertex1B, *vertex2A, *vertex2B, *vertexA, *vertexB;
02392   facetT *neighbor1A, *neighbor1B, *neighbor2A, *neighbor2B, *neighborA, *neighborB;
02393 
02394   vertex1A= SETfirstt_(facet1->vertices, vertexT);
02395   vertex1B= SETsecondt_(facet1->vertices, vertexT);
02396   vertex2A= SETfirstt_(facet2->vertices, vertexT);
02397   vertex2B= SETsecondt_(facet2->vertices, vertexT);
02398   neighbor1A= SETfirstt_(facet1->neighbors, facetT);
02399   neighbor1B= SETsecondt_(facet1->neighbors, facetT);
02400   neighbor2A= SETfirstt_(facet2->neighbors, facetT);
02401   neighbor2B= SETsecondt_(facet2->neighbors, facetT);
02402   if (vertex1A == vertex2A) {
02403     vertexA= vertex1B;
02404     vertexB= vertex2B;
02405     neighborA= neighbor2A;
02406     neighborB= neighbor1A;
02407   }else if (vertex1A == vertex2B) {
02408     vertexA= vertex1B;
02409     vertexB= vertex2A;
02410     neighborA= neighbor2B;
02411     neighborB= neighbor1A;
02412   }else if (vertex1B == vertex2A) {
02413     vertexA= vertex1A;
02414     vertexB= vertex2B;
02415     neighborA= neighbor2A;
02416     neighborB= neighbor1B;
02417   }else { /* 1B == 2B */
02418     vertexA= vertex1A;
02419     vertexB= vertex2A;
02420     neighborA= neighbor2B;
02421     neighborB= neighbor1B;
02422   }
02423   /* vertexB always from facet2, neighborB always from facet1 */
02424   if (vertexA->id > vertexB->id) {
02425     SETfirst_(facet2->vertices)= vertexA;
02426     SETsecond_(facet2->vertices)= vertexB;
02427     if (vertexB == vertex2A)
02428       facet2->toporient= !facet2->toporient;
02429     SETfirst_(facet2->neighbors)= neighborA;
02430     SETsecond_(facet2->neighbors)= neighborB;
02431   }else {
02432     SETfirst_(facet2->vertices)= vertexB;
02433     SETsecond_(facet2->vertices)= vertexA;
02434     if (vertexB == vertex2B)
02435       facet2->toporient= !facet2->toporient;
02436     SETfirst_(facet2->neighbors)= neighborB;
02437     SETsecond_(facet2->neighbors)= neighborA;
02438   }
02439   qh_makeridges (neighborB);
02440   qh_setreplace(neighborB->neighbors, facet1, facet2);
02441   trace4((qh ferr, "qh_mergefacet2d: merged v%d and neighbor f%d of f%d into f%d\n",
02442        vertexA->id, neighborB->id, facet1->id, facet2->id));
02443 } /* mergefacet2d */
02444 
02445 
02446 /*-<a                             href="qh-merge.htm#TOC"
02447   >-------------------------------</a><a name="mergeneighbors">-</a>
02448   
02449   qh_mergeneighbors( facet1, facet2 )
02450     merges the neighbors of facet1 into facet2
02451 
02452   see: 
02453     qh_mergecycle_neighbors()
02454 
02455   design:
02456     for each neighbor of facet1
02457       if neighbor is also a neighbor of facet2
02458         if neighbor is simpilicial
02459           make ridges for later deletion as a degenerate facet
02460         update its neighbor set
02461       else
02462         move the neighbor relation to facet2
02463     remove the neighbor relation for facet1 and facet2
02464 */
02465 void qh_mergeneighbors(facetT *facet1, facetT *facet2) {
02466   facetT *neighbor, **neighborp;
02467 
02468   trace4((qh ferr, "qh_mergeneighbors: merge neighbors of f%d and f%d\n",
02469           facet1->id, facet2->id));
02470   qh visit_id++;
02471   FOREACHneighbor_(facet2) {
02472     neighbor->visitid= qh visit_id;
02473   }
02474   FOREACHneighbor_(facet1) {
02475     if (neighbor->visitid == qh visit_id) {
02476       if (neighbor->simplicial)    /* is degen, needs ridges */
02477         qh_makeridges (neighbor);
02478       if (SETfirstt_(neighbor->neighbors, facetT) != facet1) /*keep newfacet->horizon*/
02479         qh_setdel (neighbor->neighbors, facet1);
02480       else {
02481         qh_setdel(neighbor->neighbors, facet2);
02482         qh_setreplace(neighbor->neighbors, facet1, facet2);
02483       }
02484     }else if (neighbor != facet2) {
02485       qh_setappend(&(facet2->neighbors), neighbor);
02486       qh_setreplace(neighbor->neighbors, facet1, facet2);
02487     }
02488   }
02489   qh_setdel(facet1->neighbors, facet2);  /* here for makeridges */
02490   qh_setdel(facet2->neighbors, facet1);
02491 } /* mergeneighbors */
02492 
02493 
02494 /*-<a                             href="qh-merge.htm#TOC"
02495   >-------------------------------</a><a name="mergeridges">-</a>
02496   
02497   qh_mergeridges( facet1, facet2 )
02498     merges the ridge set of facet1 into facet2
02499 
02500   returns:
02501     may delete all ridges for a vertex
02502     sets vertex->delridge on deleted ridges
02503 
02504   see:
02505     qh_mergecycle_ridges()
02506 
02507   design:
02508     delete ridges between facet1 and facet2
02509       mark (delridge) vertices on these ridges for later testing   
02510     for each remaining ridge
02511       rename facet1 to facet2  
02512 */
02513 void qh_mergeridges(facetT *facet1, facetT *facet2) {
02514   ridgeT *ridge, **ridgep;
02515   vertexT *vertex, **vertexp;
02516 
02517   trace4((qh ferr, "qh_mergeridges: merge ridges of f%d and f%d\n",
02518           facet1->id, facet2->id));
02519   FOREACHridge_(facet2->ridges) {
02520     if ((ridge->top == facet1) || (ridge->bottom == facet1)) {
02521       FOREACHvertex_(ridge->vertices)
02522         vertex->delridge= True;
02523       qh_delridge(ridge);  /* expensive in high-d, could rebuild */
02524       ridgep--; /*repeat*/
02525     }
02526   }
02527   FOREACHridge_(facet1->ridges) {
02528     if (ridge->top == facet1)
02529       ridge->top= facet2;
02530     else
02531       ridge->bottom= facet2;
02532     qh_setappend(&(facet2->ridges), ridge);
02533   }
02534 } /* mergeridges */
02535 
02536 
02537 /*-<a                             href="qh-merge.htm#TOC"
02538   >-------------------------------</a><a name="mergesimplex">-</a>
02539   
02540   qh_mergesimplex( facet1, facet2, mergeapex )
02541     merge simplicial facet1 into facet2
02542     mergeapex==qh_MERGEapex if merging samecycle into horizon facet
02543       vertex id is latest (most recently created)
02544     facet1 may be contained in facet2
02545     ridges exist for both facets
02546 
02547   returns:
02548     facet2 with updated vertices, ridges, neighbors
02549     updated neighbors for facet1's vertices
02550     facet1 not deleted
02551     sets vertex->delridge on deleted ridges
02552   
02553   notes:
02554     special case code since this is the most common merge
02555     called from qh_mergefacet()
02556 
02557   design:
02558     if qh_MERGEapex
02559       add vertices of facet2 to qh.new_vertexlist if necessary
02560       add apex to facet2
02561     else
02562       for each ridge between facet1 and facet2
02563         set vertex->delridge
02564       determine the apex for facet1 (i.e., vertex to be merged)
02565       unless apex already in facet2
02566         insert apex into vertices for facet2
02567       add vertices of facet2 to qh.new_vertexlist if necessary
02568       add apex to qh.new_vertexlist if necessary
02569       for each vertex of facet1
02570         if apex
02571           rename facet1 to facet2 in its vertex neighbors
02572         else
02573           delete facet1 from vertex neighors
02574           if only in facet2
02575             add vertex to qh.del_vertices for later deletion
02576       for each ridge of facet1
02577         delete ridges between facet1 and facet2
02578         append other ridges to facet2 after renaming facet to facet2
02579 */
02580 void qh_mergesimplex(facetT *facet1, facetT *facet2, boolT mergeapex) {
02581   vertexT *vertex, **vertexp, *apex;
02582   ridgeT *ridge, **ridgep;
02583   boolT issubset= False;
02584   int vertex_i= -1, vertex_n;
02585   facetT *neighbor, **neighborp, *otherfacet;
02586 
02587   if (mergeapex) {
02588     if (!facet2->newfacet)
02589       qh_newvertices (facet2->vertices);  /* apex is new */
02590     apex= SETfirstt_(facet1->vertices, vertexT);
02591     if (SETfirstt_(facet2->vertices, vertexT) != apex) 
02592       qh_setaddnth (&facet2->vertices, 0, apex);  /* apex has last id */
02593     else
02594       issubset= True;
02595   }else {
02596     zinc_(Zmergesimplex);
02597     FOREACHvertex_(facet1->vertices)
02598       vertex->seen= False;
02599     FOREACHridge_(facet1->ridges) {
02600       if (otherfacet_(ridge, facet1) == facet2) {
02601         FOREACHvertex_(ridge->vertices) {
02602           vertex->seen= True;
02603           vertex->delridge= True;
02604         }
02605         break;
02606       }
02607     }
02608     FOREACHvertex_(facet1->vertices) {
02609       if (!vertex->seen)
02610         break;  /* must occur */
02611     }
02612     apex= vertex;
02613     trace4((qh ferr, "qh_mergesimplex: merge apex v%d of f%d into facet f%d\n",
02614           apex->id, facet1->id, facet2->id));
02615     FOREACHvertex_i_(facet2->vertices) {
02616       if (vertex->id < apex->id) {
02617         break;
02618       }else if (vertex->id == apex->id) {
02619         issubset= True;
02620         break;
02621       }
02622     }
02623     if (!issubset)
02624       qh_setaddnth (&facet2->vertices, vertex_i, apex);
02625     if (!facet2->newfacet)
02626       qh_newvertices (facet2->vertices);
02627     else if (!apex->newlist) {
02628       qh_removevertex (apex);
02629       qh_appendvertex (apex);
02630     }
02631   }
02632   trace4((qh ferr, "qh_mergesimplex: update vertex neighbors of f%d\n",
02633           facet1->id));
02634   FOREACHvertex_(facet1->vertices) {
02635     if (vertex == apex && !issubset)
02636       qh_setreplace (vertex->neighbors, facet1, facet2);
02637     else {
02638       qh_setdel (vertex->neighbors, facet1);
02639       if (!SETsecond_(vertex->neighbors))
02640         qh_mergevertex_del (vertex, facet1, facet2);
02641     }
02642   }
02643   trace4((qh ferr, "qh_mergesimplex: merge ridges and neighbors of f%d into f%d\n",
02644           facet1->id, facet2->id));
02645   qh visit_id++;
02646   FOREACHneighbor_(facet2)
02647     neighbor->visitid= qh visit_id;
02648   FOREACHridge_(facet1->ridges) {
02649     otherfacet= otherfacet_(ridge, facet1);
02650     if (otherfacet == facet2) {
02651       qh_setdel (facet2->ridges, ridge);
02652       qh_setfree(&(ridge->vertices)); 
02653       qh_memfree (ridge, sizeof(ridgeT));
02654       qh_setdel (facet2->neighbors, facet1);
02655     }else {
02656       qh_setappend (&facet2->ridges, ridge);
02657       if (otherfacet->visitid != qh visit_id) {
02658         qh_setappend (&facet2->neighbors, otherfacet);
02659         qh_setreplace (otherfacet->neighbors, facet1, facet2);
02660         otherfacet->visitid= qh visit_id;
02661       }else {
02662         if (otherfacet->simplicial)    /* is degen, needs ridges */
02663           qh_makeridges (otherfacet);
02664         if (SETfirstt_(otherfacet->neighbors, facetT) != facet1)
02665           qh_setdel (otherfacet->neighbors, facet1);
02666         else {   /*keep newfacet->neighbors->horizon*/
02667           qh_setdel(otherfacet->neighbors, facet2);
02668           qh_setreplace(otherfacet->neighbors, facet1, facet2);
02669         }
02670       }
02671       if (ridge->top == facet1) /* wait until after qh_makeridges */
02672         ridge->top= facet2;
02673       else 
02674         ridge->bottom= facet2;
02675     }
02676   }
02677   SETfirst_(facet1->ridges)= NULL; /* it will be deleted */
02678   trace3((qh ferr, "qh_mergesimplex: merged simplex f%d apex v%d into facet f%d\n",
02679           facet1->id, getid_(apex), facet2->id));
02680 } /* mergesimplex */
02681 
02682 /*-<a                             href="qh-merge.htm#TOC"
02683   >-------------------------------</a><a name="mergevertex_del">-</a>
02684   
02685   qh_mergevertex_del( vertex, facet1, facet2 )
02686     delete a vertex because of merging facet1 into facet2
02687 
02688   returns:
02689     deletes vertex from facet2
02690     adds vertex to qh.del_vertices for later deletion 
02691 */
02692 void qh_mergevertex_del (vertexT *vertex, facetT *facet1, facetT *facet2) {
02693 
02694   zinc_(Zmergevertex);
02695   trace2((qh ferr, "qh_mergevertex_del: deleted v%d when merging f%d into f%d\n",
02696           vertex->id, facet1->id, facet2->id));
02697   qh_setdelsorted (facet2->vertices, vertex);
02698   vertex->deleted= True;
02699   qh_setappend (&qh del_vertices, vertex);
02700 } /* mergevertex_del */
02701 
02702 /*-<a                             href="qh-merge.htm#TOC"
02703   >-------------------------------</a><a name="mergevertex_neighbors">-</a>
02704   
02705   qh_mergevertex_neighbors( facet1, facet2 )
02706     merge the vertex neighbors of facet1 to facet2
02707 
02708   returns:
02709     if vertex is current qh.vertex_visit
02710       deletes facet1 from vertex->neighbors
02711     else
02712       renames facet1 to facet2 in vertex->neighbors 
02713     deletes vertices if only one neighbor
02714   
02715   notes:
02716     assumes vertex neighbor sets are good
02717 */
02718 void qh_mergevertex_neighbors(facetT *facet1, facetT *facet2) {
02719   vertexT *vertex, **vertexp;
02720 
02721   trace4((qh ferr, "qh_mergevertex_neighbors: merge vertex neighbors of f%d and f%d\n",
02722           facet1->id, facet2->id));
02723   if (qh tracevertex) {
02724     fprintf (qh ferr, "qh_mergevertex_neighbors: of f%d and f%d at furthest p%d f0= %p\n",
02725              facet1->id, facet2->id, qh furthest_id, qh tracevertex->neighbors->e[0].p);
02726     qh_errprint ("TRACE", NULL, NULL, NULL, qh tracevertex);
02727   }
02728   FOREACHvertex_(facet1->vertices) {
02729     if (vertex->visitid != qh vertex_visit) 
02730       qh_setreplace(vertex->neighbors, facet1, facet2);
02731     else {
02732       qh_setdel(vertex->neighbors, facet1);
02733       if (!SETsecond_(vertex->neighbors))
02734         qh_mergevertex_del (vertex, facet1, facet2);
02735     }
02736   }
02737   if (qh tracevertex) 
02738     qh_errprint ("TRACE", NULL, NULL, NULL, qh tracevertex);
02739 } /* mergevertex_neighbors */
02740 
02741 
02742 /*-<a                             href="qh-merge.htm#TOC"
02743   >-------------------------------</a><a name="mergevertices">-</a>
02744   
02745   qh_mergevertices( vertices1, vertices2 )
02746     merges the vertex set of facet1 into facet2
02747 
02748   returns:
02749     replaces vertices2 with merged set
02750     preserves vertex_visit for qh_mergevertex_neighbors
02751     updates qh.newvertex_list
02752 
02753   design:
02754     create a merged set of both vertices (in inverse id order)
02755 */
02756 void qh_mergevertices(setT *vertices1, setT **vertices2) {
02757   int newsize= qh_setsize(vertices1)+qh_setsize(*vertices2) - qh hull_dim + 1;
02758   setT *mergedvertices;
02759   vertexT *vertex, **vertexp, **vertex2= SETaddr_(*vertices2, vertexT);
02760 
02761   mergedvertices= qh_settemp (newsize);
02762   FOREACHvertex_(vertices1) {
02763     if (!*vertex2 || vertex->id > (*vertex2)->id)
02764       qh_setappend (&mergedvertices, vertex);
02765     else {
02766       while (*vertex2 && (*vertex2)->id > vertex->id)
02767         qh_setappend (&mergedvertices, *vertex2++);
02768       if (!*vertex2 || (*vertex2)->id < vertex->id)
02769         qh_setappend (&mergedvertices, vertex);
02770       else
02771         qh_setappend (&mergedvertices, *vertex2++);
02772     }
02773   }
02774   while (*vertex2)
02775     qh_setappend (&mergedvertices, *vertex2++);
02776   if (newsize < qh_setsize (mergedvertices)) {
02777     fprintf (qh ferr, "qhull internal error (qh_mergevertices): facets did not share a ridge\n");
02778     qh_errexit (qh_ERRqhull, NULL, NULL);
02779   }
02780   qh_setfree(vertices2);
02781   *vertices2= mergedvertices;
02782   qh_settemppop ();
02783 } /* mergevertices */
02784 
02785 
02786 /*-<a                             href="qh-merge.htm#TOC"
02787   >-------------------------------</a><a name="neighbor_intersections">-</a>
02788   
02789   qh_neighbor_intersections( vertex )
02790     return intersection of all vertices in vertex->neighbors except for vertex
02791 
02792   returns:
02793     returns temporary set of vertices
02794     does not include vertex
02795     NULL if a neighbor is simplicial
02796     NULL if empty set
02797     
02798   notes:
02799     used for renaming vertices
02800 
02801   design:
02802     initialize the intersection set with vertices of the first two neighbors
02803     delete vertex from the intersection
02804     for each remaining neighbor
02805       intersect its vertex set with the intersection set
02806       return NULL if empty
02807     return the intersection set  
02808 */
02809 setT *qh_neighbor_intersections (vertexT *vertex) {
02810   facetT *neighbor, **neighborp, *neighborA, *neighborB;
02811   setT *intersect;
02812   int neighbor_i, neighbor_n;
02813 
02814   FOREACHneighbor_(vertex) {
02815     if (neighbor->simplicial)
02816       return NULL;
02817   }
02818   neighborA= SETfirstt_(vertex->neighbors, facetT);
02819   neighborB= SETsecondt_(vertex->neighbors, facetT);
02820   zinc_(Zintersectnum);
02821   if (!neighborA)
02822     return NULL;
02823   if (!neighborB)
02824     intersect= qh_setcopy (neighborA->vertices, 0);
02825   else
02826     intersect= qh_vertexintersect_new (neighborA->vertices, neighborB->vertices);
02827   qh_settemppush (intersect);
02828   qh_setdelsorted (intersect, vertex);
02829   FOREACHneighbor_i_(vertex) {
02830     if (neighbor_i >= 2) {
02831       zinc_(Zintersectnum);
02832       qh_vertexintersect (&intersect, neighbor->vertices);
02833       if (!SETfirst_(intersect)) {
02834         zinc_(Zintersectfail);
02835         qh_settempfree (&intersect);
02836         return NULL;
02837       }
02838     }
02839   }
02840   trace3((qh ferr, "qh_neighbor_intersections: %d vertices in neighbor intersection of v%d\n", 
02841           qh_setsize (intersect), vertex->id));
02842   return intersect;
02843 } /* neighbor_intersections */
02844 
02845 /*-<a                             href="qh-merge.htm#TOC"
02846   >-------------------------------</a><a name="newvertices">-</a>
02847   
02848   qh_newvertices( vertices )
02849     add vertices to end of qh.vertex_list (marks as new vertices)
02850 
02851   returns:
02852     vertices on qh.newvertex_list
02853     vertex->newlist set
02854 */
02855 void qh_newvertices (setT *vertices) {
02856   vertexT *vertex, **vertexp;
02857 
02858   FOREACHvertex_(vertices) {
02859     if (!vertex->newlist) {
02860       qh_removevertex (vertex);
02861       qh_appendvertex (vertex);
02862     }
02863   }
02864 } /* newvertices */
02865 
02866 /*-<a                             href="qh-merge.htm#TOC"
02867   >-------------------------------</a><a name="reducevertices">-</a>
02868   
02869   qh_reducevertices()
02870     reduce extra vertices, shared vertices, and redundant vertices
02871     facet->newmerge is set if merged since last call
02872     if !qh.MERGEvertices, only removes extra vertices
02873 
02874   returns:
02875     True if also merged degen_redundant facets
02876     vertices are renamed if possible
02877     clears facet->newmerge and vertex->delridge
02878 
02879   notes:
02880     ignored if 2-d
02881 
02882   design:
02883     merge any degenerate or redundant facets
02884     for each newly merged facet
02885       remove extra vertices
02886     if qh.MERGEvertices
02887       for each newly merged facet
02888         for each vertex
02889           if vertex was on a deleted ridge
02890             rename vertex if it is shared
02891       remove delridge flag from new vertices
02892 */
02893 boolT qh_reducevertices (void) {
02894   int numshare=0, numrename= 0;
02895   boolT degenredun= False;
02896   facetT *newfacet;
02897   vertexT *vertex, **vertexp;
02898 
02899   if (qh hull_dim == 2) 
02900     return False;
02901   if (qh_merge_degenredundant())
02902     degenredun= True;
02903  LABELrestart:
02904   FORALLnew_facets {
02905     if (newfacet->newmerge) { 
02906       if (!qh MERGEvertices)
02907         newfacet->newmerge= False;
02908       qh_remove_extravertices (newfacet);
02909     }
02910   }
02911   if (!qh MERGEvertices)
02912     return False;
02913   FORALLnew_facets {
02914     if (newfacet->newmerge) {
02915       newfacet->newmerge= False;
02916       FOREACHvertex_(newfacet->vertices) {
02917         if (vertex->delridge) {
02918           if (qh_rename_sharedvertex (vertex, newfacet)) {
02919             numshare++;
02920             vertexp--; /* repeat since deleted vertex */
02921           }
02922         }
02923       }
02924     }
02925   }
02926   FORALLvertex_(qh newvertex_list) {
02927     if (vertex->delridge && !vertex->deleted) {
02928       vertex->delridge= False;
02929       if (qh hull_dim >= 4 && qh_redundant_vertex (vertex)) {
02930         numrename++;
02931         if (qh_merge_degenredundant()) {
02932           degenredun= True;
02933           goto LABELrestart;
02934         }
02935       }
02936     }
02937   }
02938   trace1((qh ferr, "qh_reducevertices: renamed %d shared vertices and %d redundant vertices. Degen? %d\n",
02939           numshare, numrename, degenredun));
02940   return degenredun;
02941 } /* reducevertices */
02942       
02943 /*-<a                             href="qh-merge.htm#TOC"
02944   >-------------------------------</a><a name="redundant_vertex">-</a>
02945   
02946   qh_redundant_vertex( vertex )
02947     detect and rename a redundant vertex
02948     vertices have full vertex->neighbors 
02949 
02950   returns:
02951     returns true if find a redundant vertex
02952       deletes vertex (vertex->deleted)
02953   
02954   notes:
02955     only needed if vertex->delridge and hull_dim >= 4
02956     may add degenerate facets to qh.facet_mergeset
02957     doesn't change vertex->neighbors or create redundant facets
02958 
02959   design:
02960     intersect vertices of all facet neighbors of vertex
02961     determine ridges for these vertices
02962     if find a new vertex for vertex amoung these ridges and vertices
02963       rename vertex to the new vertex
02964 */
02965 vertexT *qh_redundant_vertex (vertexT *vertex) {
02966   vertexT *newvertex= NULL;
02967   setT *vertices, *ridges;
02968 
02969   trace3((qh ferr, "qh_redundant_vertex: check if v%d can be renamed\n", vertex->id));  
02970   if ((vertices= qh_neighbor_intersections (vertex))) {
02971     ridges= qh_vertexridges (vertex);
02972     if ((newvertex= qh_find_newvertex (vertex, vertices, ridges)))
02973       qh_renamevertex (vertex, newvertex, ridges, NULL, NULL);
02974     qh_settempfree (&ridges);
02975     qh_settempfree (&vertices);
02976   }
02977   return newvertex;
02978 } /* redundant_vertex */
02979 
02980 /*-<a                             href="qh-merge.htm#TOC"
02981   >-------------------------------</a><a name="remove_extravertices">-</a>
02982   
02983   qh_remove_extravertices( facet )
02984     remove extra vertices from non-simplicial facets
02985 
02986   returns:
02987     returns True if it finds them
02988 
02989   design:
02990     for each vertex in facet
02991       if vertex not in a ridge (i.e., no longer used)
02992         delete vertex from facet
02993         delete facet from vertice's neighbors
02994         unless vertex in another facet
02995           add vertex to qh.del_vertices for later deletion
02996 */
02997 boolT qh_remove_extravertices (facetT *facet) {
02998   ridgeT *ridge, **ridgep;
02999   vertexT *vertex, **vertexp;
03000   boolT foundrem= False;
03001 
03002   trace4((qh ferr, "qh_remove_extravertices: test f%d for extra vertices\n",
03003           facet->id));
03004   FOREACHvertex_(facet->vertices)
03005     vertex->seen= False;
03006   FOREACHridge_(facet->ridges) { 
03007     FOREACHvertex_(ridge->vertices)
03008       vertex->seen= True;
03009   }
03010   FOREACHvertex_(facet->vertices) {
03011     if (!vertex->seen) {
03012       foundrem= True;
03013       zinc_(Zremvertex);
03014       qh_setdelsorted (facet->vertices, vertex);
03015       qh_setdel (vertex->neighbors, facet);
03016       if (!qh_setsize (vertex->neighbors)) {
03017         vertex->deleted= True;
03018         qh_setappend (&qh del_vertices, vertex);
03019         zinc_(Zremvertexdel);
03020         trace2((qh ferr, "qh_remove_extravertices: v%d deleted because it's lost all ridges\n", vertex->id));
03021       }else
03022         trace3((qh ferr, "qh_remove_extravertices: v%d removed from f%d because it's lost all ridges\n", vertex->id, facet->id));
03023       vertexp--; /*repeat*/
03024     }
03025   }
03026   return foundrem;
03027 } /* remove_extravertices */
03028 
03029 /*-<a                             href="qh-merge.htm#TOC"
03030   >-------------------------------</a><a name="rename_sharedvertex">-</a>
03031   
03032   qh_rename_sharedvertex( vertex, facet )
03033     detect and rename if shared vertex in facet
03034     vertices have full ->neighbors
03035 
03036   returns:
03037     newvertex or NULL
03038     the vertex may still exist in other facets (i.e., a neighbor was pinched)
03039     does not change facet->neighbors
03040     updates vertex->neighbors
03041   
03042   notes:
03043     a shared vertex for a facet is only in ridges to one neighbor
03044     this may undo a pinched facet
03045  
03046     it does not catch pinches involving multiple facets.  These appear
03047       to be difficult to detect, since an exhaustive search is too expensive.
03048 
03049   design:
03050     if vertex only has two neighbors
03051       determine the ridges that contain the vertex
03052       determine the vertices shared by both neighbors
03053       if can find a new vertex in this set
03054         rename the vertex to the new vertex
03055 */
03056 vertexT *qh_rename_sharedvertex (vertexT *vertex, facetT *facet) {
03057   facetT *neighbor, **neighborp, *neighborA= NULL;
03058   setT *vertices, *ridges;
03059   vertexT *newvertex;
03060 
03061   if (qh_setsize (vertex->neighbors) == 2) {
03062     neighborA= SETfirstt_(vertex->neighbors, facetT);
03063     if (neighborA == facet)
03064       neighborA= SETsecondt_(vertex->neighbors, facetT);
03065   }else if (qh hull_dim == 3)
03066     return NULL;
03067   else {
03068     qh visit_id++;
03069     FOREACHneighbor_(facet)
03070       neighbor->visitid= qh visit_id;
03071     FOREACHneighbor_(vertex) {
03072       if (neighbor->visitid == qh visit_id) {
03073         if (neighborA)
03074           return NULL;
03075         neighborA= neighbor;
03076       }
03077     }
03078     if (!neighborA) {
03079       fprintf (qh ferr, "qhull internal error (qh_rename_sharedvertex): v%d's neighbors not in f%d\n",
03080         vertex->id, facet->id);
03081       qh_errprint ("ERRONEOUS", facet, NULL, NULL, vertex);
03082       qh_errexit (qh_ERRqhull, NULL, NULL);
03083     }
03084   }
03085   /* the vertex is shared by facet and neighborA */
03086   ridges= qh_settemp (qh TEMPsize);
03087   neighborA->visitid= ++qh visit_id;
03088   qh_vertexridges_facet (vertex, facet, &ridges);
03089   trace2((qh ferr, "qh_rename_sharedvertex: p%d (v%d) is shared by f%d (%d ridges) and f%d\n",
03090     qh_pointid(vertex->point), vertex->id, facet->id, qh_setsize (ridges), neighborA->id));
03091   zinc_(Zintersectnum);
03092   vertices= qh_vertexintersect_new (facet->vertices, neighborA->vertices);
03093   qh_setdel (vertices, vertex);
03094   qh_settemppush (vertices);
03095   if ((newvertex= qh_find_newvertex (vertex, vertices, ridges))) 
03096     qh_renamevertex (vertex, newvertex, ridges, facet, neighborA);
03097   qh_settempfree (&vertices);
03098   qh_settempfree (&ridges);
03099   return newvertex;
03100 } /* rename_sharedvertex */
03101 
03102 /*-<a                             href="qh-merge.htm#TOC"
03103   >-------------------------------</a><a name="renameridgevertex">-</a>
03104   
03105   qh_renameridgevertex( ridge, oldvertex, newvertex )
03106     renames oldvertex as newvertex in ridge
03107 
03108   returns:
03109   
03110   design:
03111     delete oldvertex from ridge
03112     if newvertex already in ridge
03113       copy ridge->noconvex to another ridge if possible
03114       delete the ridge
03115     else
03116       insert newvertex into the ridge
03117       adjust the ridge's orientation
03118 */
03119 void qh_renameridgevertex(ridgeT *ridge, vertexT *oldvertex, vertexT *newvertex) {
03120   int nth= 0, oldnth;
03121   facetT *temp;
03122   vertexT *vertex, **vertexp;
03123 
03124   oldnth= qh_setindex (ridge->vertices, oldvertex);
03125   qh_setdelnthsorted (ridge->vertices, oldnth);
03126   FOREACHvertex_(ridge->vertices) {
03127     if (vertex == newvertex) {
03128       zinc_(Zdelridge);
03129       if (ridge->nonconvex) /* only one ridge has nonconvex set */
03130         qh_copynonconvex (ridge);
03131       qh_delridge (ridge);
03132       trace2((qh ferr, "qh_renameridgevertex: ridge r%d deleted.  It contained both v%d and v%d\n",
03133         ridge->id, oldvertex->id, newvertex->id));
03134       return;
03135     }
03136     if (vertex->id < newvertex->id)
03137       break;
03138     nth++;
03139   }
03140   qh_setaddnth(&ridge->vertices, nth, newvertex);
03141   if (abs(oldnth - nth)%2) {
03142     trace3((qh ferr, "qh_renameridgevertex: swapped the top and bottom of ridge r%d\n", 
03143             ridge->id));
03144     temp= ridge->top;
03145     ridge->top= ridge->bottom;
03146     ridge->bottom= temp;
03147   }
03148 } /* renameridgevertex */
03149 
03150 
03151 /*-<a                             href="qh-merge.htm#TOC"
03152   >-------------------------------</a><a name="renamevertex">-</a>
03153   
03154   qh_renamevertex( oldvertex, newvertex, ridges, oldfacet, neighborA )
03155     renames oldvertex as newvertex in ridges 
03156     gives oldfacet/neighborA if oldvertex is shared between two facets
03157 
03158   returns:
03159     oldvertex may still exist afterwards
03160     
03161 
03162   notes:
03163     can not change neighbors of newvertex (since it's a subset)
03164 
03165   design:
03166     for each ridge in ridges
03167       rename oldvertex to newvertex and delete degenerate ridges
03168     if oldfacet not defined
03169       for each neighbor of oldvertex
03170         delete oldvertex from neighbor's vertices
03171         remove extra vertices from neighbor
03172       add oldvertex to qh.del_vertices
03173     else if oldvertex only between oldfacet and neighborA
03174       delete oldvertex from oldfacet and neighborA
03175       add oldvertex to qh.del_vertices
03176     else oldvertex is in oldfacet and neighborA and other facets (i.e., pinched)
03177       delete oldvertex from oldfacet
03178       delete oldfacet from oldvertice's neighbors
03179       remove extra vertices (e.g., oldvertex) from neighborA
03180 */
03181 void qh_renamevertex(vertexT *oldvertex, vertexT *newvertex, setT *ridges, facetT *oldfacet, facetT *neighborA) {
03182   facetT *neighbor, **neighborp;
03183   ridgeT *ridge, **ridgep;
03184   boolT istrace= False;
03185 
03186   if (qh IStracing >= 2 || oldvertex->id == qh tracevertex_id ||
03187         newvertex->id == qh tracevertex_id)
03188     istrace= True;
03189   FOREACHridge_(ridges) 
03190     qh_renameridgevertex (ridge, oldvertex, newvertex);
03191   if (!oldfacet) {
03192     zinc_(Zrenameall);
03193     if (istrace)
03194       fprintf (qh ferr, "qh_renamevertex: renamed v%d to v%d in several facets\n",
03195                oldvertex->id, newvertex->id);
03196     FOREACHneighbor_(oldvertex) {
03197       qh_maydropneighbor (neighbor);
03198       qh_setdelsorted (neighbor->vertices, oldvertex);
03199       if (qh_remove_extravertices (neighbor))
03200         neighborp--; /* neighbor may be deleted */
03201     }
03202     if (!oldvertex->deleted) {
03203       oldvertex->deleted= True;
03204       qh_setappend (&qh del_vertices, oldvertex);
03205     }
03206   }else if (qh_setsize (oldvertex->neighbors) == 2) {
03207     zinc_(Zrenameshare);
03208     if (istrace)
03209       fprintf (qh ferr, "qh_renamevertex: renamed v%d to v%d in oldfacet f%d\n", 
03210                oldvertex->id, newvertex->id, oldfacet->id);
03211     FOREACHneighbor_(oldvertex)
03212       qh_setdelsorted (neighbor->vertices, oldvertex);
03213     oldvertex->deleted= True;
03214     qh_setappend (&qh del_vertices, oldvertex);
03215   }else {
03216     zinc_(Zrenamepinch);
03217     if (istrace || qh IStracing)
03218       fprintf (qh ferr, "qh_renamevertex: renamed pinched v%d to v%d between f%d and f%d\n", 
03219                oldvertex->id, newvertex->id, oldfacet->id, neighborA->id);
03220     qh_setdelsorted (oldfacet->vertices, oldvertex);
03221     qh_setdel (oldvertex->neighbors, oldfacet);
03222     qh_remove_extravertices (neighborA);
03223   }
03224 } /* renamevertex */
03225 
03226 
03227 /*-<a                             href="qh-merge.htm#TOC"
03228   >-------------------------------</a><a name="test_appendmerge">-</a>
03229   
03230   qh_test_appendmerge( facet, neighbor )
03231     tests facet/neighbor for convexity
03232     appends to mergeset if non-convex
03233     if pre-merging, 
03234       nop if qh.SKIPconvex, or qh.MERGEexact and coplanar
03235 
03236   returns:
03237     true if appends facet/neighbor to mergeset
03238     sets facet->center as needed
03239     does not change facet->seen
03240 
03241   design:
03242     if qh.cos_max is defined
03243       if the angle between facet normals is too shallow
03244         append an angle-coplanar merge to qh.mergeset
03245         return True
03246     make facet's centrum if needed
03247     if facet's centrum is above the neighbor
03248       set isconcave
03249     else
03250       if facet's centrum is not below the neighbor
03251         set iscoplanar
03252       make neighbor's centrum if needed
03253       if neighbor's centrum is above the facet
03254         set isconcave
03255       else if neighbor's centrum is not below the facet
03256         set iscoplanar
03257    if isconcave or iscoplanar
03258      get angle if needed
03259      append concave or coplanar merge to qh.mergeset
03260 */
03261 boolT qh_test_appendmerge (facetT *facet, facetT *neighbor) {
03262   realT dist, dist2= -REALmax, angle= -REALmax;
03263   boolT isconcave= False, iscoplanar= False, okangle= False;
03264 
03265   if (qh SKIPconvex && !qh POSTmerging)
03266     return False;
03267   if ((!qh MERGEexact || qh POSTmerging) && qh cos_max < REALmax/2) {
03268     angle= qh_getangle(facet->normal, neighbor->normal);
03269     zinc_(Zangletests);
03270     if (angle > qh cos_max) {
03271       zinc_(Zcoplanarangle);
03272       qh_appendmergeset(facet, neighbor, MRGanglecoplanar, &angle);
03273       trace2((qh ferr, "qh_test_appendmerge: coplanar angle %4.4g between f%d and f%d\n",
03274          angle, facet->id, neighbor->id));
03275       return True;
03276     }else
03277       okangle= True;
03278   }
03279   if (!facet->center)
03280     facet->center= qh_getcentrum (facet);
03281   zzinc_(Zcentrumtests);
03282   qh_distplane(facet->center, neighbor, &dist);
03283   if (dist > qh centrum_radius)
03284     isconcave= True;
03285   else {
03286     if (dist > -qh centrum_radius)
03287       iscoplanar= True;
03288     if (!neighbor->center)
03289       neighbor->center= qh_getcentrum (neighbor);
03290     zzinc_(Zcentrumtests);
03291     qh_distplane(neighbor->center, facet, &dist2);
03292     if (dist2 > qh centrum_radius)
03293       isconcave= True;
03294     else if (!iscoplanar && dist2 > -qh centrum_radius)
03295       iscoplanar= True;
03296   }
03297   if (!isconcave && (!iscoplanar || (qh MERGEexact && !qh POSTmerging)))
03298     return False;
03299   if (!okangle && qh ANGLEmerge) {
03300     angle= qh_getangle(facet->normal, neighbor->normal);
03301     zinc_(Zangletests);
03302   }
03303   if (isconcave) {
03304     zinc_(Zconcaveridge);
03305     if (qh ANGLEmerge)
03306       angle += qh_ANGLEconcave + 0.5;
03307     qh_appendmergeset(facet, neighbor, MRGconcave, &angle);
03308     trace0((qh ferr, "qh_test_appendmerge: concave f%d to f%d dist %4.4g and reverse dist %4.4g angle %4.4g during p%d\n",
03309            facet->id, neighbor->id, dist, dist2, angle, qh furthest_id));
03310   }else /* iscoplanar */ {
03311     zinc_(Zcoplanarcentrum);
03312     qh_appendmergeset(facet, neighbor, MRGcoplanar, &angle);
03313     trace2((qh ferr, "qh_test_appendmerge: coplanar f%d to f%d dist %4.4g, reverse dist %4.4g angle %4.4g\n",
03314               facet->id, neighbor->id, dist, dist2, angle));
03315   }
03316   return True;
03317 } /* test_appendmerge */
03318 
03319 /*-<a                             href="qh-merge.htm#TOC"
03320   >-------------------------------</a><a name="test_vneighbors">-</a>
03321   
03322   qh_test_vneighbors()
03323     test vertex neighbors for convexity
03324     tests all facets on qh.newfacet_list
03325 
03326   returns:
03327     true if non-convex vneighbors appended to qh.facet_mergeset
03328     initializes vertex neighbors if needed
03329 
03330   notes:
03331     assumes all facet neighbors have been tested
03332     this can be expensive
03333     this does not guarantee that a centrum is below all facets
03334       but it is unlikely
03335     uses qh.visit_id
03336 
03337   design:
03338     build vertex neighbors if necessary
03339     for all new facets
03340       for all vertices
03341         for each unvisited facet neighbor of the vertex
03342           test new facet and neighbor for convexity
03343 */
03344 boolT qh_test_vneighbors (void /* qh newfacet_list */) {
03345   facetT *newfacet, *neighbor, **neighborp;
03346   vertexT *vertex, **vertexp;
03347   int nummerges= 0;
03348 
03349   trace1((qh ferr, "qh_test_vneighbors: testing vertex neighbors for convexity\n"));
03350   if (!qh VERTEXneighbors)
03351     qh_vertexneighbors();
03352   FORALLnew_facets 
03353     newfacet->seen= False;
03354   FORALLnew_facets {
03355     newfacet->seen= True;
03356     newfacet->visitid= qh visit_id++;
03357     FOREACHneighbor_(newfacet)
03358       newfacet->visitid= qh visit_id;
03359     FOREACHvertex_(newfacet->vertices) {
03360       FOREACHneighbor_(vertex) {
03361         if (neighbor->seen || neighbor->visitid == qh visit_id)
03362           continue;
03363         if (qh_test_appendmerge (newfacet, neighbor))
03364           nummerges++;
03365       }
03366     }
03367   }
03368   zadd_(Ztestvneighbor, nummerges);
03369   trace1((qh ferr, "qh_test_vneighbors: found %d non-convex, vertex neighbors\n",
03370            nummerges));
03371   return (nummerges > 0);    
03372 } /* test_vneighbors */
03373 
03374 /*-<a                             href="qh-merge.htm#TOC"
03375   >-------------------------------</a><a name="tracemerge">-</a>
03376   
03377   qh_tracemerge( facet1, facet2 )
03378     print trace message after merge
03379 */
03380 void qh_tracemerge (facetT *facet1, facetT *facet2) {
03381   boolT waserror= False;
03382 
03383 #ifndef qh_NOtrace
03384   if (qh IStracing >= 4) 
03385     qh_errprint ("MERGED", facet2, NULL, NULL, NULL);
03386   if (facet2 == qh tracefacet || (qh tracevertex && qh tracevertex->newlist)) {
03387     fprintf (qh ferr, "qh_tracemerge: trace facet and vertex after merge of f%d and f%d, furthest p%d\n", facet1->id, facet2->id, qh furthest_id);
03388     if (facet2 != qh tracefacet)
03389       qh_errprint ("TRACE", qh tracefacet, 
03390         (qh tracevertex && qh tracevertex->neighbors) ? 
03391            SETfirstt_(qh tracevertex->neighbors, facetT) : NULL,
03392         NULL, qh tracevertex);      
03393   }
03394   if (qh tracevertex) {
03395     if (qh tracevertex->deleted)
03396       fprintf (qh ferr, "qh_tracemerge: trace vertex deleted at furthest p%d\n",
03397             qh furthest_id);
03398     else
03399       qh_checkvertex (qh tracevertex);
03400   }
03401   if (qh tracefacet) {
03402     qh_checkfacet (qh tracefacet, True, &waserror);
03403     if (waserror)
03404       qh_errexit (qh_ERRqhull, qh tracefacet, NULL);
03405   }
03406 #endif /* !qh_NOtrace */
03407   if (qh CHECKfrequently || qh IStracing >= 4) { /* can't check polygon here */
03408     qh_checkfacet (facet2, True, &waserror);
03409     if (waserror)
03410       qh_errexit(qh_ERRqhull, NULL, NULL);
03411   }
03412 } /* tracemerge */
03413 
03414 /*-<a                             href="qh-merge.htm#TOC"
03415   >-------------------------------</a><a name="tracemerging">-</a>
03416   
03417   qh_tracemerging()
03418     print trace message during POSTmerging
03419 
03420   returns:
03421     updates qh.mergereport
03422   
03423   notes:
03424     called from qh_mergecycle() and qh_mergefacet()
03425   
03426   see:
03427     qh_buildtracing()
03428 */
03429 void qh_tracemerging (void) {
03430   realT cpu;
03431   int total;
03432   time_t timedata;
03433   struct tm *tp;
03434 
03435   qh mergereport= zzval_(Ztotmerge);
03436   time (&timedata);
03437   tp= localtime (&timedata);
03438   cpu= qh_CPUclock;
03439   cpu /= qh_SECticks;
03440   total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
03441   fprintf (qh ferr, "\n\
03442 At %d:%d:%d & %2.5g CPU secs, qhull has merged %d facets.  The hull\n\
03443   contains %d facets and %d vertices.\n",
03444       tp->tm_hour, tp->tm_min, tp->tm_sec, cpu,
03445       total, qh num_facets - qh num_visible,
03446       qh num_vertices-qh_setsize (qh del_vertices));
03447 } /* tracemerging */
03448 
03449 /*-<a                             href="qh-merge.htm#TOC"
03450   >-------------------------------</a><a name="updatetested">-</a>
03451   
03452   qh_updatetested( facet1, facet2 )
03453     clear facet2->tested and facet1->ridge->tested for merge
03454 
03455   returns:
03456     deletes facet2->center unless it's already large
03457       if so, clears facet2->ridge->tested
03458 
03459   design:
03460     clear facet2->tested
03461     clear ridge->tested for facet1's ridges
03462     if facet2 has a centrum
03463       if facet2 is large
03464         set facet2->keepcentrum 
03465       else if facet2 has 3 vertices due to many merges, or not large and post merging
03466         clear facet2->keepcentrum
03467       unless facet2->keepcentrum
03468         clear facet2->center to recompute centrum later
03469         clear ridge->tested for facet2's ridges
03470 */
03471 void qh_updatetested (facetT *facet1, facetT *facet2) {
03472   ridgeT *ridge, **ridgep;
03473   int size;
03474   
03475   facet2->tested= False;
03476   FOREACHridge_(facet1->ridges)
03477     ridge->tested= False;
03478   if (!facet2->center)
03479     return;
03480   size= qh_setsize (facet2->vertices);
03481   if (!facet2->keepcentrum) {
03482     if (size > qh hull_dim + qh_MAXnewcentrum) {
03483       facet2->keepcentrum= True;
03484       zinc_(Zwidevertices);
03485     }
03486   }else if (size <= qh hull_dim + qh_MAXnewcentrum) {
03487     /* center and keepcentrum was set */
03488     if (size == qh hull_dim || qh POSTmerging)
03489       facet2->keepcentrum= False; /* if many merges need to recompute centrum */
03490   }
03491   if (!facet2->keepcentrum) {
03492     qh_memfree (facet2->center, qh normal_size);
03493     facet2->center= NULL;
03494     FOREACHridge_(facet2->ridges)
03495       ridge->tested= False;
03496   }
03497 } /* updatetested */
03498 
03499 /*-<a                             href="qh-merge.htm#TOC"
03500   >-------------------------------</a><a name="vertexridges">-</a>
03501   
03502   qh_vertexridges( vertex )
03503     return temporary set of ridges adjacent to a vertex
03504     vertex->neighbors defined
03505 
03506   ntoes:
03507     uses qh.visit_id
03508     does not include implicit ridges for simplicial facets
03509 
03510   design:
03511     for each neighbor of vertex
03512       add ridges that include the vertex to ridges  
03513 */
03514 setT *qh_vertexridges (vertexT *vertex) {
03515   facetT *neighbor, **neighborp;
03516   setT *ridges= qh_settemp (qh TEMPsize);
03517   int size;
03518 
03519   qh visit_id++;
03520   FOREACHneighbor_(vertex)
03521     neighbor->visitid= qh visit_id;
03522   FOREACHneighbor_(vertex) {
03523     if (*neighborp)   /* no new ridges in last neighbor */
03524       qh_vertexridges_facet (vertex, neighbor, &ridges);
03525   }
03526   if (qh PRINTstatistics || qh IStracing) {
03527     size= qh_setsize (ridges);
03528     zinc_(Zvertexridge);
03529     zadd_(Zvertexridgetot, size);
03530     zmax_(Zvertexridgemax, size);
03531     trace3((qh ferr, "qh_vertexridges: found %d ridges for v%d\n",
03532              size, vertex->id));
03533   }
03534   return ridges;
03535 } /* vertexridges */
03536 
03537 /*-<a                             href="qh-merge.htm#TOC"
03538   >-------------------------------</a><a name="vertexridges_facet">-</a>
03539   
03540   qh_vertexridges_facet( vertex, facet, ridges )
03541     add adjacent ridges for vertex in facet
03542     neighbor->visitid==qh.visit_id if it hasn't been visited
03543 
03544   returns:
03545     ridges updated
03546     sets facet->visitid to qh.visit_id-1
03547 
03548   design:
03549     for each ridge of facet
03550       if ridge of visited neighbor (i.e., unprocessed)
03551         if vertex in ridge
03552           append ridge to vertex
03553     mark facet processed
03554 */
03555 void qh_vertexridges_facet (vertexT *vertex, facetT *facet, setT **ridges) {
03556   ridgeT *ridge, **ridgep;
03557   facetT *neighbor;
03558 
03559   FOREACHridge_(facet->ridges) {
03560     neighbor= otherfacet_(ridge, facet);
03561     if (neighbor->visitid == qh visit_id 
03562     && qh_setin (ridge->vertices, vertex))
03563       qh_setappend (ridges, ridge);
03564   }
03565   facet->visitid= qh visit_id-1;
03566 } /* vertexridges_facet */
03567 
03568 /*-<a                             href="qh-merge.htm#TOC"
03569   >-------------------------------</a><a name="willdelete">-</a>
03570   
03571   qh_willdelete( facet, replace )
03572     moves facet to visible list
03573     sets facet->f.replace to replace (may be NULL)
03574 
03575   returns:
03576     bumps qh.num_visible
03577 */
03578 void qh_willdelete (facetT *facet, facetT *replace) {
03579 
03580   qh_removefacet(facet);
03581   qh_prependfacet (facet, &qh visible_list);
03582   qh num_visible++;
03583   facet->visible= True;
03584   facet->f.replace= replace;
03585 } /* willdelete */
03586 
03587 #else /* qh_NOmerge */
03588 void qh_premerge (vertexT *apex, realT maxcentrum, realT maxangle) {
03589 }
03590 void qh_postmerge (char *reason, realT maxcentrum, realT maxangle, 
03591                       boolT vneighbors) {
03592 }
03593 boolT qh_checkzero (boolT testall) {
03594    }
03595 #endif /* qh_NOmerge */
03596 
 

Powered by Plone

This site conforms to the following standards: