~diresu/blender/blender-command-port

« back to all changes in this revision

Viewing changes to extern/qhull/src/poly2.c

  • Committer: theeth
  • Date: 2008-10-14 16:52:04 UTC
  • Revision ID: vcs-imports@canonical.com-20081014165204-r32w2gm6s0osvdhn
copy back trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*<html><pre>  -<a                             href="qh-poly.htm"
 
2
  >-------------------------------</a><a name="TOP">-</a>
 
3
 
 
4
   poly2.c 
 
5
   implements polygons and simplices
 
6
 
 
7
   see qh-poly.htm, poly.h and qhull.h
 
8
 
 
9
   frequently used code is in poly.c
 
10
 
 
11
   copyright (c) 1993-2002, The Geometry Center
 
12
*/
 
13
 
 
14
#include "qhull_a.h"
 
15
 
 
16
/*======== functions in alphabetical order ==========*/
 
17
 
 
18
/*-<a                             href="qh-poly.htm#TOC"
 
19
  >-------------------------------</a><a name="addhash">-</a>
 
20
  
 
21
  qh_addhash( newelem, hashtable, hashsize, hash )
 
22
    add newelem to linear hash table at hash if not already there
 
23
*/
 
24
void qh_addhash (void* newelem, setT *hashtable, int hashsize, unsigned hash) {
 
25
  int scan;
 
26
  void *elem;
 
27
 
 
28
  for (scan= (int)hash; (elem= SETelem_(hashtable, scan)); 
 
29
       scan= (++scan >= hashsize ? 0 : scan)) {
 
30
    if (elem == newelem)
 
31
      break;
 
32
  }
 
33
  /* loop terminates because qh_HASHfactor >= 1.1 by qh_initbuffers */
 
34
  if (!elem)
 
35
    SETelem_(hashtable, scan)= newelem;
 
36
} /* addhash */
 
37
 
 
38
/*-<a                             href="qh-poly.htm#TOC"
 
39
  >-------------------------------</a><a name="check_bestdist">-</a>
 
40
  
 
41
  qh_check_bestdist()
 
42
    check that all points are within max_outside of the nearest facet
 
43
    if qh.ONLYgood,
 
44
      ignores !good facets
 
45
 
 
46
  see: 
 
47
    qh_check_maxout(), qh_outerinner()
 
48
 
 
49
  notes:
 
50
    only called from qh_check_points()
 
51
      seldom used since qh.MERGING is almost always set
 
52
    if notverified>0 at end of routine
 
53
      some points were well inside the hull.  If the hull contains
 
54
      a lens-shaped component, these points were not verified.  Use
 
55
      options 'Qi Tv' to verify all points.  (Exhaustive check also verifies)
 
56
 
 
57
  design:
 
58
    determine facet for each point (if any)
 
59
    for each point
 
60
      start with the assigned facet or with the first facet
 
61
      find the best facet for the point and check all coplanar facets
 
62
      error if point is outside of facet
 
63
*/
 
64
void qh_check_bestdist (void) {
 
65
  boolT waserror= False, unassigned;
 
66
  facetT *facet, *bestfacet, *errfacet1= NULL, *errfacet2= NULL;
 
67
  facetT *facetlist; 
 
68
  realT dist, maxoutside, maxdist= -REALmax;
 
69
  pointT *point;
 
70
  int numpart= 0, facet_i, facet_n, notgood= 0, notverified= 0;
 
71
  setT *facets;
 
72
 
 
73
  trace1((qh ferr, "qh_check_bestdist: check points below nearest facet.  Facet_list f%d\n",
 
74
      qh facet_list->id));
 
75
  maxoutside= qh_maxouter();
 
76
  maxoutside += qh DISTround;
 
77
  /* one more qh.DISTround for check computation */
 
78
  trace1((qh ferr, "qh_check_bestdist: check that all points are within %2.2g of best facet\n", maxoutside));
 
79
  facets= qh_pointfacet (/*qh facet_list*/);
 
80
  if (!qh_QUICKhelp && qh PRINTprecision)
 
81
    fprintf (qh ferr, "\n\
 
82
qhull output completed.  Verifying that %d points are\n\
 
83
below %2.2g of the nearest %sfacet.\n",
 
84
             qh_setsize(facets), maxoutside, (qh ONLYgood ?  "good " : ""));
 
85
  FOREACHfacet_i_(facets) {  /* for each point with facet assignment */
 
86
    if (facet)
 
87
      unassigned= False;
 
88
    else {
 
89
      unassigned= True;
 
90
      facet= qh facet_list;
 
91
    }
 
92
    point= qh_point(facet_i);
 
93
    if (point == qh GOODpointp)
 
94
      continue;
 
95
    qh_distplane(point, facet, &dist);
 
96
    numpart++;
 
97
    bestfacet= qh_findbesthorizon (!qh_IScheckmax, point, facet, qh_NOupper, &dist, &numpart);
 
98
    /* occurs after statistics reported */
 
99
    maximize_(maxdist, dist);
 
100
    if (dist > maxoutside) {
 
101
      if (qh ONLYgood && !bestfacet->good 
 
102
          && !((bestfacet= qh_findgooddist (point, bestfacet, &dist, &facetlist))
 
103
               && dist > maxoutside))
 
104
        notgood++;
 
105
      else {
 
106
        waserror= True;
 
107
        fprintf(qh ferr, "qhull precision error: point p%d is outside facet f%d, distance= %6.8g maxoutside= %6.8g\n", 
 
108
                facet_i, bestfacet->id, dist, maxoutside);
 
109
        if (errfacet1 != bestfacet) {
 
110
          errfacet2= errfacet1;
 
111
          errfacet1= bestfacet;
 
112
        }
 
113
      }
 
114
    }else if (unassigned && dist < -qh MAXcoplanar)
 
115
      notverified++;
 
116
  }
 
117
  qh_settempfree (&facets);
 
118
  if (notverified && !qh DELAUNAY && !qh_QUICKhelp && qh PRINTprecision) 
 
119
    fprintf(qh ferr, "\n%d points were well inside the hull.  If the hull contains\n\
 
120
a lens-shaped component, these points were not verified.  Use\n\
 
121
options 'Qci Tv' to verify all points.\n", notverified); 
 
122
  if (maxdist > qh outside_err) {
 
123
    fprintf( qh ferr, "qhull precision error (qh_check_bestdist): a coplanar point is %6.2g from convex hull.  The maximum value (qh.outside_err) is %6.2g\n",
 
124
              maxdist, qh outside_err);
 
125
    qh_errexit2 (qh_ERRprec, errfacet1, errfacet2);
 
126
  }else if (waserror && qh outside_err > REALmax/2)
 
127
    qh_errexit2 (qh_ERRprec, errfacet1, errfacet2);
 
128
  else if (waserror)
 
129
    ;                       /* the error was logged to qh.ferr but does not effect the output */
 
130
  trace0((qh ferr, "qh_check_bestdist: max distance outside %2.2g\n", maxdist));
 
131
} /* check_bestdist */
 
132
 
 
133
/*-<a                             href="qh-poly.htm#TOC"
 
134
  >-------------------------------</a><a name="check_maxout">-</a>
 
135
  
 
136
  qh_check_maxout()
 
137
    updates qh.max_outside by checking all points against bestfacet
 
138
    if qh.ONLYgood, ignores !good facets
 
139
 
 
140
  returns:
 
141
    updates facet->maxoutside via qh_findbesthorizon()
 
142
    sets qh.maxoutdone
 
143
    if printing qh.min_vertex (qh_outerinner), 
 
144
      it is updated to the current vertices
 
145
    removes inside/coplanar points from coplanarset as needed
 
146
 
 
147
  notes:
 
148
    defines coplanar as min_vertex instead of MAXcoplanar 
 
149
    may not need to check near-inside points because of qh.MAXcoplanar 
 
150
      and qh.KEEPnearinside (before it was -DISTround)
 
151
 
 
152
  see also:
 
153
    qh_check_bestdist()
 
154
 
 
155
  design:
 
156
    if qh.min_vertex is needed
 
157
      for all neighbors of all vertices
 
158
        test distance from vertex to neighbor
 
159
    determine facet for each point (if any)
 
160
    for each point with an assigned facet
 
161
      find the best facet for the point and check all coplanar facets
 
162
        (updates outer planes)
 
163
    remove near-inside points from coplanar sets
 
164
*/
 
165
#ifndef qh_NOmerge
 
166
void qh_check_maxout (void) {
 
167
  facetT *facet, *bestfacet, *neighbor, **neighborp, *facetlist;
 
168
  realT dist, maxoutside, minvertex, old_maxoutside;
 
169
  pointT *point;
 
170
  int numpart= 0, facet_i, facet_n, notgood= 0;
 
171
  setT *facets, *vertices;
 
172
  vertexT *vertex;
 
173
 
 
174
  trace1((qh ferr, "qh_check_maxout: check and update maxoutside for each facet.\n"));
 
175
  maxoutside= minvertex= 0;
 
176
  if (qh VERTEXneighbors 
 
177
  && (qh PRINTsummary || qh KEEPinside || qh KEEPcoplanar 
 
178
        || qh TRACElevel || qh PRINTstatistics
 
179
        || qh PRINTout[0] == qh_PRINTsummary || qh PRINTout[0] == qh_PRINTnone)) { 
 
180
    trace1((qh ferr, "qh_check_maxout: determine actual maxoutside and minvertex\n"));
 
181
    vertices= qh_pointvertex (/*qh facet_list*/);
 
182
    FORALLvertices {
 
183
      FOREACHneighbor_(vertex) {
 
184
        zinc_(Zdistvertex);  /* distance also computed by main loop below */
 
185
        qh_distplane (vertex->point, neighbor, &dist);
 
186
        minimize_(minvertex, dist);
 
187
        if (-dist > qh TRACEdist || dist > qh TRACEdist 
 
188
        || neighbor == qh tracefacet || vertex == qh tracevertex)
 
189
          fprintf (qh ferr, "qh_check_maxout: p%d (v%d) is %.2g from f%d\n",
 
190
                    qh_pointid (vertex->point), vertex->id, dist, neighbor->id);
 
191
      }
 
192
    }
 
193
    if (qh MERGING) {
 
194
      wmin_(Wminvertex, qh min_vertex);
 
195
    }
 
196
    qh min_vertex= minvertex;
 
197
    qh_settempfree (&vertices);  
 
198
  }
 
199
  facets= qh_pointfacet (/*qh facet_list*/);
 
200
  do {
 
201
    old_maxoutside= fmax_(qh max_outside, maxoutside);
 
202
    FOREACHfacet_i_(facets) {     /* for each point with facet assignment */
 
203
      if (facet) { 
 
204
        point= qh_point(facet_i);
 
205
        if (point == qh GOODpointp)
 
206
          continue;
 
207
        zinc_(Ztotcheck);
 
208
        qh_distplane(point, facet, &dist);
 
209
        numpart++;
 
210
        bestfacet= qh_findbesthorizon (qh_IScheckmax, point, facet, !qh_NOupper, &dist, &numpart);
 
211
        if (bestfacet && dist > maxoutside) {
 
212
          if (qh ONLYgood && !bestfacet->good 
 
213
          && !((bestfacet= qh_findgooddist (point, bestfacet, &dist, &facetlist))
 
214
               && dist > maxoutside))
 
215
            notgood++;
 
216
          else
 
217
            maxoutside= dist;
 
218
        }
 
219
        if (dist > qh TRACEdist || (bestfacet && bestfacet == qh tracefacet))
 
220
          fprintf (qh ferr, "qh_check_maxout: p%d is %.2g above f%d\n",
 
221
                     qh_pointid (point), dist, bestfacet->id);
 
222
      }
 
223
    }
 
224
  }while 
 
225
    (maxoutside > 2*old_maxoutside);
 
226
    /* if qh.maxoutside increases substantially, qh_SEARCHdist is not valid 
 
227
          e.g., RBOX 5000 s Z1 G1e-13 t1001200614 | qhull */
 
228
  zzadd_(Zcheckpart, numpart);
 
229
  qh_settempfree (&facets);
 
230
  wval_(Wmaxout)= maxoutside - qh max_outside;
 
231
  wmax_(Wmaxoutside, qh max_outside);
 
232
  qh max_outside= maxoutside;
 
233
  qh_nearcoplanar (/*qh.facet_list*/);
 
234
  qh maxoutdone= True;
 
235
  trace1((qh ferr, "qh_check_maxout: maxoutside %2.2g, min_vertex %2.2g, outside of not good %d\n",
 
236
       maxoutside, qh min_vertex, notgood));
 
237
} /* check_maxout */
 
238
#else /* qh_NOmerge */
 
239
void qh_check_maxout (void) {
 
240
}
 
241
#endif
 
242
 
 
243
/*-<a                             href="qh-poly.htm#TOC"
 
244
  >-------------------------------</a><a name="check_output">-</a>
 
245
  
 
246
  qh_check_output()
 
247
    performs the checks at the end of qhull algorithm
 
248
    Maybe called after voronoi output.  Will recompute otherwise centrums are Voronoi centers instead
 
249
*/
 
250
void qh_check_output (void) {
 
251
  int i;
 
252
 
 
253
  if (qh STOPcone)
 
254
    return;
 
255
  if (qh VERIFYoutput | qh IStracing | qh CHECKfrequently) {
 
256
    qh_checkpolygon (qh facet_list);
 
257
    qh_checkflipped_all (qh facet_list);
 
258
    qh_checkconvex (qh facet_list, qh_ALGORITHMfault);
 
259
  }else if (!qh MERGING && qh_newstats (qhstat precision, &i)) {
 
260
    qh_checkflipped_all (qh facet_list);
 
261
    qh_checkconvex (qh facet_list, qh_ALGORITHMfault);
 
262
  }
 
263
} /* check_output */
 
264
 
 
265
 
 
266
 
 
267
/*-<a                             href="qh-poly.htm#TOC"
 
268
  >-------------------------------</a><a name="check_point">-</a>
 
269
  
 
270
  qh_check_point( point, facet, maxoutside, maxdist, errfacet1, errfacet2 )
 
271
    check that point is less than maxoutside from facet
 
272
*/
 
273
void qh_check_point (pointT *point, facetT *facet, realT *maxoutside, realT *maxdist, facetT **errfacet1, facetT **errfacet2) {
 
274
  realT dist;
 
275
 
 
276
  /* occurs after statistics reported */
 
277
  qh_distplane(point, facet, &dist);
 
278
  if (dist > *maxoutside) {
 
279
    if (*errfacet1 != facet) {
 
280
      *errfacet2= *errfacet1;
 
281
      *errfacet1= facet;
 
282
    }
 
283
    fprintf(qh ferr, "qhull precision error: point p%d is outside facet f%d, distance= %6.8g maxoutside= %6.8g\n", 
 
284
              qh_pointid(point), facet->id, dist, *maxoutside);
 
285
  }
 
286
  maximize_(*maxdist, dist);
 
287
} /* qh_check_point */
 
288
 
 
289
 
 
290
/*-<a                             href="qh-poly.htm#TOC"
 
291
  >-------------------------------</a><a name="check_points">-</a>
 
292
  
 
293
  qh_check_points()
 
294
    checks that all points are inside all facets
 
295
 
 
296
  notes:
 
297
    if many points and qh_check_maxout not called (i.e., !qh.MERGING), 
 
298
       calls qh_findbesthorizon (seldom done).
 
299
    ignores flipped facets
 
300
    maxoutside includes 2 qh.DISTrounds
 
301
      one qh.DISTround for the computed distances in qh_check_points
 
302
    qh_printafacet and qh_printsummary needs only one qh.DISTround
 
303
    the computation for qh.VERIFYdirect does not account for qh.other_points
 
304
 
 
305
  design:
 
306
    if many points
 
307
      use qh_check_bestdist()
 
308
    else
 
309
      for all facets
 
310
        for all points
 
311
          check that point is inside facet
 
312
*/
 
313
void qh_check_points (void) {
 
314
  facetT *facet, *errfacet1= NULL, *errfacet2= NULL;
 
315
  realT total, maxoutside, maxdist= -REALmax;
 
316
  pointT *point, **pointp, *pointtemp;
 
317
  boolT testouter;
 
318
 
 
319
  maxoutside= qh_maxouter();
 
320
  maxoutside += qh DISTround;
 
321
  /* one more qh.DISTround for check computation */
 
322
  trace1((qh ferr, "qh_check_points: check all points below %2.2g of all facet planes\n",
 
323
          maxoutside));
 
324
  if (qh num_good)   /* miss counts other_points and !good facets */
 
325
     total= (float) qh num_good * qh num_points;
 
326
  else
 
327
     total= (float) qh num_facets * qh num_points;
 
328
  if (total >= qh_VERIFYdirect && !qh maxoutdone) {
 
329
    if (!qh_QUICKhelp && qh SKIPcheckmax && qh MERGING)
 
330
      fprintf (qh ferr, "\n\
 
331
qhull input warning: merging without checking outer planes ('Q5' or 'Po').\n\
 
332
Verify may report that a point is outside of a facet.\n");
 
333
    qh_check_bestdist();
 
334
  }else {
 
335
    if (qh_MAXoutside && qh maxoutdone)
 
336
      testouter= True;
 
337
    else
 
338
      testouter= False;
 
339
    if (!qh_QUICKhelp) {
 
340
      if (qh MERGEexact)
 
341
        fprintf (qh ferr, "\n\
 
342
qhull input warning: exact merge ('Qx').  Verify may report that a point\n\
 
343
is outside of a facet.  See qh-optq.htm#Qx\n");
 
344
      else if (qh SKIPcheckmax || qh NOnearinside)
 
345
        fprintf (qh ferr, "\n\
 
346
qhull input warning: no outer plane check ('Q5') or no processing of\n\
 
347
near-inside points ('Q8').  Verify may report that a point is outside\n\
 
348
of a facet.\n");
 
349
    }
 
350
    if (qh PRINTprecision) {
 
351
      if (testouter)
 
352
        fprintf (qh ferr, "\n\
 
353
Output completed.  Verifying that all points are below outer planes of\n\
 
354
all %sfacets.  Will make %2.0f distance computations.\n", 
 
355
              (qh ONLYgood ?  "good " : ""), total);
 
356
      else
 
357
        fprintf (qh ferr, "\n\
 
358
Output completed.  Verifying that all points are below %2.2g of\n\
 
359
all %sfacets.  Will make %2.0f distance computations.\n", 
 
360
              maxoutside, (qh ONLYgood ?  "good " : ""), total);
 
361
    }
 
362
    FORALLfacets {
 
363
      if (!facet->good && qh ONLYgood)
 
364
        continue;
 
365
      if (facet->flipped)
 
366
        continue;
 
367
      if (!facet->normal) {
 
368
        fprintf( qh ferr, "qhull warning (qh_check_points): missing normal for facet f%d\n", facet->id);
 
369
        continue;
 
370
      }
 
371
      if (testouter) {
 
372
#if qh_MAXoutside
 
373
        maxoutside= facet->maxoutside + 2* qh DISTround;
 
374
        /* one DISTround to actual point and another to computed point */
 
375
#endif
 
376
      }
 
377
      FORALLpoints {
 
378
        if (point != qh GOODpointp)
 
379
          qh_check_point (point, facet, &maxoutside, &maxdist, &errfacet1, &errfacet2);
 
380
      }
 
381
      FOREACHpoint_(qh other_points) {
 
382
        if (point != qh GOODpointp)
 
383
          qh_check_point (point, facet, &maxoutside, &maxdist, &errfacet1, &errfacet2);
 
384
      }
 
385
    }
 
386
    if (maxdist > qh outside_err) {
 
387
      fprintf( qh ferr, "qhull precision error (qh_check_points): a coplanar point is %6.2g from convex hull.  The maximum value (qh.outside_err) is %6.2g\n",
 
388
                maxdist, qh outside_err );
 
389
      qh_errexit2( qh_ERRprec, errfacet1, errfacet2 );
 
390
    }else if (errfacet1 && qh outside_err > REALmax/2)
 
391
        qh_errexit2( qh_ERRprec, errfacet1, errfacet2 );
 
392
    else if (errfacet1)
 
393
        ;  /* the error was logged to qh.ferr but does not effect the output */
 
394
    trace0((qh ferr, "qh_check_points: max distance outside %2.2g\n", maxdist));
 
395
  }
 
396
} /* check_points */
 
397
 
 
398
 
 
399
/*-<a                             href="qh-poly.htm#TOC"
 
400
  >-------------------------------</a><a name="checkconvex">-</a>
 
401
  
 
402
  qh_checkconvex( facetlist, fault )
 
403
    check that each ridge in facetlist is convex
 
404
    fault = qh_DATAfault if reporting errors
 
405
          = qh_ALGORITHMfault otherwise
 
406
 
 
407
  returns:
 
408
    counts Zconcaveridges and Zcoplanarridges
 
409
    errors if concaveridge or if merging an coplanar ridge
 
410
 
 
411
  note:
 
412
    if not merging, 
 
413
      tests vertices for neighboring simplicial facets
 
414
    else if ZEROcentrum, 
 
415
      tests vertices for neighboring simplicial   facets
 
416
    else 
 
417
      tests centrums of neighboring facets
 
418
 
 
419
  design:
 
420
    for all facets
 
421
      report flipped facets
 
422
      if ZEROcentrum and simplicial neighbors
 
423
        test vertices for neighboring simplicial facets
 
424
      else
 
425
        test centrum against all neighbors 
 
426
*/
 
427
void qh_checkconvex(facetT *facetlist, int fault) {
 
428
  facetT *facet, *neighbor, **neighborp, *errfacet1=NULL, *errfacet2=NULL;
 
429
  vertexT *vertex;
 
430
  realT dist;
 
431
  pointT *centrum;
 
432
  boolT waserror= False, centrum_warning= False, tempcentrum= False, allsimplicial;
 
433
  int neighbor_i;
 
434
 
 
435
  trace1((qh ferr, "qh_checkconvex: check all ridges are convex\n"));
 
436
  if (!qh RERUN) {
 
437
    zzval_(Zconcaveridges)= 0;
 
438
    zzval_(Zcoplanarridges)= 0;
 
439
  }
 
440
  FORALLfacet_(facetlist) {
 
441
    if (facet->flipped) {
 
442
      qh_precision ("flipped facet");
 
443
      fprintf (qh ferr, "qhull precision error: f%d is flipped (interior point is outside)\n",
 
444
               facet->id);
 
445
      errfacet1= facet;
 
446
      waserror= True;
 
447
      continue;
 
448
    }
 
449
    if (qh MERGING && (!qh ZEROcentrum || !facet->simplicial || facet->tricoplanar))
 
450
      allsimplicial= False;
 
451
    else {
 
452
      allsimplicial= True;
 
453
      neighbor_i= 0;
 
454
      FOREACHneighbor_(facet) {
 
455
        vertex= SETelemt_(facet->vertices, neighbor_i++, vertexT);
 
456
        if (!neighbor->simplicial || neighbor->tricoplanar) {
 
457
          allsimplicial= False;
 
458
          continue;
 
459
        }
 
460
        qh_distplane (vertex->point, neighbor, &dist);
 
461
        if (dist > -qh DISTround) {
 
462
          if (fault == qh_DATAfault) {
 
463
            qh_precision ("coplanar or concave ridge");
 
464
            fprintf (qh ferr, "qhull precision error: initial simplex is not convex. Distance=%.2g\n", dist);
 
465
            qh_errexit(qh_ERRsingular, NULL, NULL);
 
466
          }
 
467
          if (dist > qh DISTround) {
 
468
            zzinc_(Zconcaveridges);
 
469
            qh_precision ("concave ridge");
 
470
            fprintf (qh ferr, "qhull precision error: f%d is concave to f%d, since p%d (v%d) is %6.4g above\n",
 
471
              facet->id, neighbor->id, qh_pointid(vertex->point), vertex->id, dist);
 
472
            errfacet1= facet;
 
473
            errfacet2= neighbor;
 
474
            waserror= True;
 
475
          }else if (qh ZEROcentrum) {
 
476
            if (dist > 0) {     /* qh_checkzero checks that dist < - qh DISTround */
 
477
              zzinc_(Zcoplanarridges); 
 
478
              qh_precision ("coplanar ridge");
 
479
              fprintf (qh ferr, "qhull precision error: f%d is clearly not convex to f%d, since p%d (v%d) is %6.4g above\n",
 
480
                facet->id, neighbor->id, qh_pointid(vertex->point), vertex->id, dist);
 
481
              errfacet1= facet;
 
482
              errfacet2= neighbor;
 
483
              waserror= True;
 
484
            }
 
485
          }else {              
 
486
            zzinc_(Zcoplanarridges);
 
487
            qh_precision ("coplanar ridge");
 
488
            trace0((qh ferr, "qhull precision error: f%d may be coplanar to f%d, since p%d (v%d) is within %6.4g during p%d\n",
 
489
              facet->id, neighbor->id, qh_pointid(vertex->point), vertex->id, dist, qh furthest_id));
 
490
          }
 
491
        }
 
492
      }
 
493
    }
 
494
    if (!allsimplicial) {
 
495
      if (qh CENTERtype == qh_AScentrum) {
 
496
        if (!facet->center)
 
497
          facet->center= qh_getcentrum (facet);
 
498
        centrum= facet->center;
 
499
      }else {
 
500
        if (!centrum_warning && (!facet->simplicial || facet->tricoplanar)) {
 
501
           centrum_warning= True;
 
502
           fprintf (qh ferr, "qhull note: recomputing centrums for convexity test.  This may lead to false, precision errors.\n");
 
503
        }
 
504
        centrum= qh_getcentrum(facet);
 
505
        tempcentrum= True;
 
506
      }
 
507
      FOREACHneighbor_(facet) {
 
508
        if (qh ZEROcentrum && facet->simplicial && neighbor->simplicial)
 
509
          continue;
 
510
        if (facet->tricoplanar || neighbor->tricoplanar)
 
511
          continue;
 
512
        zzinc_(Zdistconvex);
 
513
        qh_distplane (centrum, neighbor, &dist);
 
514
        if (dist > qh DISTround) {
 
515
          zzinc_(Zconcaveridges);
 
516
          qh_precision ("concave ridge");
 
517
          fprintf (qh ferr, "qhull precision error: f%d is concave to f%d.  Centrum of f%d is %6.4g above f%d\n",
 
518
            facet->id, neighbor->id, facet->id, dist, neighbor->id);
 
519
          errfacet1= facet;
 
520
          errfacet2= neighbor;
 
521
          waserror= True;
 
522
        }else if (dist >= 0.0) {   /* if arithmetic always rounds the same,
 
523
                                     can test against centrum radius instead */
 
524
          zzinc_(Zcoplanarridges);
 
525
          qh_precision ("coplanar ridge");
 
526
          fprintf (qh ferr, "qhull precision error: f%d is coplanar or concave to f%d.  Centrum of f%d is %6.4g above f%d\n",
 
527
            facet->id, neighbor->id, facet->id, dist, neighbor->id);
 
528
          errfacet1= facet;
 
529
          errfacet2= neighbor;
 
530
          waserror= True;
 
531
        }
 
532
      }
 
533
      if (tempcentrum)
 
534
        qh_memfree(centrum, qh normal_size);
 
535
    }
 
536
  }
 
537
  if (waserror && !qh FORCEoutput)
 
538
    qh_errexit2 (qh_ERRprec, errfacet1, errfacet2);
 
539
} /* checkconvex */
 
540
 
 
541
 
 
542
/*-<a                             href="qh-poly.htm#TOC"
 
543
  >-------------------------------</a><a name="checkfacet">-</a>
 
544
  
 
545
  qh_checkfacet( facet, newmerge, waserror )
 
546
    checks for consistency errors in facet
 
547
    newmerge set if from merge.c
 
548
 
 
549
  returns:
 
550
    sets waserror if any error occurs
 
551
 
 
552
  checks:
 
553
    vertex ids are inverse sorted
 
554
    unless newmerge, at least hull_dim neighbors and vertices (exactly if simplicial)
 
555
    if non-simplicial, at least as many ridges as neighbors
 
556
    neighbors are not duplicated
 
557
    ridges are not duplicated
 
558
    in 3-d, ridges=verticies
 
559
    (qh.hull_dim-1) ridge vertices
 
560
    neighbors are reciprocated
 
561
    ridge neighbors are facet neighbors and a ridge for every neighbor
 
562
    simplicial neighbors match facetintersect
 
563
    vertex intersection matches vertices of common ridges 
 
564
    vertex neighbors and facet vertices agree
 
565
    all ridges have distinct vertex sets
 
566
 
 
567
  notes:  
 
568
    uses neighbor->seen
 
569
 
 
570
  design:
 
571
    check sets
 
572
    check vertices
 
573
    check sizes of neighbors and vertices
 
574
    check for qh_MERGEridge and qh_DUPLICATEridge flags
 
575
    check neighbor set
 
576
    check ridge set
 
577
    check ridges, neighbors, and vertices
 
578
*/
 
579
void qh_checkfacet(facetT *facet, boolT newmerge, boolT *waserrorp) {
 
580
  facetT *neighbor, **neighborp, *errother=NULL;
 
581
  ridgeT *ridge, **ridgep, *errridge= NULL, *ridge2;
 
582
  vertexT *vertex, **vertexp;
 
583
  unsigned previousid= INT_MAX;
 
584
  int numneighbors, numvertices, numridges=0, numRvertices=0;
 
585
  boolT waserror= False;
 
586
  int skipA, skipB, ridge_i, ridge_n, i;
 
587
  setT *intersection;
 
588
 
 
589
  if (facet->visible) {
 
590
    fprintf (qh ferr, "qhull internal error (qh_checkfacet): facet f%d is on the visible_list\n",
 
591
      facet->id);
 
592
    qh_errexit (qh_ERRqhull, facet, NULL);
 
593
  }
 
594
  if (!facet->normal) {
 
595
    fprintf (qh ferr, "qhull internal error (qh_checkfacet): facet f%d does not have  a normal\n",
 
596
      facet->id);
 
597
    waserror= True;
 
598
  }
 
599
  qh_setcheck (facet->vertices, "vertices for f", facet->id);
 
600
  qh_setcheck (facet->ridges, "ridges for f", facet->id);
 
601
  qh_setcheck (facet->outsideset, "outsideset for f", facet->id);
 
602
  qh_setcheck (facet->coplanarset, "coplanarset for f", facet->id);
 
603
  qh_setcheck (facet->neighbors, "neighbors for f", facet->id);
 
604
  FOREACHvertex_(facet->vertices) {
 
605
    if (vertex->deleted) {
 
606
      fprintf(qh ferr, "qhull internal error (qh_checkfacet): deleted vertex v%d in f%d\n", vertex->id, facet->id);
 
607
      qh_errprint ("ERRONEOUS", NULL, NULL, NULL, vertex);
 
608
      waserror= True;
 
609
    }
 
610
    if (vertex->id >= previousid) {
 
611
      fprintf(qh ferr, "qhull internal error (qh_checkfacet): vertices of f%d are not in descending id order at v%d\n", facet->id, vertex->id);
 
612
      waserror= True;
 
613
      break;
 
614
    }
 
615
    previousid= vertex->id;
 
616
  }
 
617
  numneighbors= qh_setsize(facet->neighbors);
 
618
  numvertices= qh_setsize(facet->vertices);
 
619
  numridges= qh_setsize(facet->ridges);
 
620
  if (facet->simplicial) {
 
621
    if (numvertices+numneighbors != 2*qh hull_dim 
 
622
    && !facet->degenerate && !facet->redundant) {
 
623
      fprintf(qh ferr, "qhull internal error (qh_checkfacet): for simplicial facet f%d, #vertices %d + #neighbors %d != 2*qh hull_dim\n", 
 
624
                facet->id, numvertices, numneighbors);
 
625
      qh_setprint (qh ferr, "", facet->neighbors);
 
626
      waserror= True;
 
627
    }
 
628
  }else { /* non-simplicial */
 
629
    if (!newmerge 
 
630
    &&(numvertices < qh hull_dim || numneighbors < qh hull_dim)
 
631
    && !facet->degenerate && !facet->redundant) {
 
632
      fprintf(qh ferr, "qhull internal error (qh_checkfacet): for facet f%d, #vertices %d or #neighbors %d < qh hull_dim\n",
 
633
         facet->id, numvertices, numneighbors);
 
634
       waserror= True;
 
635
    }
 
636
    /* in 3-d, can get a vertex twice in an edge list, e.g., RBOX 1000 s W1e-13 t995849315 D2 | QHULL d Tc Tv TP624 TW1e-13 T4 */
 
637
    if (numridges < numneighbors
 
638
    ||(qh hull_dim == 3 && numvertices > numridges && !qh NEWfacets)
 
639
    ||(qh hull_dim == 2 && numridges + numvertices + numneighbors != 6)) {
 
640
      if (!facet->degenerate && !facet->redundant) {
 
641
        fprintf(qh ferr, "qhull internal error (qh_checkfacet): for facet f%d, #ridges %d < #neighbors %d or (3-d) > #vertices %d or (2-d) not all 2\n",
 
642
            facet->id, numridges, numneighbors, numvertices);
 
643
        waserror= True;
 
644
      }
 
645
    }
 
646
  }
 
647
  FOREACHneighbor_(facet) {
 
648
    if (neighbor == qh_MERGEridge || neighbor == qh_DUPLICATEridge) {
 
649
      fprintf(qh ferr, "qhull internal error (qh_checkfacet): facet f%d still has a MERGE or DUP neighbor\n", facet->id);
 
650
      qh_errexit (qh_ERRqhull, facet, NULL);
 
651
    }
 
652
    neighbor->seen= True;
 
653
  }
 
654
  FOREACHneighbor_(facet) {
 
655
    if (!qh_setin(neighbor->neighbors, facet)) {
 
656
      fprintf(qh ferr, "qhull internal error (qh_checkfacet): facet f%d has neighbor f%d, but f%d does not have neighbor f%d\n",
 
657
              facet->id, neighbor->id, neighbor->id, facet->id);
 
658
      errother= neighbor;
 
659
      waserror= True;
 
660
    }
 
661
    if (!neighbor->seen) {
 
662
      fprintf(qh ferr, "qhull internal error (qh_checkfacet): facet f%d has a duplicate neighbor f%d\n",
 
663
              facet->id, neighbor->id);
 
664
      errother= neighbor;
 
665
      waserror= True;
 
666
    }    
 
667
    neighbor->seen= False;
 
668
  }
 
669
  FOREACHridge_(facet->ridges) {
 
670
    qh_setcheck (ridge->vertices, "vertices for r", ridge->id);
 
671
    ridge->seen= False;
 
672
  }
 
673
  FOREACHridge_(facet->ridges) {
 
674
    if (ridge->seen) {
 
675
      fprintf(qh ferr, "qhull internal error (qh_checkfacet): facet f%d has a duplicate ridge r%d\n",
 
676
              facet->id, ridge->id);
 
677
      errridge= ridge;
 
678
      waserror= True;
 
679
    }    
 
680
    ridge->seen= True;
 
681
    numRvertices= qh_setsize(ridge->vertices);
 
682
    if (numRvertices != qh hull_dim - 1) {
 
683
      fprintf(qh ferr, "qhull internal error (qh_checkfacet): ridge between f%d and f%d has %d vertices\n", 
 
684
                ridge->top->id, ridge->bottom->id, numRvertices);
 
685
      errridge= ridge;
 
686
      waserror= True;
 
687
    }
 
688
    neighbor= otherfacet_(ridge, facet);
 
689
    neighbor->seen= True;
 
690
    if (!qh_setin(facet->neighbors, neighbor)) {
 
691
      fprintf(qh ferr, "qhull internal error (qh_checkfacet): for facet f%d, neighbor f%d of ridge r%d not in facet\n",
 
692
           facet->id, neighbor->id, ridge->id);
 
693
      errridge= ridge;
 
694
      waserror= True;
 
695
    }
 
696
  }
 
697
  if (!facet->simplicial) {
 
698
    FOREACHneighbor_(facet) {
 
699
      if (!neighbor->seen) {
 
700
        fprintf(qh ferr, "qhull internal error (qh_checkfacet): facet f%d does not have a ridge for neighbor f%d\n",
 
701
              facet->id, neighbor->id);
 
702
        errother= neighbor;
 
703
        waserror= True;
 
704
      }
 
705
      intersection= qh_vertexintersect_new(facet->vertices, neighbor->vertices);
 
706
      qh_settemppush (intersection);
 
707
      FOREACHvertex_(facet->vertices) {
 
708
        vertex->seen= False;
 
709
        vertex->seen2= False;
 
710
      }
 
711
      FOREACHvertex_(intersection)
 
712
        vertex->seen= True;
 
713
      FOREACHridge_(facet->ridges) {
 
714
        if (neighbor != otherfacet_(ridge, facet))
 
715
            continue;
 
716
        FOREACHvertex_(ridge->vertices) {
 
717
          if (!vertex->seen) {
 
718
            fprintf (qh ferr, "qhull internal error (qh_checkfacet): vertex v%d in r%d not in f%d intersect f%d\n",
 
719
                  vertex->id, ridge->id, facet->id, neighbor->id);
 
720
            qh_errexit (qh_ERRqhull, facet, ridge);
 
721
          }
 
722
          vertex->seen2= True;
 
723
        }
 
724
      }
 
725
      if (!newmerge) {
 
726
        FOREACHvertex_(intersection) {
 
727
          if (!vertex->seen2) {
 
728
            if (qh IStracing >=3 || !qh MERGING) {
 
729
              fprintf (qh ferr, "qhull precision error (qh_checkfacet): vertex v%d in f%d intersect f%d but\n\
 
730
 not in a ridge.  This is ok under merging.  Last point was p%d\n",
 
731
                     vertex->id, facet->id, neighbor->id, qh furthest_id);
 
732
              if (!qh FORCEoutput && !qh MERGING) {
 
733
                qh_errprint ("ERRONEOUS", facet, neighbor, NULL, vertex);
 
734
                if (!qh MERGING)
 
735
                  qh_errexit (qh_ERRqhull, NULL, NULL);
 
736
              }
 
737
            }
 
738
          }
 
739
        }
 
740
      }      
 
741
      qh_settempfree (&intersection);
 
742
    }
 
743
  }else { /* simplicial */
 
744
    FOREACHneighbor_(facet) {
 
745
      if (neighbor->simplicial) {    
 
746
        skipA= SETindex_(facet->neighbors, neighbor);
 
747
        skipB= qh_setindex (neighbor->neighbors, facet);
 
748
        if (!qh_setequal_skip (facet->vertices, skipA, neighbor->vertices, skipB)) {
 
749
          fprintf (qh ferr, "qhull internal error (qh_checkfacet): facet f%d skip %d and neighbor f%d skip %d do not match \n",
 
750
                   facet->id, skipA, neighbor->id, skipB);
 
751
          errother= neighbor;
 
752
          waserror= True;
 
753
        }
 
754
      }
 
755
    }
 
756
  }
 
757
  if (qh hull_dim < 5 && (qh IStracing > 2 || qh CHECKfrequently)) {
 
758
    FOREACHridge_i_(facet->ridges) {           /* expensive */
 
759
      for (i= ridge_i+1; i < ridge_n; i++) {
 
760
        ridge2= SETelemt_(facet->ridges, i, ridgeT);
 
761
        if (qh_setequal (ridge->vertices, ridge2->vertices)) {
 
762
          fprintf (qh ferr, "qh_checkfacet: ridges r%d and r%d have the same vertices\n",
 
763
                  ridge->id, ridge2->id);
 
764
          errridge= ridge;
 
765
          waserror= True;
 
766
        }
 
767
      }
 
768
    }
 
769
  }
 
770
  if (waserror) {
 
771
    qh_errprint("ERRONEOUS", facet, errother, errridge, NULL);
 
772
    *waserrorp= True;
 
773
  }
 
774
} /* checkfacet */
 
775
 
 
776
 
 
777
/*-<a                             href="qh-poly.htm#TOC"
 
778
  >-------------------------------</a><a name="checkflipped_all">-</a>
 
779
  
 
780
  qh_checkflipped_all( facetlist )
 
781
    checks orientation of facets in list against interior point
 
782
*/
 
783
void qh_checkflipped_all (facetT *facetlist) {
 
784
  facetT *facet;
 
785
  boolT waserror= False;
 
786
  realT dist;
 
787
 
 
788
  if (facetlist == qh facet_list)
 
789
    zzval_(Zflippedfacets)= 0;
 
790
  FORALLfacet_(facetlist) {
 
791
    if (facet->normal && !qh_checkflipped (facet, &dist, !qh_ALL)) {
 
792
      fprintf(qh ferr, "qhull precision error: facet f%d is flipped, distance= %6.12g\n",
 
793
              facet->id, dist);
 
794
      if (!qh FORCEoutput) {
 
795
        qh_errprint("ERRONEOUS", facet, NULL, NULL, NULL);
 
796
        waserror= True;
 
797
      }
 
798
    }
 
799
  }
 
800
  if (waserror) {
 
801
    fprintf (qh ferr, "\n\
 
802
A flipped facet occurs when its distance to the interior point is\n\
 
803
greater than %2.2g, the maximum roundoff error.\n", -qh DISTround);
 
804
    qh_errexit(qh_ERRprec, NULL, NULL);
 
805
  }
 
806
} /* checkflipped_all */
 
807
 
 
808
/*-<a                             href="qh-poly.htm#TOC"
 
809
  >-------------------------------</a><a name="checkpolygon">-</a>
 
810
  
 
811
  qh_checkpolygon( facetlist )
 
812
    checks the correctness of the structure
 
813
 
 
814
  notes:
 
815
    call with either qh.facet_list or qh.newfacet_list
 
816
    checks num_facets and num_vertices if qh.facet_list
 
817
 
 
818
  design:
 
819
    for each facet
 
820
      checks facet and outside set
 
821
    initializes vertexlist
 
822
    for each facet
 
823
      checks vertex set
 
824
    if checking all facets (qh.facetlist)
 
825
      check facet count
 
826
      if qh.VERTEXneighbors
 
827
        check vertex neighbors and count
 
828
      check vertex count
 
829
*/
 
830
void qh_checkpolygon(facetT *facetlist) {
 
831
  facetT *facet;
 
832
  vertexT *vertex, **vertexp, *vertexlist;
 
833
  int numfacets= 0, numvertices= 0, numridges= 0;
 
834
  int totvneighbors= 0, totvertices= 0;
 
835
  boolT waserror= False, nextseen= False, visibleseen= False;
 
836
  
 
837
  trace1((qh ferr, "qh_checkpolygon: check all facets from f%d\n", facetlist->id));
 
838
  if (facetlist != qh facet_list || qh ONLYgood)
 
839
    nextseen= True;
 
840
  FORALLfacet_(facetlist) {
 
841
    if (facet == qh visible_list)
 
842
      visibleseen= True;
 
843
    if (!facet->visible) {
 
844
      if (!nextseen) {
 
845
        if (facet == qh facet_next)
 
846
          nextseen= True;
 
847
        else if (qh_setsize (facet->outsideset)) {
 
848
          if (!qh NARROWhull
 
849
#if !qh_COMPUTEfurthest
 
850
               || facet->furthestdist >= qh MINoutside
 
851
#endif
 
852
                        ) {
 
853
            fprintf (qh ferr, "qhull internal error (qh_checkpolygon): f%d has outside points before qh facet_next\n",
 
854
                     facet->id);
 
855
            qh_errexit (qh_ERRqhull, facet, NULL);
 
856
          }
 
857
        }
 
858
      }
 
859
      numfacets++;
 
860
      qh_checkfacet(facet, False, &waserror);
 
861
    }
 
862
  }
 
863
  if (qh visible_list && !visibleseen && facetlist == qh facet_list) {
 
864
    fprintf (qh ferr, "qhull internal error (qh_checkpolygon): visible list f%d no longer on facet list\n", qh visible_list->id);
 
865
    qh_printlists();
 
866
    qh_errexit (qh_ERRqhull, qh visible_list, NULL);
 
867
  }
 
868
  if (facetlist == qh facet_list)
 
869
    vertexlist= qh vertex_list;
 
870
  else if (facetlist == qh newfacet_list)
 
871
    vertexlist= qh newvertex_list;
 
872
  else
 
873
    vertexlist= NULL;
 
874
  FORALLvertex_(vertexlist) {
 
875
    vertex->seen= False;
 
876
    vertex->visitid= 0;
 
877
  }  
 
878
  FORALLfacet_(facetlist) {
 
879
    if (facet->visible)
 
880
      continue;
 
881
    if (facet->simplicial)
 
882
      numridges += qh hull_dim;
 
883
    else
 
884
      numridges += qh_setsize (facet->ridges);
 
885
    FOREACHvertex_(facet->vertices) {
 
886
      vertex->visitid++;
 
887
      if (!vertex->seen) {
 
888
        vertex->seen= True;
 
889
        numvertices++;
 
890
        if (qh_pointid (vertex->point) == -1) {
 
891
          fprintf (qh ferr, "qhull internal error (qh_checkpolygon): unknown point %p for vertex v%d first_point %p\n",
 
892
                   vertex->point, vertex->id, qh first_point);
 
893
          waserror= True;
 
894
        }
 
895
      }
 
896
    }
 
897
  }
 
898
  qh vertex_visit += numfacets;
 
899
  if (facetlist == qh facet_list) {
 
900
    if (numfacets != qh num_facets - qh num_visible) {
 
901
      fprintf(qh ferr, "qhull internal error (qh_checkpolygon): actual number of facets is %d, cumulative facet count is %d - %d visible facets\n",
 
902
              numfacets, qh num_facets, qh num_visible);
 
903
      waserror= True;
 
904
    }
 
905
    qh vertex_visit++;
 
906
    if (qh VERTEXneighbors) {
 
907
      FORALLvertices {
 
908
        qh_setcheck (vertex->neighbors, "neighbors for v", vertex->id);
 
909
        if (vertex->deleted)
 
910
          continue;
 
911
        totvneighbors += qh_setsize (vertex->neighbors);
 
912
      }
 
913
      FORALLfacet_(facetlist)
 
914
        totvertices += qh_setsize (facet->vertices);
 
915
      if (totvneighbors != totvertices) {
 
916
        fprintf(qh ferr, "qhull internal error (qh_checkpolygon): vertex neighbors inconsistent.  Totvneighbors %d, totvertices %d\n",
 
917
                totvneighbors, totvertices);
 
918
        waserror= True;
 
919
      }
 
920
    }
 
921
    if (numvertices != qh num_vertices - qh_setsize(qh del_vertices)) {
 
922
      fprintf(qh ferr, "qhull internal error (qh_checkpolygon): actual number of vertices is %d, cumulative vertex count is %d\n",
 
923
              numvertices, qh num_vertices - qh_setsize(qh del_vertices));
 
924
      waserror= True;
 
925
    }
 
926
    if (qh hull_dim == 2 && numvertices != numfacets) {
 
927
      fprintf (qh ferr, "qhull internal error (qh_checkpolygon): #vertices %d != #facets %d\n",
 
928
        numvertices, numfacets);
 
929
      waserror= True;
 
930
    }
 
931
    if (qh hull_dim == 3 && numvertices + numfacets - numridges/2 != 2) {
 
932
      fprintf (qh ferr, "qhull warning: #vertices %d + #facets %d - #edges %d != 2\n\
 
933
        A vertex appears twice in a edge list.  May occur during merging.",
 
934
        numvertices, numfacets, numridges/2);
 
935
      /* occurs if lots of merging and a vertex ends up twice in an edge list.  e.g., RBOX 1000 s W1e-13 t995849315 D2 | QHULL d Tc Tv */
 
936
    }
 
937
  }
 
938
  if (waserror) 
 
939
    qh_errexit(qh_ERRqhull, NULL, NULL);
 
940
} /* checkpolygon */
 
941
 
 
942
 
 
943
/*-<a                             href="qh-poly.htm#TOC"
 
944
  >-------------------------------</a><a name="checkvertex">-</a>
 
945
  
 
946
  qh_checkvertex( vertex )
 
947
    check vertex for consistency
 
948
    checks vertex->neighbors
 
949
 
 
950
  notes:
 
951
    neighbors checked efficiently in checkpolygon
 
952
*/
 
953
void qh_checkvertex (vertexT *vertex) {
 
954
  boolT waserror= False;
 
955
  facetT *neighbor, **neighborp, *errfacet=NULL;
 
956
 
 
957
  if (qh_pointid (vertex->point) == -1) {
 
958
    fprintf (qh ferr, "qhull internal error (qh_checkvertex): unknown point id %p\n", vertex->point);
 
959
    waserror= True;
 
960
  }
 
961
  if (vertex->id >= qh vertex_id) {
 
962
    fprintf (qh ferr, "qhull internal error (qh_checkvertex): unknown vertex id %d\n", vertex->id);
 
963
    waserror= True;
 
964
  }
 
965
  if (!waserror && !vertex->deleted) {
 
966
    if (qh_setsize (vertex->neighbors)) {
 
967
      FOREACHneighbor_(vertex) {
 
968
        if (!qh_setin (neighbor->vertices, vertex)) {
 
969
          fprintf (qh ferr, "qhull internal error (qh_checkvertex): neighbor f%d does not contain v%d\n", neighbor->id, vertex->id);
 
970
          errfacet= neighbor;
 
971
          waserror= True;
 
972
        }
 
973
      }
 
974
    }
 
975
  }
 
976
  if (waserror) {
 
977
    qh_errprint ("ERRONEOUS", NULL, NULL, NULL, vertex);
 
978
    qh_errexit (qh_ERRqhull, errfacet, NULL);
 
979
  }
 
980
} /* checkvertex */
 
981
  
 
982
/*-<a                             href="qh-poly.htm#TOC"
 
983
  >-------------------------------</a><a name="clearcenters">-</a>
 
984
  
 
985
  qh_clearcenters( type )
 
986
    clear old data from facet->center
 
987
 
 
988
  notes:
 
989
    sets new centertype
 
990
    nop if CENTERtype is the same
 
991
*/
 
992
void qh_clearcenters (qh_CENTER type) {
 
993
  facetT *facet;
 
994
  
 
995
  if (qh CENTERtype != type) {
 
996
    FORALLfacets {
 
997
      if (qh CENTERtype == qh_ASvoronoi){
 
998
        if (facet->center) {
 
999
          qh_memfree (facet->center, qh center_size);
 
1000
          facet->center= NULL;
 
1001
        }
 
1002
      }else /* qh CENTERtype == qh_AScentrum */ {
 
1003
        if (facet->center) {
 
1004
          qh_memfree (facet->center, qh normal_size);
 
1005
          facet->center= NULL;
 
1006
        }
 
1007
      }
 
1008
    }
 
1009
    qh CENTERtype= type;
 
1010
  }
 
1011
  trace2((qh ferr, "qh_clearcenters: switched to center type %d\n", type));
 
1012
} /* clearcenters */
 
1013
 
 
1014
/*-<a                             href="qh-poly.htm#TOC"
 
1015
  >-------------------------------</a><a name="createsimplex">-</a>
 
1016
  
 
1017
  qh_createsimplex( vertices )
 
1018
    creates a simplex from a set of vertices
 
1019
 
 
1020
  returns:
 
1021
    initializes qh.facet_list to the simplex
 
1022
    initializes qh.newfacet_list, .facet_tail
 
1023
    initializes qh.vertex_list, .newvertex_list, .vertex_tail
 
1024
 
 
1025
  design:
 
1026
    initializes lists
 
1027
    for each vertex
 
1028
      create a new facet
 
1029
    for each new facet
 
1030
      create its neighbor set
 
1031
*/
 
1032
void qh_createsimplex(setT *vertices) {
 
1033
  facetT *facet= NULL, *newfacet;
 
1034
  boolT toporient= True;
 
1035
  int vertex_i, vertex_n, nth;
 
1036
  setT *newfacets= qh_settemp (qh hull_dim+1);
 
1037
  vertexT *vertex;
 
1038
  
 
1039
  qh facet_list= qh newfacet_list= qh facet_tail= qh_newfacet();
 
1040
  qh num_facets= qh num_vertices= qh num_visible= 0;
 
1041
  qh vertex_list= qh newvertex_list= qh vertex_tail= qh_newvertex(NULL);
 
1042
  FOREACHvertex_i_(vertices) {
 
1043
    newfacet= qh_newfacet();
 
1044
    newfacet->vertices= qh_setnew_delnthsorted (vertices, vertex_n,
 
1045
                                                vertex_i, 0);
 
1046
    newfacet->toporient= toporient;
 
1047
    qh_appendfacet(newfacet);
 
1048
    newfacet->newfacet= True;
 
1049
    qh_appendvertex (vertex);
 
1050
    qh_setappend (&newfacets, newfacet);
 
1051
    toporient ^= True;
 
1052
  }
 
1053
  FORALLnew_facets {
 
1054
    nth= 0;
 
1055
    FORALLfacet_(qh newfacet_list) {
 
1056
      if (facet != newfacet) 
 
1057
        SETelem_(newfacet->neighbors, nth++)= facet;
 
1058
    }
 
1059
    qh_settruncate (newfacet->neighbors, qh hull_dim);
 
1060
  }
 
1061
  qh_settempfree (&newfacets);
 
1062
  trace1((qh ferr, "qh_createsimplex: created simplex\n"));
 
1063
} /* createsimplex */
 
1064
 
 
1065
/*-<a                             href="qh-poly.htm#TOC"
 
1066
  >-------------------------------</a><a name="delridge">-</a>
 
1067
  
 
1068
  qh_delridge( ridge )
 
1069
    deletes ridge from data structures it belongs to
 
1070
    frees up its memory
 
1071
 
 
1072
  notes:
 
1073
    in merge.c, caller sets vertex->delridge for each vertex
 
1074
    ridges also freed in qh_freeqhull
 
1075
*/
 
1076
void qh_delridge(ridgeT *ridge) {
 
1077
  void **freelistp; /* used !qh_NOmem */
 
1078
  
 
1079
  qh_setdel(ridge->top->ridges, ridge);
 
1080
  qh_setdel(ridge->bottom->ridges, ridge);
 
1081
  qh_setfree(&(ridge->vertices));
 
1082
  qh_memfree_(ridge, sizeof(ridgeT), freelistp);
 
1083
} /* delridge */
 
1084
 
 
1085
 
 
1086
/*-<a                             href="qh-poly.htm#TOC"
 
1087
  >-------------------------------</a><a name="delvertex">-</a>
 
1088
  
 
1089
  qh_delvertex( vertex )
 
1090
    deletes a vertex and frees its memory
 
1091
 
 
1092
  notes:
 
1093
    assumes vertex->adjacencies have been updated if needed
 
1094
    unlinks from vertex_list
 
1095
*/
 
1096
void qh_delvertex (vertexT *vertex) {
 
1097
 
 
1098
  if (vertex == qh tracevertex)
 
1099
    qh tracevertex= NULL;
 
1100
  qh_removevertex (vertex);
 
1101
  qh_setfree (&vertex->neighbors);
 
1102
  qh_memfree(vertex, sizeof(vertexT));
 
1103
} /* delvertex */
 
1104
 
 
1105
 
 
1106
/*-<a                             href="qh-poly.htm#TOC"
 
1107
  >-------------------------------</a><a name="facet3vertex">-</a>
 
1108
  
 
1109
  qh_facet3vertex(  )
 
1110
    return temporary set of 3-d vertices in qh_ORIENTclock order
 
1111
 
 
1112
  design:
 
1113
    if simplicial facet
 
1114
      build set from facet->vertices with facet->toporient
 
1115
    else
 
1116
      for each ridge in order
 
1117
        build set from ridge's vertices
 
1118
*/
 
1119
setT *qh_facet3vertex (facetT *facet) {
 
1120
  ridgeT *ridge, *firstridge;
 
1121
  vertexT *vertex;
 
1122
  int cntvertices, cntprojected=0;
 
1123
  setT *vertices;
 
1124
 
 
1125
  cntvertices= qh_setsize(facet->vertices);
 
1126
  vertices= qh_settemp (cntvertices);
 
1127
  if (facet->simplicial) {
 
1128
    if (cntvertices != 3) {
 
1129
      fprintf (qh ferr, "qhull internal error (qh_facet3vertex): only %d vertices for simplicial facet f%d\n", 
 
1130
                  cntvertices, facet->id);
 
1131
      qh_errexit(qh_ERRqhull, facet, NULL);
 
1132
    }
 
1133
    qh_setappend (&vertices, SETfirst_(facet->vertices));
 
1134
    if (facet->toporient ^ qh_ORIENTclock)
 
1135
      qh_setappend (&vertices, SETsecond_(facet->vertices));
 
1136
    else
 
1137
      qh_setaddnth (&vertices, 0, SETsecond_(facet->vertices));
 
1138
    qh_setappend (&vertices, SETelem_(facet->vertices, 2));
 
1139
  }else {
 
1140
    ridge= firstridge= SETfirstt_(facet->ridges, ridgeT);   /* no infinite */
 
1141
    while ((ridge= qh_nextridge3d (ridge, facet, &vertex))) {
 
1142
      qh_setappend (&vertices, vertex);
 
1143
      if (++cntprojected > cntvertices || ridge == firstridge)
 
1144
        break;
 
1145
    }
 
1146
    if (!ridge || cntprojected != cntvertices) {
 
1147
      fprintf (qh ferr, "qhull internal error (qh_facet3vertex): ridges for facet %d don't match up.  got at least %d\n", 
 
1148
                  facet->id, cntprojected);
 
1149
      qh_errexit(qh_ERRqhull, facet, ridge);
 
1150
    }
 
1151
  }
 
1152
  return vertices;
 
1153
} /* facet3vertex */
 
1154
 
 
1155
/*-<a                             href="qh-poly.htm#TOC"
 
1156
  >-------------------------------</a><a name="findbestfacet">-</a>
 
1157
  
 
1158
  qh_findbestfacet( point, bestoutside, bestdist, isoutside )
 
1159
    find facet that is furthest below a point 
 
1160
 
 
1161
    for Delaunay triangulations, 
 
1162
      Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed
 
1163
      Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates. 
 
1164
 
 
1165
  returns:
 
1166
    if bestoutside is set (e.g., qh_ALL)
 
1167
      returns best facet that is not upperdelaunay
 
1168
      if Delaunay and inside, point is outside circumsphere of bestfacet
 
1169
    else
 
1170
      returns first facet below point
 
1171
      if point is inside, returns nearest, !upperdelaunay facet
 
1172
    distance to facet
 
1173
    isoutside set if outside of facet
 
1174
    
 
1175
  notes:
 
1176
    this works for all distributions
 
1177
    if inside, qh_findbestfacet performs an exhaustive search
 
1178
       this may be too conservative.  Sometimes it is clearly required.
 
1179
    qh_findbestfacet is not used by qhull.
 
1180
    uses qh.visit_id and qh.coplanarset
 
1181
    
 
1182
  see:
 
1183
    <a href="geom.c#findbest">qh_findbest</a>
 
1184
*/
 
1185
facetT *qh_findbestfacet (pointT *point, boolT bestoutside,
 
1186
           realT *bestdist, boolT *isoutside) {
 
1187
  facetT *bestfacet= NULL;
 
1188
  int numpart, totpart= 0;
 
1189
  
 
1190
  bestfacet= qh_findbest (point, qh facet_list, 
 
1191
                            bestoutside, !qh_ISnewfacets, bestoutside /* qh_NOupper */,
 
1192
                            bestdist, isoutside, &totpart);
 
1193
  if (*bestdist < -qh DISTround) {
 
1194
    bestfacet= qh_findfacet_all (point, bestdist, isoutside, &numpart);
 
1195
    totpart += numpart;
 
1196
    if ((isoutside && bestoutside)
 
1197
    || (!isoutside && bestfacet->upperdelaunay)) {
 
1198
      bestfacet= qh_findbest (point, bestfacet, 
 
1199
                            bestoutside, False, bestoutside,
 
1200
                            bestdist, isoutside, &totpart);
 
1201
      totpart += numpart;
 
1202
    }
 
1203
  }
 
1204
  trace3((qh ferr, "qh_findbestfacet: f%d dist %2.2g isoutside %d totpart %d\n",
 
1205
          bestfacet->id, *bestdist, *isoutside, totpart));
 
1206
  return bestfacet;
 
1207
} /* findbestfacet */ 
 
1208
 
 
1209
/*-<a                             href="qh-poly.htm#TOC"
 
1210
  >-------------------------------</a><a name="findfacet_all">-</a>
 
1211
  
 
1212
  qh_findfacet_all( point, bestdist, isoutside, numpart )
 
1213
    exhaustive search for facet below a point 
 
1214
 
 
1215
    for Delaunay triangulations, 
 
1216
      Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed
 
1217
      Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates. 
 
1218
 
 
1219
  returns:
 
1220
    returns first facet below point
 
1221
    if point is inside, 
 
1222
      returns nearest facet
 
1223
    distance to facet
 
1224
    isoutside if point is outside of the hull
 
1225
    number of distance tests
 
1226
*/
 
1227
facetT *qh_findfacet_all (pointT *point, realT *bestdist, boolT *isoutside,
 
1228
                          int *numpart) {
 
1229
  facetT *bestfacet= NULL, *facet;
 
1230
  realT dist;
 
1231
  int totpart= 0;
 
1232
  
 
1233
  *bestdist= REALmin;
 
1234
  *isoutside= False;
 
1235
  FORALLfacets {
 
1236
    if (facet->flipped || !facet->normal)
 
1237
      continue;
 
1238
    totpart++;
 
1239
    qh_distplane (point, facet, &dist);
 
1240
    if (dist > *bestdist) {
 
1241
      *bestdist= dist;
 
1242
      bestfacet= facet;
 
1243
      if (dist > qh MINoutside) {
 
1244
        *isoutside= True;
 
1245
        break;
 
1246
      }
 
1247
    }
 
1248
  }
 
1249
  *numpart= totpart;
 
1250
  trace3((qh ferr, "qh_findfacet_all: f%d dist %2.2g isoutside %d totpart %d\n",
 
1251
          getid_(bestfacet), *bestdist, *isoutside, totpart));
 
1252
  return bestfacet;
 
1253
} /* findfacet_all */ 
 
1254
 
 
1255
/*-<a                             href="qh-poly.htm#TOC"
 
1256
  >-------------------------------</a><a name="findgood">-</a>
 
1257
  
 
1258
  qh_findgood( facetlist, goodhorizon )
 
1259
    identify good facets for qh.PRINTgood
 
1260
    if qh.GOODvertex>0
 
1261
      facet includes point as vertex
 
1262
      if !match, returns goodhorizon
 
1263
      inactive if qh.MERGING
 
1264
    if qh.GOODpoint
 
1265
      facet is visible or coplanar (>0) or not visible (<0) 
 
1266
    if qh.GOODthreshold
 
1267
      facet->normal matches threshold
 
1268
    if !goodhorizon and !match, 
 
1269
      selects facet with closest angle
 
1270
      sets GOODclosest
 
1271
      
 
1272
  returns:
 
1273
    number of new, good facets found
 
1274
    determines facet->good
 
1275
    may update qh.GOODclosest
 
1276
    
 
1277
  notes:
 
1278
    qh_findgood_all further reduces the good region
 
1279
 
 
1280
  design:
 
1281
    count good facets
 
1282
    mark good facets for qh.GOODpoint  
 
1283
    mark good facets for qh.GOODthreshold
 
1284
    if necessary
 
1285
      update qh.GOODclosest  
 
1286
*/
 
1287
int qh_findgood (facetT *facetlist, int goodhorizon) {
 
1288
  facetT *facet, *bestfacet= NULL;
 
1289
  realT angle, bestangle= REALmax, dist;
 
1290
  int  numgood=0;
 
1291
 
 
1292
  FORALLfacet_(facetlist) {
 
1293
    if (facet->good)
 
1294
      numgood++;
 
1295
  }
 
1296
  if (qh GOODvertex>0 && !qh MERGING) {
 
1297
    FORALLfacet_(facetlist) {
 
1298
      if (!qh_isvertex (qh GOODvertexp, facet->vertices)) {
 
1299
        facet->good= False;
 
1300
        numgood--;
 
1301
      }
 
1302
    }
 
1303
  }
 
1304
  if (qh GOODpoint && numgood) {
 
1305
    FORALLfacet_(facetlist) {
 
1306
      if (facet->good && facet->normal) {
 
1307
        zinc_(Zdistgood);
 
1308
        qh_distplane (qh GOODpointp, facet, &dist);
 
1309
        if ((qh GOODpoint > 0) ^ (dist > 0.0)) {
 
1310
          facet->good= False;
 
1311
          numgood--;
 
1312
        }
 
1313
      }
 
1314
    }
 
1315
  }
 
1316
  if (qh GOODthreshold && (numgood || goodhorizon || qh GOODclosest)) {
 
1317
    FORALLfacet_(facetlist) {
 
1318
      if (facet->good && facet->normal) {
 
1319
        if (!qh_inthresholds (facet->normal, &angle)) {
 
1320
          facet->good= False;
 
1321
          numgood--;
 
1322
          if (angle < bestangle) {
 
1323
            bestangle= angle;
 
1324
            bestfacet= facet;
 
1325
          }
 
1326
        }
 
1327
      }
 
1328
    }
 
1329
    if (!numgood && (!goodhorizon || qh GOODclosest)) {
 
1330
      if (qh GOODclosest) {
 
1331
        if (qh GOODclosest->visible)
 
1332
          qh GOODclosest= NULL;
 
1333
        else {
 
1334
          qh_inthresholds (qh GOODclosest->normal, &angle);
 
1335
          if (angle < bestangle)
 
1336
            bestfacet= qh GOODclosest;
 
1337
        }
 
1338
      }
 
1339
      if (bestfacet && bestfacet != qh GOODclosest) {
 
1340
        if (qh GOODclosest)
 
1341
          qh GOODclosest->good= False;
 
1342
        qh GOODclosest= bestfacet;
 
1343
        bestfacet->good= True;
 
1344
        numgood++;
 
1345
        trace2((qh ferr, "qh_findgood: f%d is closest (%2.2g) to thresholds\n", 
 
1346
           bestfacet->id, bestangle));
 
1347
        return numgood;
 
1348
      }
 
1349
    }else if (qh GOODclosest) { /* numgood > 0 */
 
1350
      qh GOODclosest->good= False;
 
1351
      qh GOODclosest= NULL;
 
1352
    }
 
1353
  }
 
1354
  zadd_(Zgoodfacet, numgood);
 
1355
  trace2((qh ferr, "qh_findgood: found %d good facets with %d good horizon\n",
 
1356
               numgood, goodhorizon));
 
1357
  if (!numgood && qh GOODvertex>0 && !qh MERGING) 
 
1358
    return goodhorizon;
 
1359
  return numgood;
 
1360
} /* findgood */
 
1361
 
 
1362
/*-<a                             href="qh-poly.htm#TOC"
 
1363
  >-------------------------------</a><a name="findgood_all">-</a>
 
1364
  
 
1365
  qh_findgood_all( facetlist )
 
1366
    apply other constraints for good facets (used by qh.PRINTgood)
 
1367
    if qh.GOODvertex 
 
1368
      facet includes (>0) or doesn't include (<0) point as vertex
 
1369
      if last good facet and ONLYgood, prints warning and continues
 
1370
    if qh.SPLITthresholds
 
1371
      facet->normal matches threshold, or if none, the closest one
 
1372
    calls qh_findgood
 
1373
    nop if good not used
 
1374
 
 
1375
  returns:
 
1376
    clears facet->good if not good
 
1377
    sets qh.num_good
 
1378
 
 
1379
  notes:
 
1380
    this is like qh_findgood but more restrictive
 
1381
 
 
1382
  design:
 
1383
    uses qh_findgood to mark good facets
 
1384
    marks facets for qh.GOODvertex
 
1385
    marks facets for qh.SPLITthreholds  
 
1386
*/
 
1387
void qh_findgood_all (facetT *facetlist) {
 
1388
  facetT *facet, *bestfacet=NULL;
 
1389
  realT angle, bestangle= REALmax;
 
1390
  int  numgood=0, startgood;
 
1391
 
 
1392
  if (!qh GOODvertex && !qh GOODthreshold && !qh GOODpoint 
 
1393
  && !qh SPLITthresholds)
 
1394
    return;
 
1395
  if (!qh ONLYgood)
 
1396
    qh_findgood (qh facet_list, 0);
 
1397
  FORALLfacet_(facetlist) {
 
1398
    if (facet->good)
 
1399
      numgood++;
 
1400
  }
 
1401
  if (qh GOODvertex <0 || (qh GOODvertex > 0 && qh MERGING)) {
 
1402
    FORALLfacet_(facetlist) {
 
1403
      if (facet->good && ((qh GOODvertex > 0) ^ !!qh_isvertex (qh GOODvertexp, facet->vertices))) {
 
1404
        if (!--numgood) {
 
1405
          if (qh ONLYgood) {
 
1406
            fprintf (qh ferr, "qhull warning: good vertex p%d does not match last good facet f%d.  Ignored.\n",
 
1407
               qh_pointid(qh GOODvertexp), facet->id);
 
1408
            return;
 
1409
          }else if (qh GOODvertex > 0)
 
1410
            fprintf (qh ferr, "qhull warning: point p%d is not a vertex ('QV%d').\n",
 
1411
                qh GOODvertex-1, qh GOODvertex-1);
 
1412
          else
 
1413
            fprintf (qh ferr, "qhull warning: point p%d is a vertex for every facet ('QV-%d').\n",
 
1414
                -qh GOODvertex - 1, -qh GOODvertex - 1);
 
1415
        }
 
1416
        facet->good= False;
 
1417
      }
 
1418
    }
 
1419
  }
 
1420
  startgood= numgood;
 
1421
  if (qh SPLITthresholds) {
 
1422
    FORALLfacet_(facetlist) {
 
1423
      if (facet->good) {
 
1424
        if (!qh_inthresholds (facet->normal, &angle)) {
 
1425
          facet->good= False;
 
1426
          numgood--;
 
1427
          if (angle < bestangle) {
 
1428
            bestangle= angle;
 
1429
            bestfacet= facet;
 
1430
          }
 
1431
        }
 
1432
      }
 
1433
    }
 
1434
    if (!numgood && bestfacet) {
 
1435
      bestfacet->good= True;
 
1436
      numgood++;
 
1437
      trace0((qh ferr, "qh_findgood_all: f%d is closest (%2.2g) to thresholds\n", 
 
1438
           bestfacet->id, bestangle));
 
1439
      return;
 
1440
    }
 
1441
  }
 
1442
  qh num_good= numgood;
 
1443
  trace0((qh ferr, "qh_findgood_all: %d good facets remain out of %d facets\n",
 
1444
        numgood, startgood));
 
1445
} /* findgood_all */
 
1446
 
 
1447
/*-<a                             href="qh-poly.htm#TOC"
 
1448
  >-------------------------------</a><a name="furthestnext">-</a>
 
1449
  
 
1450
  qh_furthestnext()
 
1451
    set qh.facet_next to facet with furthest of all furthest points
 
1452
    searches all facets on qh.facet_list
 
1453
 
 
1454
  notes:
 
1455
    this may help avoid precision problems
 
1456
*/
 
1457
void qh_furthestnext (void /* qh facet_list */) {
 
1458
  facetT *facet, *bestfacet= NULL;
 
1459
  realT dist, bestdist= -REALmax;
 
1460
 
 
1461
  FORALLfacets {
 
1462
    if (facet->outsideset) {
 
1463
#if qh_COMPUTEfurthest
 
1464
      pointT *furthest;
 
1465
      furthest= (pointT*)qh_setlast (facet->outsideset);
 
1466
      zinc_(Zcomputefurthest);
 
1467
      qh_distplane (furthest, facet, &dist);
 
1468
#else
 
1469
      dist= facet->furthestdist;
 
1470
#endif
 
1471
      if (dist > bestdist) {
 
1472
        bestfacet= facet;
 
1473
        bestdist= dist;
 
1474
      }
 
1475
    }
 
1476
  }
 
1477
  if (bestfacet) {
 
1478
    qh_removefacet (bestfacet);
 
1479
    qh_prependfacet (bestfacet, &qh facet_next);
 
1480
    trace1((qh ferr, "qh_furthestnext: made f%d next facet (dist %.2g)\n",
 
1481
            bestfacet->id, bestdist));
 
1482
  }
 
1483
} /* furthestnext */
 
1484
 
 
1485
/*-<a                             href="qh-poly.htm#TOC"
 
1486
  >-------------------------------</a><a name="furthestout">-</a>
 
1487
  
 
1488
  qh_furthestout( facet )
 
1489
    make furthest outside point the last point of outsideset
 
1490
 
 
1491
  returns:
 
1492
    updates facet->outsideset
 
1493
    clears facet->notfurthest
 
1494
    sets facet->furthestdist
 
1495
 
 
1496
  design:
 
1497
    determine best point of outsideset
 
1498
    make it the last point of outsideset
 
1499
*/
 
1500
void qh_furthestout (facetT *facet) {
 
1501
  pointT *point, **pointp, *bestpoint= NULL;
 
1502
  realT dist, bestdist= -REALmax;
 
1503
 
 
1504
  FOREACHpoint_(facet->outsideset) {
 
1505
    qh_distplane (point, facet, &dist);
 
1506
    zinc_(Zcomputefurthest);
 
1507
    if (dist > bestdist) {
 
1508
      bestpoint= point;
 
1509
      bestdist= dist;
 
1510
    }
 
1511
  }
 
1512
  if (bestpoint) {
 
1513
    qh_setdel (facet->outsideset, point);
 
1514
    qh_setappend (&facet->outsideset, point);
 
1515
#if !qh_COMPUTEfurthest
 
1516
    facet->furthestdist= bestdist;
 
1517
#endif
 
1518
  }
 
1519
  facet->notfurthest= False;
 
1520
  trace3((qh ferr, "qh_furthestout: p%d is furthest outside point of f%d\n",
 
1521
          qh_pointid (point), facet->id));
 
1522
} /* furthestout */
 
1523
 
 
1524
 
 
1525
/*-<a                             href="qh-qhull.htm#TOC"
 
1526
  >-------------------------------</a><a name="infiniteloop">-</a>
 
1527
  
 
1528
  qh_infiniteloop( facet )
 
1529
    report infinite loop error due to facet
 
1530
*/
 
1531
void qh_infiniteloop (facetT *facet) {
 
1532
 
 
1533
  fprintf (qh ferr, "qhull internal error (qh_infiniteloop): potential infinite loop detected\n");
 
1534
  qh_errexit (qh_ERRqhull, facet, NULL);
 
1535
} /* qh_infiniteloop */
 
1536
 
 
1537
/*-<a                             href="qh-poly.htm#TOC"
 
1538
  >-------------------------------</a><a name="initbuild">-</a>
 
1539
  
 
1540
  qh_initbuild()
 
1541
    initialize hull and outside sets with point array
 
1542
    qh.FIRSTpoint/qh.NUMpoints is point array
 
1543
    if qh.GOODpoint
 
1544
      adds qh.GOODpoint to initial hull
 
1545
 
 
1546
  returns:
 
1547
    qh_facetlist with initial hull
 
1548
    points partioned into outside sets, coplanar sets, or inside
 
1549
    initializes qh.GOODpointp, qh.GOODvertexp,
 
1550
 
 
1551
  design:
 
1552
    initialize global variables used during qh_buildhull
 
1553
    determine precision constants and points with max/min coordinate values
 
1554
      if qh.SCALElast, scale last coordinate (for 'd')
 
1555
    build initial simplex
 
1556
    partition input points into facets of initial simplex
 
1557
    set up lists
 
1558
    if qh.ONLYgood
 
1559
      check consistency  
 
1560
      add qh.GOODvertex if defined
 
1561
*/
 
1562
void qh_initbuild( void) {
 
1563
  setT *maxpoints, *vertices;
 
1564
  facetT *facet;
 
1565
  int i, numpart;
 
1566
  realT dist;
 
1567
  boolT isoutside;
 
1568
 
 
1569
  qh furthest_id= -1;
 
1570
  qh lastreport= 0;
 
1571
  qh facet_id= qh vertex_id= qh ridge_id= 0;
 
1572
  qh visit_id= qh vertex_visit= 0;
 
1573
  qh maxoutdone= False;
 
1574
 
 
1575
  if (qh GOODpoint > 0) 
 
1576
    qh GOODpointp= qh_point (qh GOODpoint-1);
 
1577
  else if (qh GOODpoint < 0) 
 
1578
    qh GOODpointp= qh_point (-qh GOODpoint-1);
 
1579
  if (qh GOODvertex > 0)
 
1580
    qh GOODvertexp= qh_point (qh GOODvertex-1);
 
1581
  else if (qh GOODvertex < 0) 
 
1582
    qh GOODvertexp= qh_point (-qh GOODvertex-1);
 
1583
  if ((qh GOODpoint  
 
1584
       && (qh GOODpointp < qh first_point  /* also catches !GOODpointp */
 
1585
           || qh GOODpointp > qh_point (qh num_points-1)))
 
1586
    || (qh GOODvertex
 
1587
        && (qh GOODvertexp < qh first_point  /* also catches !GOODvertexp */
 
1588
            || qh GOODvertexp > qh_point (qh num_points-1)))) {
 
1589
    fprintf (qh ferr, "qhull input error: either QGn or QVn point is > p%d\n",
 
1590
             qh num_points-1);
 
1591
    qh_errexit (qh_ERRinput, NULL, NULL);
 
1592
  }
 
1593
  maxpoints= qh_maxmin(qh first_point, qh num_points, qh hull_dim);
 
1594
  if (qh SCALElast)
 
1595
    qh_scalelast (qh first_point, qh num_points, qh hull_dim,
 
1596
               qh MINlastcoord, qh MAXlastcoord, qh MAXwidth);
 
1597
  qh_detroundoff();
 
1598
  if (qh DELAUNAY && qh upper_threshold[qh hull_dim-1] > REALmax/2
 
1599
                  && qh lower_threshold[qh hull_dim-1] < -REALmax/2) {
 
1600
    for (i= qh_PRINTEND; i--; ) {
 
1601
      if (qh PRINTout[i] == qh_PRINTgeom && qh DROPdim < 0 
 
1602
          && !qh GOODthreshold && !qh SPLITthresholds)
 
1603
        break;  /* in this case, don't set upper_threshold */
 
1604
    }
 
1605
    if (i < 0) {
 
1606
      if (qh UPPERdelaunay) { /* matches qh.upperdelaunay in qh_setfacetplane */
 
1607
        qh lower_threshold[qh hull_dim-1]= qh ANGLEround * qh_ZEROdelaunay;
 
1608
        qh GOODthreshold= True;
 
1609
      }else { 
 
1610
        qh upper_threshold[qh hull_dim-1]= -qh ANGLEround * qh_ZEROdelaunay;
 
1611
        if (!qh GOODthreshold) 
 
1612
          qh SPLITthresholds= True; /* build upper-convex hull even if Qg */
 
1613
          /* qh_initqhull_globals errors if Qg without Pdk/etc. */
 
1614
      }
 
1615
    }
 
1616
  }
 
1617
  vertices= qh_initialvertices(qh hull_dim, maxpoints, qh first_point, qh num_points); 
 
1618
  qh_initialhull (vertices);  /* initial qh facet_list */
 
1619
  qh_partitionall (vertices, qh first_point, qh num_points);
 
1620
  if (qh PRINToptions1st || qh TRACElevel || qh IStracing) {
 
1621
    if (qh TRACElevel || qh IStracing)
 
1622
      fprintf (qh ferr, "\nTrace level %d for %s | %s\n", 
 
1623
         qh IStracing ? qh IStracing : qh TRACElevel, qh rbox_command, qh qhull_command);
 
1624
    fprintf (qh ferr, "Options selected for Qhull %s:\n%s\n", qh_VERSION, qh qhull_options);
 
1625
  }
 
1626
  qh_resetlists (False, qh_RESETvisible /*qh visible_list newvertex_list newfacet_list */);
 
1627
  qh facet_next= qh facet_list;
 
1628
  qh_furthestnext (/* qh facet_list */);
 
1629
  if (qh PREmerge) {
 
1630
    qh cos_max= qh premerge_cos;
 
1631
    qh centrum_radius= qh premerge_centrum;
 
1632
  }
 
1633
  if (qh ONLYgood) {
 
1634
    if (qh GOODvertex > 0 && qh MERGING) {
 
1635
      fprintf (qh ferr, "qhull input error: 'Qg QVn' (only good vertex) does not work with merging.\nUse 'QJ' to joggle the input or 'Q0' to turn off merging.\n");
 
1636
      qh_errexit (qh_ERRinput, NULL, NULL);
 
1637
    }
 
1638
    if (!(qh GOODthreshold || qh GOODpoint
 
1639
         || (!qh MERGEexact && !qh PREmerge && qh GOODvertexp))) {
 
1640
      fprintf (qh ferr, "qhull input error: 'Qg' (ONLYgood) needs a good threshold ('Pd0D0'), a\n\
 
1641
good point (QGn or QG-n), or a good vertex with 'QJ' or 'Q0' (QVn).\n");
 
1642
      qh_errexit (qh_ERRinput, NULL, NULL);
 
1643
    }
 
1644
    if (qh GOODvertex > 0  && !qh MERGING  /* matches qh_partitionall */
 
1645
        && !qh_isvertex (qh GOODvertexp, vertices)) {
 
1646
      facet= qh_findbestnew (qh GOODvertexp, qh facet_list, 
 
1647
                          &dist, !qh_ALL, &isoutside, &numpart);
 
1648
      zadd_(Zdistgood, numpart);
 
1649
      if (!isoutside) {
 
1650
        fprintf (qh ferr, "qhull input error: point for QV%d is inside initial simplex.  It can not be made a vertex.\n",
 
1651
               qh_pointid(qh GOODvertexp));
 
1652
        qh_errexit (qh_ERRinput, NULL, NULL);
 
1653
      }
 
1654
      if (!qh_addpoint (qh GOODvertexp, facet, False)) {
 
1655
        qh_settempfree(&vertices);
 
1656
        qh_settempfree(&maxpoints);
 
1657
        return;
 
1658
      }
 
1659
    }
 
1660
    qh_findgood (qh facet_list, 0);
 
1661
  }
 
1662
  qh_settempfree(&vertices);
 
1663
  qh_settempfree(&maxpoints);
 
1664
  trace1((qh ferr, "qh_initbuild: initial hull created and points partitioned\n"));
 
1665
} /* initbuild */
 
1666
 
 
1667
/*-<a                             href="qh-poly.htm#TOC"
 
1668
  >-------------------------------</a><a name="initialhull">-</a>
 
1669
  
 
1670
  qh_initialhull( vertices )
 
1671
    constructs the initial hull as a DIM3 simplex of vertices
 
1672
 
 
1673
  design:
 
1674
    creates a simplex (initializes lists)
 
1675
    determines orientation of simplex
 
1676
    sets hyperplanes for facets
 
1677
    doubles checks orientation (in case of axis-parallel facets with Gaussian elimination)
 
1678
    checks for flipped facets and qh.NARROWhull
 
1679
    checks the result   
 
1680
*/
 
1681
void qh_initialhull(setT *vertices) {
 
1682
  facetT *facet, *firstfacet, *neighbor, **neighborp;
 
1683
  realT dist, angle, minangle= REALmax;
 
1684
#ifndef qh_NOtrace
 
1685
  int k;
 
1686
#endif
 
1687
 
 
1688
  qh_createsimplex(vertices);  /* qh facet_list */
 
1689
  qh_resetlists (False, qh_RESETvisible);
 
1690
  qh facet_next= qh facet_list;      /* advance facet when processed */
 
1691
  qh interior_point= qh_getcenter(vertices);
 
1692
  firstfacet= qh facet_list;
 
1693
  qh_setfacetplane(firstfacet);
 
1694
  zinc_(Znumvisibility); /* needs to be in printsummary */
 
1695
  qh_distplane(qh interior_point, firstfacet, &dist);
 
1696
  if (dist > 0) {  
 
1697
    FORALLfacets
 
1698
      facet->toporient ^= True;
 
1699
  }
 
1700
  FORALLfacets
 
1701
    qh_setfacetplane(facet);
 
1702
  FORALLfacets {
 
1703
    if (!qh_checkflipped (facet, NULL, qh_ALL)) {/* due to axis-parallel facet */
 
1704
      trace1((qh ferr, "qh_initialhull: initial orientation incorrect.  Correct all facets\n"));
 
1705
      facet->flipped= False;
 
1706
      FORALLfacets {
 
1707
        facet->toporient ^= True;
 
1708
        qh_orientoutside (facet);
 
1709
      }
 
1710
      break;
 
1711
    }
 
1712
  }
 
1713
  FORALLfacets {
 
1714
    if (!qh_checkflipped (facet, NULL, !qh_ALL)) {  /* can happen with 'R0.1' */
 
1715
      qh_precision ("initial facet is coplanar with interior point");
 
1716
      fprintf (qh ferr, "qhull precision error: initial facet %d is coplanar with the interior point\n",
 
1717
                   facet->id);
 
1718
      qh_errexit (qh_ERRsingular, facet, NULL);
 
1719
    }
 
1720
    FOREACHneighbor_(facet) {
 
1721
      angle= qh_getangle (facet->normal, neighbor->normal);
 
1722
      minimize_( minangle, angle);
 
1723
    }
 
1724
  }
 
1725
  if (minangle < qh_MAXnarrow && !qh NOnarrow) { 
 
1726
    realT diff= 1.0 + minangle;
 
1727
 
 
1728
    qh NARROWhull= True;
 
1729
    qh_option ("_narrow-hull", NULL, &diff);
 
1730
    if (minangle < qh_WARNnarrow && !qh RERUN && qh PRINTprecision)
 
1731
      fprintf (qh ferr, "qhull precision warning: \n\
 
1732
The initial hull is narrow (cosine of min. angle is %.16f).\n\
 
1733
A coplanar point may lead to a wide facet.  Options 'QbB' (scale to unit box)\n\
 
1734
or 'Qbb' (scale last coordinate) may remove this warning.  Use 'Pp' to skip\n\
 
1735
this warning.  See 'Limitations' in qh-impre.htm.\n",
 
1736
          -minangle);   /* convert from angle between normals to angle between facets */
 
1737
  }
 
1738
  zzval_(Zprocessed)= qh hull_dim+1;
 
1739
  qh_checkpolygon (qh facet_list);
 
1740
  qh_checkconvex(qh facet_list,   qh_DATAfault);
 
1741
#ifndef qh_NOtrace
 
1742
  if (qh IStracing >= 1) {
 
1743
    fprintf(qh ferr, "qh_initialhull: simplex constructed, interior point:");
 
1744
    for (k=0; k < qh hull_dim; k++) 
 
1745
      fprintf (qh ferr, " %6.4g", qh interior_point[k]);
 
1746
    fprintf (qh ferr, "\n");
 
1747
  }
 
1748
#endif
 
1749
} /* initialhull */
 
1750
 
 
1751
/*-<a                             href="qh-poly.htm#TOC"
 
1752
  >-------------------------------</a><a name="initialvertices">-</a>
 
1753
  
 
1754
  qh_initialvertices( dim, maxpoints, points, numpoints )
 
1755
    determines a non-singular set of initial vertices
 
1756
    maxpoints may include duplicate points
 
1757
 
 
1758
  returns:
 
1759
    temporary set of dim+1 vertices in descending order by vertex id
 
1760
    if qh.RANDOMoutside && !qh.ALLpoints
 
1761
      picks random points
 
1762
    if dim >= qh_INITIALmax, 
 
1763
      uses min/max x and max points with non-zero determinants
 
1764
 
 
1765
  notes:
 
1766
    unless qh.ALLpoints, 
 
1767
      uses maxpoints as long as determinate is non-zero
 
1768
*/
 
1769
setT *qh_initialvertices(int dim, setT *maxpoints, pointT *points, int numpoints) {
 
1770
  pointT *point, **pointp;
 
1771
  setT *vertices, *simplex, *tested;
 
1772
  realT randr;
 
1773
  int index, point_i, point_n, k;
 
1774
  boolT nearzero= False;
 
1775
  
 
1776
  vertices= qh_settemp (dim + 1);
 
1777
  simplex= qh_settemp (dim+1);
 
1778
  if (qh ALLpoints) 
 
1779
    qh_maxsimplex (dim, NULL, points, numpoints, &simplex);
 
1780
  else if (qh RANDOMoutside) {
 
1781
    while (qh_setsize (simplex) != dim+1) {
 
1782
      randr= qh_RANDOMint;
 
1783
      randr= randr/(qh_RANDOMmax+1);
 
1784
      index= (int)floor(qh num_points * randr);
 
1785
      while (qh_setin (simplex, qh_point (index))) {
 
1786
        index++; /* in case qh_RANDOMint always returns the same value */
 
1787
        index= index < qh num_points ? index : 0;
 
1788
      }
 
1789
      qh_setappend (&simplex, qh_point (index));
 
1790
    }
 
1791
  }else if (qh hull_dim >= qh_INITIALmax) {
 
1792
    tested= qh_settemp (dim+1);
 
1793
    qh_setappend (&simplex, SETfirst_(maxpoints));   /* max and min X coord */
 
1794
    qh_setappend (&simplex, SETsecond_(maxpoints));
 
1795
    qh_maxsimplex (fmin_(qh_INITIALsearch, dim), maxpoints, points, numpoints, &simplex);
 
1796
    k= qh_setsize (simplex);
 
1797
    FOREACHpoint_i_(maxpoints) { 
 
1798
      if (point_i & 0x1) {     /* first pick up max. coord. points */
 
1799
        if (!qh_setin (simplex, point) && !qh_setin (tested, point)){
 
1800
          qh_detsimplex(point, simplex, k, &nearzero);
 
1801
          if (nearzero)
 
1802
            qh_setappend (&tested, point);
 
1803
          else {
 
1804
            qh_setappend (&simplex, point);
 
1805
            if (++k == dim)  /* use search for last point */
 
1806
              break;
 
1807
          }
 
1808
        }
 
1809
      }
 
1810
    }
 
1811
    while (k != dim && (point= (pointT*)qh_setdellast (maxpoints))) {
 
1812
      if (!qh_setin (simplex, point) && !qh_setin (tested, point)){
 
1813
        qh_detsimplex (point, simplex, k, &nearzero);
 
1814
        if (nearzero)
 
1815
          qh_setappend (&tested, point);
 
1816
        else {
 
1817
          qh_setappend (&simplex, point);
 
1818
          k++;
 
1819
        }
 
1820
      }
 
1821
    }
 
1822
    index= 0;
 
1823
    while (k != dim && (point= qh_point (index++))) {
 
1824
      if (!qh_setin (simplex, point) && !qh_setin (tested, point)){
 
1825
        qh_detsimplex (point, simplex, k, &nearzero);
 
1826
        if (!nearzero){
 
1827
          qh_setappend (&simplex, point);
 
1828
          k++;
 
1829
        }
 
1830
      }
 
1831
    }
 
1832
    qh_settempfree (&tested);
 
1833
    qh_maxsimplex (dim, maxpoints, points, numpoints, &simplex);
 
1834
  }else
 
1835
    qh_maxsimplex (dim, maxpoints, points, numpoints, &simplex);
 
1836
  FOREACHpoint_(simplex) 
 
1837
    qh_setaddnth (&vertices, 0, qh_newvertex(point)); /* descending order */
 
1838
  qh_settempfree (&simplex);
 
1839
  return vertices;
 
1840
} /* initialvertices */
 
1841
 
 
1842
 
 
1843
/*-<a                             href="qh-poly.htm#TOC"
 
1844
  >-------------------------------</a><a name="isvertex">-</a>
 
1845
  
 
1846
  qh_isvertex(  )
 
1847
    returns vertex if point is in vertex set, else returns NULL
 
1848
 
 
1849
  notes:
 
1850
    for qh.GOODvertex
 
1851
*/
 
1852
vertexT *qh_isvertex (pointT *point, setT *vertices) {
 
1853
  vertexT *vertex, **vertexp;
 
1854
 
 
1855
  FOREACHvertex_(vertices) {
 
1856
    if (vertex->point == point)
 
1857
      return vertex;
 
1858
  }
 
1859
  return NULL;
 
1860
} /* isvertex */
 
1861
 
 
1862
/*-<a                             href="qh-poly.htm#TOC"
 
1863
  >-------------------------------</a><a name="makenewfacets">-</a>
 
1864
  
 
1865
  qh_makenewfacets( point )
 
1866
    make new facets from point and qh.visible_list
 
1867
 
 
1868
  returns:
 
1869
    qh.newfacet_list= list of new facets with hyperplanes and ->newfacet
 
1870
    qh.newvertex_list= list of vertices in new facets with ->newlist set
 
1871
    
 
1872
    if (qh.ONLYgood)
 
1873
      newfacets reference horizon facets, but not vice versa
 
1874
      ridges reference non-simplicial horizon ridges, but not vice versa
 
1875
      does not change existing facets
 
1876
    else
 
1877
      sets qh.NEWfacets
 
1878
      new facets attached to horizon facets and ridges
 
1879
      for visible facets, 
 
1880
        visible->r.replace is corresponding new facet
 
1881
 
 
1882
  see also: 
 
1883
    qh_makenewplanes() -- make hyperplanes for facets
 
1884
    qh_attachnewfacets() -- attachnewfacets if not done here (qh ONLYgood)
 
1885
    qh_matchnewfacets() -- match up neighbors
 
1886
    qh_updatevertices() -- update vertex neighbors and delvertices
 
1887
    qh_deletevisible() -- delete visible facets
 
1888
    qh_checkpolygon() --check the result
 
1889
    qh_triangulate() -- triangulate a non-simplicial facet
 
1890
 
 
1891
  design:
 
1892
    for each visible facet
 
1893
      make new facets to its horizon facets
 
1894
      update its f.replace 
 
1895
      clear its neighbor set
 
1896
*/
 
1897
vertexT *qh_makenewfacets (pointT *point /*visible_list*/) {
 
1898
  facetT *visible, *newfacet= NULL, *newfacet2= NULL, *neighbor, **neighborp;
 
1899
  vertexT *apex;
 
1900
  int numnew=0;
 
1901
 
 
1902
  qh newfacet_list= qh facet_tail;
 
1903
  qh newvertex_list= qh vertex_tail;
 
1904
  apex= qh_newvertex(point);
 
1905
  qh_appendvertex (apex);  
 
1906
  qh visit_id++;
 
1907
  if (!qh ONLYgood)
 
1908
    qh NEWfacets= True;
 
1909
  FORALLvisible_facets {
 
1910
    FOREACHneighbor_(visible) 
 
1911
      neighbor->seen= False;
 
1912
    if (visible->ridges) {
 
1913
      visible->visitid= qh visit_id;
 
1914
      newfacet2= qh_makenew_nonsimplicial (visible, apex, &numnew);
 
1915
    }
 
1916
    if (visible->simplicial)
 
1917
      newfacet= qh_makenew_simplicial (visible, apex, &numnew);
 
1918
    if (!qh ONLYgood) {
 
1919
      if (newfacet2)  /* newfacet is null if all ridges defined */
 
1920
        newfacet= newfacet2;
 
1921
      if (newfacet)
 
1922
        visible->f.replace= newfacet;
 
1923
      else
 
1924
        zinc_(Zinsidevisible);
 
1925
      SETfirst_(visible->neighbors)= NULL;
 
1926
    }
 
1927
  }
 
1928
  trace1((qh ferr, "qh_makenewfacets: created %d new facets from point p%d to horizon\n",
 
1929
          numnew, qh_pointid(point)));
 
1930
  if (qh IStracing >= 4)
 
1931
    qh_printfacetlist (qh newfacet_list, NULL, qh_ALL);
 
1932
  return apex;
 
1933
} /* makenewfacets */
 
1934
 
 
1935
/*-<a                             href="qh-poly.htm#TOC"
 
1936
  >-------------------------------</a><a name="matchduplicates">-</a>
 
1937
  
 
1938
  qh_matchduplicates( atfacet, atskip, hashsize, hashcount )
 
1939
    match duplicate ridges in qh.hash_table for atfacet/atskip
 
1940
    duplicates marked with ->dupridge and qh_DUPLICATEridge
 
1941
 
 
1942
  returns:
 
1943
    picks match with worst merge (min distance apart)
 
1944
    updates hashcount
 
1945
  
 
1946
  see also:
 
1947
    qh_matchneighbor
 
1948
 
 
1949
  notes:
 
1950
 
 
1951
  design:
 
1952
    compute hash value for atfacet and atskip
 
1953
    repeat twice -- once to make best matches, once to match the rest
 
1954
      for each possible facet in qh.hash_table
 
1955
        if it is a matching facet and pass 2
 
1956
          make match 
 
1957
          unless tricoplanar, mark match for merging (qh_MERGEridge)
 
1958
          [e.g., tricoplanar RBOX s 1000 t993602376 | QHULL C-1e-3 d Qbb FA Qt]
 
1959
        if it is a matching facet and pass 1
 
1960
          test if this is a better match
 
1961
      if pass 1,
 
1962
        make best match (it will not be merged)
 
1963
*/
 
1964
#ifndef qh_NOmerge
 
1965
void qh_matchduplicates (facetT *atfacet, int atskip, int hashsize, int *hashcount) {
 
1966
  boolT same, ismatch;
 
1967
  int hash, scan;
 
1968
  facetT *facet, *newfacet, *maxmatch= NULL, *maxmatch2= NULL, *nextfacet;
 
1969
  int skip, newskip, nextskip= 0, maxskip= 0, maxskip2= 0, makematch;
 
1970
  realT maxdist= -REALmax, mindist, dist2, low, high;
 
1971
 
 
1972
  hash= (int)qh_gethash (hashsize, atfacet->vertices, qh hull_dim, 1, 
 
1973
                     SETelem_(atfacet->vertices, atskip));
 
1974
  trace2((qh ferr, "qh_matchduplicates: find duplicate matches for f%d skip %d hash %d hashcount %d\n",
 
1975
          atfacet->id, atskip, hash, *hashcount));
 
1976
  for (makematch= 0; makematch < 2; makematch++) {
 
1977
    qh visit_id++;
 
1978
    for (newfacet= atfacet, newskip= atskip; newfacet; newfacet= nextfacet, newskip= nextskip) {
 
1979
      zinc_(Zhashlookup);
 
1980
      nextfacet= NULL;
 
1981
      newfacet->visitid= qh visit_id;
 
1982
      for (scan= hash; (facet= SETelemt_(qh hash_table, scan, facetT)); 
 
1983
           scan= (++scan >= hashsize ? 0 : scan)) {
 
1984
        if (!facet->dupridge || facet->visitid == qh visit_id)
 
1985
          continue;
 
1986
        zinc_(Zhashtests);
 
1987
        if (qh_matchvertices (1, newfacet->vertices, newskip, facet->vertices, &skip, &same)) {
 
1988
          ismatch= (same == (newfacet->toporient ^ facet->toporient));
 
1989
          if (SETelemt_(facet->neighbors, skip, facetT) != qh_DUPLICATEridge) {
 
1990
            if (!makematch) {
 
1991
              fprintf (qh ferr, "qhull internal error (qh_matchduplicates): missing dupridge at f%d skip %d for new f%d skip %d hash %d\n",
 
1992
                     facet->id, skip, newfacet->id, newskip, hash);
 
1993
              qh_errexit2 (qh_ERRqhull, facet, newfacet);
 
1994
            }
 
1995
          }else if (ismatch && makematch) {
 
1996
            if (SETelemt_(newfacet->neighbors, newskip, facetT) == qh_DUPLICATEridge) {
 
1997
              SETelem_(facet->neighbors, skip)= newfacet;
 
1998
              if (newfacet->tricoplanar)
 
1999
                SETelem_(newfacet->neighbors, newskip)= facet;
 
2000
              else
 
2001
                SETelem_(newfacet->neighbors, newskip)= qh_MERGEridge;
 
2002
              *hashcount -= 2; /* removed two unmatched facets */
 
2003
              trace4((qh ferr, "qh_matchduplicates: duplicate f%d skip %d matched with new f%d skip %d merge\n",
 
2004
                    facet->id, skip, newfacet->id, newskip));
 
2005
            }
 
2006
          }else if (ismatch) {
 
2007
            mindist= qh_getdistance (facet, newfacet, &low, &high);
 
2008
            dist2= qh_getdistance (newfacet, facet, &low, &high);
 
2009
            minimize_(mindist, dist2);
 
2010
            if (mindist > maxdist) {
 
2011
              maxdist= mindist;
 
2012
              maxmatch= facet;
 
2013
              maxskip= skip;
 
2014
              maxmatch2= newfacet;
 
2015
              maxskip2= newskip;
 
2016
            }
 
2017
            trace3((qh ferr, "qh_matchduplicates: duplicate f%d skip %d new f%d skip %d at dist %2.2g, max is now f%d f%d\n",
 
2018
                    facet->id, skip, newfacet->id, newskip, mindist, 
 
2019
                    maxmatch->id, maxmatch2->id));
 
2020
          }else { /* !ismatch */
 
2021
            nextfacet= facet;
 
2022
            nextskip= skip;
 
2023
          }
 
2024
        }
 
2025
        if (makematch && !facet 
 
2026
        && SETelemt_(facet->neighbors, skip, facetT) == qh_DUPLICATEridge) {
 
2027
          fprintf (qh ferr, "qhull internal error (qh_matchduplicates): no MERGEridge match for duplicate f%d skip %d at hash %d\n",
 
2028
                     newfacet->id, newskip, hash);
 
2029
          qh_errexit (qh_ERRqhull, newfacet, NULL);
 
2030
        }
 
2031
      }
 
2032
    } /* end of for each new facet at hash */
 
2033
    if (!makematch) {
 
2034
      if (!maxmatch) {
 
2035
        fprintf (qh ferr, "qhull internal error (qh_matchduplicates): no maximum match at duplicate f%d skip %d at hash %d\n",
 
2036
                     atfacet->id, atskip, hash);
 
2037
        qh_errexit (qh_ERRqhull, atfacet, NULL);
 
2038
      }
 
2039
      SETelem_(maxmatch->neighbors, maxskip)= maxmatch2;
 
2040
      SETelem_(maxmatch2->neighbors, maxskip2)= maxmatch;
 
2041
      *hashcount -= 2; /* removed two unmatched facets */
 
2042
      zzinc_(Zmultiridge);
 
2043
      trace0((qh ferr, "qh_matchduplicates: duplicate f%d skip %d matched with new f%d skip %d keep\n",
 
2044
              maxmatch->id, maxskip, maxmatch2->id, maxskip2));
 
2045
      qh_precision ("ridge with multiple neighbors");
 
2046
      if (qh IStracing >= 4)
 
2047
        qh_errprint ("DUPLICATED/MATCH", maxmatch, maxmatch2, NULL, NULL);
 
2048
    }
 
2049
  }
 
2050
} /* matchduplicates */
 
2051
 
 
2052
/*-<a                             href="qh-poly.htm#TOC"
 
2053
  >-------------------------------</a><a name="nearcoplanar">-</a>
 
2054
  
 
2055
  qh_nearcoplanar()
 
2056
    for all facets, remove near-inside points from facet->coplanarset</li>
 
2057
    coplanar points defined by innerplane from qh_outerinner()
 
2058
 
 
2059
  returns:
 
2060
    if qh KEEPcoplanar && !qh KEEPinside
 
2061
      facet->coplanarset only contains coplanar points
 
2062
    if qh.JOGGLEmax
 
2063
      drops inner plane by another qh.JOGGLEmax diagonal since a
 
2064
        vertex could shift out while a coplanar point shifts in
 
2065
  
 
2066
  notes:
 
2067
    used for qh.PREmerge and qh.JOGGLEmax
 
2068
    must agree with computation of qh.NEARcoplanar in qh_detroundoff()
 
2069
  design:
 
2070
    if not keeping coplanar or inside points
 
2071
      free all coplanar sets
 
2072
    else if not keeping both coplanar and inside points
 
2073
      remove !coplanar or !inside points from coplanar sets
 
2074
*/
 
2075
void qh_nearcoplanar ( void /* qh.facet_list */) {
 
2076
  facetT *facet;
 
2077
  pointT *point, **pointp;
 
2078
  int numpart;
 
2079
  realT dist, innerplane;
 
2080
 
 
2081
  if (!qh KEEPcoplanar && !qh KEEPinside) {
 
2082
    FORALLfacets {
 
2083
      if (facet->coplanarset) 
 
2084
        qh_setfree( &facet->coplanarset);
 
2085
    }
 
2086
  }else if (!qh KEEPcoplanar || !qh KEEPinside) {
 
2087
    qh_outerinner (NULL, NULL, &innerplane);
 
2088
    if (qh JOGGLEmax < REALmax/2)
 
2089
      innerplane -= qh JOGGLEmax * sqrt (qh hull_dim);
 
2090
    numpart= 0;
 
2091
    FORALLfacets { 
 
2092
      if (facet->coplanarset) {
 
2093
        FOREACHpoint_(facet->coplanarset) {
 
2094
          numpart++;
 
2095
          qh_distplane (point, facet, &dist); 
 
2096
          if (dist < innerplane) {
 
2097
            if (!qh KEEPinside)
 
2098
              SETref_(point)= NULL;
 
2099
          }else if (!qh KEEPcoplanar)
 
2100
            SETref_(point)= NULL;
 
2101
        }
 
2102
        qh_setcompact (facet->coplanarset);
 
2103
      }
 
2104
    }
 
2105
    zzadd_(Zcheckpart, numpart);
 
2106
  }
 
2107
} /* nearcoplanar */
 
2108
 
 
2109
/*-<a                             href="qh-poly.htm#TOC"
 
2110
  >-------------------------------</a><a name="nearvertex">-</a>
 
2111
  
 
2112
  qh_nearvertex( facet, point, bestdist )
 
2113
    return nearest vertex in facet to point
 
2114
 
 
2115
  returns:
 
2116
    vertex and its distance
 
2117
    
 
2118
  notes:
 
2119
    if qh.DELAUNAY
 
2120
      distance is measured in the input set
 
2121
    searches neighboring tricoplanar facets (requires vertexneighbors)
 
2122
      Slow implementation.  Recomputes vertex set for each point.
 
2123
    The vertex set could be stored in the qh.keepcentrum facet.
 
2124
*/
 
2125
vertexT *qh_nearvertex (facetT *facet, pointT *point, realT *bestdistp) {
 
2126
  realT bestdist= REALmax, dist;
 
2127
  vertexT *bestvertex= NULL, *vertex, **vertexp, *apex;
 
2128
  coordT *center;
 
2129
  facetT *neighbor, **neighborp;
 
2130
  setT *vertices;
 
2131
  int dim= qh hull_dim;
 
2132
 
 
2133
  if (qh DELAUNAY)
 
2134
    dim--;
 
2135
  if (facet->tricoplanar) {
 
2136
    if (!qh VERTEXneighbors || !facet->center) {
 
2137
      fprintf(qh ferr, "qhull internal error (qh_nearvertex): qh.VERTEXneighbors and facet->center required for tricoplanar facets\n");
 
2138
      qh_errexit(qh_ERRqhull, NULL, NULL);
 
2139
    }
 
2140
    vertices= qh_settemp (qh TEMPsize);
 
2141
    apex= SETfirst_(facet->vertices);
 
2142
    center= facet->center;
 
2143
    FOREACHneighbor_(apex) {
 
2144
      if (neighbor->center == center) {
 
2145
        FOREACHvertex_(neighbor->vertices) 
 
2146
          qh_setappend(&vertices, vertex);
 
2147
      }
 
2148
    }
 
2149
  }else 
 
2150
    vertices= facet->vertices;
 
2151
  FOREACHvertex_(vertices) {
 
2152
    dist= qh_pointdist (vertex->point, point, -dim);
 
2153
    if (dist < bestdist) {
 
2154
      bestdist= dist;
 
2155
      bestvertex= vertex;
 
2156
    }
 
2157
  }
 
2158
  if (facet->tricoplanar)
 
2159
    qh_settempfree (&vertices);
 
2160
  *bestdistp= sqrt (bestdist);
 
2161
  return bestvertex;
 
2162
} /* nearvertex */
 
2163
 
 
2164
/*-<a                             href="qh-poly.htm#TOC"
 
2165
  >-------------------------------</a><a name="newhashtable">-</a>
 
2166
  
 
2167
  qh_newhashtable( newsize )
 
2168
    returns size of qh.hash_table of at least newsize slots
 
2169
 
 
2170
  notes:
 
2171
    assumes qh.hash_table is NULL
 
2172
    qh_HASHfactor determines the number of extra slots
 
2173
    size is not divisible by 2, 3, or 5
 
2174
*/
 
2175
int qh_newhashtable(int newsize) {
 
2176
  int size;
 
2177
 
 
2178
  size= ((newsize+1)*qh_HASHfactor) | 0x1;  /* odd number */
 
2179
  while (True) { 
 
2180
    if ((size%3) && (size%5))
 
2181
      break;
 
2182
    size += 2;
 
2183
    /* loop terminates because there is an infinite number of primes */
 
2184
  }
 
2185
  qh hash_table= qh_setnew (size);
 
2186
  qh_setzero (qh hash_table, 0, size);
 
2187
  return size;
 
2188
} /* newhashtable */
 
2189
 
 
2190
/*-<a                             href="qh-poly.htm#TOC"
 
2191
  >-------------------------------</a><a name="newvertex">-</a>
 
2192
  
 
2193
  qh_newvertex( point )
 
2194
    returns a new vertex for point
 
2195
*/
 
2196
vertexT *qh_newvertex(pointT *point) {
 
2197
  vertexT *vertex;
 
2198
 
 
2199
  zinc_(Ztotvertices);
 
2200
  vertex= (vertexT *)qh_memalloc(sizeof(vertexT));
 
2201
  memset ((char *) vertex, 0, sizeof (vertexT));
 
2202
  if (qh vertex_id == 0xFFFFFF) {
 
2203
    fprintf(qh ferr, "qhull input error: more than %d vertices.  ID field overflows and two vertices\n\
 
2204
may have the same identifier.  Vertices not sorted correctly.\n", 0xFFFFFF);
 
2205
    qh_errexit(qh_ERRinput, NULL, NULL);
 
2206
  }
 
2207
  if (qh vertex_id == qh tracevertex_id)
 
2208
    qh tracevertex= vertex;
 
2209
  vertex->id= qh vertex_id++;
 
2210
  vertex->point= point;
 
2211
  trace4((qh ferr, "qh_newvertex: vertex p%d (v%d) created\n", qh_pointid(vertex->point), 
 
2212
          vertex->id));
 
2213
  return (vertex);
 
2214
} /* newvertex */
 
2215
 
 
2216
/*-<a                             href="qh-poly.htm#TOC"
 
2217
  >-------------------------------</a><a name="nextridge3d">-</a>
 
2218
  
 
2219
  qh_nextridge3d( atridge, facet, vertex )
 
2220
    return next ridge and vertex for a 3d facet
 
2221
 
 
2222
  notes:
 
2223
    in qh_ORIENTclock order
 
2224
    this is a O(n^2) implementation to trace all ridges
 
2225
    be sure to stop on any 2nd visit
 
2226
  
 
2227
  design:
 
2228
    for each ridge
 
2229
      exit if it is the ridge after atridge
 
2230
*/
 
2231
ridgeT *qh_nextridge3d (ridgeT *atridge, facetT *facet, vertexT **vertexp) {
 
2232
  vertexT *atvertex, *vertex, *othervertex;
 
2233
  ridgeT *ridge, **ridgep;
 
2234
 
 
2235
  if ((atridge->top == facet) ^ qh_ORIENTclock)
 
2236
    atvertex= SETsecondt_(atridge->vertices, vertexT);
 
2237
  else
 
2238
    atvertex= SETfirstt_(atridge->vertices, vertexT);
 
2239
  FOREACHridge_(facet->ridges) {
 
2240
    if (ridge == atridge)
 
2241
      continue;
 
2242
    if ((ridge->top == facet) ^ qh_ORIENTclock) {
 
2243
      othervertex= SETsecondt_(ridge->vertices, vertexT);
 
2244
      vertex= SETfirstt_(ridge->vertices, vertexT);
 
2245
    }else {
 
2246
      vertex= SETsecondt_(ridge->vertices, vertexT);
 
2247
      othervertex= SETfirstt_(ridge->vertices, vertexT);
 
2248
    }
 
2249
    if (vertex == atvertex) {
 
2250
      if (vertexp)
 
2251
        *vertexp= othervertex;
 
2252
      return ridge;
 
2253
    }
 
2254
  }
 
2255
  return NULL;
 
2256
} /* nextridge3d */
 
2257
#else /* qh_NOmerge */
 
2258
void qh_matchduplicates (facetT *atfacet, int atskip, int hashsize, int *hashcount) {
 
2259
}
 
2260
ridgeT *qh_nextridge3d (ridgeT *atridge, facetT *facet, vertexT **vertexp) {
 
2261
 
 
2262
  return NULL;
 
2263
}
 
2264
#endif /* qh_NOmerge */
 
2265
  
 
2266
/*-<a                             href="qh-poly.htm#TOC"
 
2267
  >-------------------------------</a><a name="outcoplanar">-</a>
 
2268
  
 
2269
  qh_outcoplanar()
 
2270
    move points from all facets' outsidesets to their coplanarsets
 
2271
 
 
2272
  notes:
 
2273
    for post-processing under qh.NARROWhull
 
2274
 
 
2275
  design:
 
2276
    for each facet
 
2277
      for each outside point for facet
 
2278
        partition point into coplanar set
 
2279
*/
 
2280
void qh_outcoplanar (void /* facet_list */) {
 
2281
  pointT *point, **pointp;
 
2282
  facetT *facet;
 
2283
  realT dist;
 
2284
 
 
2285
  trace1((qh ferr, "qh_outcoplanar: move outsideset to coplanarset for qh NARROWhull\n"));
 
2286
  FORALLfacets {
 
2287
    FOREACHpoint_(facet->outsideset) {
 
2288
      qh num_outside--;
 
2289
      if (qh KEEPcoplanar || qh KEEPnearinside) {
 
2290
        qh_distplane (point, facet, &dist);
 
2291
        zinc_(Zpartition);
 
2292
        qh_partitioncoplanar (point, facet, &dist);
 
2293
      }
 
2294
    }
 
2295
    qh_setfree (&facet->outsideset);
 
2296
  }
 
2297
} /* outcoplanar */
 
2298
 
 
2299
/*-<a                             href="qh-poly.htm#TOC"
 
2300
  >-------------------------------</a><a name="point">-</a>
 
2301
  
 
2302
  qh_point( id )
 
2303
    return point for a point id, or NULL if unknown
 
2304
 
 
2305
  alternative code:
 
2306
    return ((pointT *)((unsigned   long)qh.first_point
 
2307
           + (unsigned long)((id)*qh.normal_size)));
 
2308
*/
 
2309
pointT *qh_point (int id) {
 
2310
 
 
2311
  if (id < 0)
 
2312
    return NULL;
 
2313
  if (id < qh num_points)
 
2314
    return qh first_point + id * qh hull_dim;
 
2315
  id -= qh num_points;
 
2316
  if (id < qh_setsize (qh other_points))
 
2317
    return SETelemt_(qh other_points, id, pointT);
 
2318
  return NULL;
 
2319
} /* point */
 
2320
  
 
2321
/*-<a                             href="qh-poly.htm#TOC"
 
2322
  >-------------------------------</a><a name="point_add">-</a>
 
2323
  
 
2324
  qh_point_add( set, point, elem )
 
2325
    stores elem at set[point.id]
 
2326
  
 
2327
  returns:
 
2328
    access function for qh_pointfacet and qh_pointvertex
 
2329
 
 
2330
  notes:
 
2331
    checks point.id
 
2332
*/
 
2333
void qh_point_add (setT *set, pointT *point, void *elem) {
 
2334
  int id, size;
 
2335
 
 
2336
  SETreturnsize_(set, size);
 
2337
  if ((id= qh_pointid(point)) < 0)
 
2338
    fprintf (qh ferr, "qhull internal warning (point_add): unknown point %p id %d\n", 
 
2339
      point, id);
 
2340
  else if (id >= size) {
 
2341
    fprintf (qh ferr, "qhull internal errror (point_add): point p%d is out of bounds (%d)\n",
 
2342
             id, size);
 
2343
    qh_errexit (qh_ERRqhull, NULL, NULL);
 
2344
  }else
 
2345
    SETelem_(set, id)= elem;
 
2346
} /* point_add */
 
2347
 
 
2348
 
 
2349
/*-<a                             href="qh-poly.htm#TOC"
 
2350
  >-------------------------------</a><a name="pointfacet">-</a>
 
2351
  
 
2352
  qh_pointfacet()
 
2353
    return temporary set of facet for each point
 
2354
    the set is indexed by point id
 
2355
 
 
2356
  notes:
 
2357
    vertices assigned to one of the facets
 
2358
    coplanarset assigned to the facet
 
2359
    outside set assigned to the facet
 
2360
    NULL if no facet for point (inside)
 
2361
      includes qh.GOODpointp
 
2362
 
 
2363
  access:
 
2364
    FOREACHfacet_i_(facets) { ... }
 
2365
    SETelem_(facets, i)
 
2366
  
 
2367
  design:
 
2368
    for each facet
 
2369
      add each vertex
 
2370
      add each coplanar point
 
2371
      add each outside point
 
2372
*/
 
2373
setT *qh_pointfacet (void /*qh facet_list*/) {
 
2374
  int numpoints= qh num_points + qh_setsize (qh other_points);
 
2375
  setT *facets;
 
2376
  facetT *facet;
 
2377
  vertexT *vertex, **vertexp;
 
2378
  pointT *point, **pointp;
 
2379
  
 
2380
  facets= qh_settemp (numpoints);
 
2381
  qh_setzero (facets, 0, numpoints);
 
2382
  qh vertex_visit++;
 
2383
  FORALLfacets {
 
2384
    FOREACHvertex_(facet->vertices) {
 
2385
      if (vertex->visitid != qh vertex_visit) {
 
2386
        vertex->visitid= qh vertex_visit;
 
2387
        qh_point_add (facets, vertex->point, facet);
 
2388
      }
 
2389
    }
 
2390
    FOREACHpoint_(facet->coplanarset) 
 
2391
      qh_point_add (facets, point, facet);
 
2392
    FOREACHpoint_(facet->outsideset) 
 
2393
      qh_point_add (facets, point, facet);
 
2394
  }
 
2395
  return facets;
 
2396
} /* pointfacet */
 
2397
 
 
2398
/*-<a                             href="qh-poly.htm#TOC"
 
2399
  >-------------------------------</a><a name="pointvertex">-</a>
 
2400
  
 
2401
  qh_pointvertex(  )
 
2402
    return temporary set of vertices indexed by point id
 
2403
    entry is NULL if no vertex for a point
 
2404
      this will include qh.GOODpointp
 
2405
 
 
2406
  access:
 
2407
    FOREACHvertex_i_(vertices) { ... }
 
2408
    SETelem_(vertices, i)
 
2409
*/
 
2410
setT *qh_pointvertex (void /*qh facet_list*/) {
 
2411
  int numpoints= qh num_points + qh_setsize (qh other_points);
 
2412
  setT *vertices;
 
2413
  vertexT *vertex;
 
2414
  
 
2415
  vertices= qh_settemp (numpoints);
 
2416
  qh_setzero (vertices, 0, numpoints);
 
2417
  FORALLvertices 
 
2418
    qh_point_add (vertices, vertex->point, vertex);
 
2419
  return vertices;
 
2420
} /* pointvertex */
 
2421
 
 
2422
 
 
2423
/*-<a                             href="qh-poly.htm#TOC"
 
2424
  >-------------------------------</a><a name="prependfacet">-</a>
 
2425
  
 
2426
  qh_prependfacet( facet, facetlist )
 
2427
    prepend facet to the start of a facetlist
 
2428
 
 
2429
  returns:
 
2430
    increments qh.numfacets
 
2431
    updates facetlist, qh.facet_list, facet_next
 
2432
  
 
2433
  notes:
 
2434
    be careful of prepending since it can lose a pointer.
 
2435
      e.g., can lose _next by deleting and then prepending before _next
 
2436
*/
 
2437
void qh_prependfacet(facetT *facet, facetT **facetlist) {
 
2438
  facetT *prevfacet, *list;
 
2439
  
 
2440
 
 
2441
  trace4((qh ferr, "qh_prependfacet: prepend f%d before f%d\n",
 
2442
          facet->id, getid_(*facetlist)));
 
2443
  if (!*facetlist)
 
2444
    (*facetlist)= qh facet_tail;
 
2445
  list= *facetlist;
 
2446
  prevfacet= list->previous;
 
2447
  facet->previous= prevfacet;
 
2448
  if (prevfacet)
 
2449
    prevfacet->next= facet;
 
2450
  list->previous= facet;
 
2451
  facet->next= *facetlist;
 
2452
  if (qh facet_list == list)  /* this may change *facetlist */
 
2453
    qh facet_list= facet;
 
2454
  if (qh facet_next == list)
 
2455
    qh facet_next= facet;
 
2456
  *facetlist= facet;
 
2457
  qh num_facets++;
 
2458
} /* prependfacet */
 
2459
 
 
2460
 
 
2461
/*-<a                             href="qh-poly.htm#TOC"
 
2462
  >-------------------------------</a><a name="printhashtable">-</a>
 
2463
  
 
2464
  qh_printhashtable( fp )
 
2465
    print hash table to fp
 
2466
 
 
2467
  notes:
 
2468
    not in I/O to avoid bringing io.c in
 
2469
  
 
2470
  design:
 
2471
    for each hash entry
 
2472
      if defined
 
2473
        if unmatched or will merge (NULL, qh_MERGEridge, qh_DUPLICATEridge)
 
2474
          print entry and neighbors
 
2475
*/
 
2476
void qh_printhashtable(FILE *fp) {
 
2477
  facetT *facet, *neighbor;
 
2478
  int id, facet_i, facet_n, neighbor_i= 0, neighbor_n= 0;
 
2479
  vertexT *vertex, **vertexp;
 
2480
 
 
2481
  FOREACHfacet_i_(qh hash_table) {
 
2482
    if (facet) {
 
2483
      FOREACHneighbor_i_(facet) {
 
2484
        if (!neighbor || neighbor == qh_MERGEridge || neighbor == qh_DUPLICATEridge) 
 
2485
          break;
 
2486
      }
 
2487
      if (neighbor_i == neighbor_n)
 
2488
        continue;
 
2489
      fprintf (fp, "hash %d f%d ", facet_i, facet->id);
 
2490
      FOREACHvertex_(facet->vertices)
 
2491
        fprintf (fp, "v%d ", vertex->id);
 
2492
      fprintf (fp, "\n neighbors:");
 
2493
      FOREACHneighbor_i_(facet) {
 
2494
        if (neighbor == qh_MERGEridge)
 
2495
          id= -3;
 
2496
        else if (neighbor == qh_DUPLICATEridge)
 
2497
          id= -2;
 
2498
        else
 
2499
          id= getid_(neighbor);
 
2500
        fprintf (fp, " %d", id);
 
2501
      }
 
2502
      fprintf (fp, "\n");
 
2503
    }
 
2504
  }
 
2505
} /* printhashtable */
 
2506
     
 
2507
 
 
2508
/*-<a                             href="qh-poly.htm#TOC"
 
2509
  >-------------------------------</a><a name="printlists">-</a>
 
2510
  
 
2511
  qh_printlists( fp )
 
2512
    print out facet and vertex list for debugging (without 'f/v' tags)
 
2513
*/
 
2514
void qh_printlists (void) {
 
2515
  facetT *facet;
 
2516
  vertexT *vertex;
 
2517
  int count= 0;
 
2518
  
 
2519
  fprintf (qh ferr, "qh_printlists: facets:");
 
2520
  FORALLfacets {
 
2521
    if (++count % 100 == 0)
 
2522
      fprintf (qh ferr, "\n     ");
 
2523
    fprintf (qh ferr, " %d", facet->id);
 
2524
  }
 
2525
  fprintf (qh ferr, "\n  new facets %d visible facets %d next facet for qh_addpoint %d\n  vertices (new %d):",
 
2526
     getid_(qh newfacet_list), getid_(qh visible_list), getid_(qh facet_next),
 
2527
     getid_(qh newvertex_list));
 
2528
  count = 0;
 
2529
  FORALLvertices {
 
2530
    if (++count % 100 == 0)
 
2531
      fprintf (qh ferr, "\n     ");
 
2532
    fprintf (qh ferr, " %d", vertex->id);
 
2533
  }
 
2534
  fprintf (qh ferr, "\n");
 
2535
} /* printlists */
 
2536
  
 
2537
/*-<a                             href="qh-poly.htm#TOC"
 
2538
  >-------------------------------</a><a name="resetlists">-</a>
 
2539
  
 
2540
  qh_resetlists( stats, qh_RESETvisible )
 
2541
    reset newvertex_list, newfacet_list, visible_list
 
2542
    if stats, 
 
2543
      maintains statistics
 
2544
 
 
2545
  returns:
 
2546
    visible_list is empty if qh_deletevisible was called
 
2547
*/
 
2548
void qh_resetlists (boolT stats, boolT resetVisible /*qh newvertex_list newfacet_list visible_list*/) {
 
2549
  vertexT *vertex;
 
2550
  facetT *newfacet, *visible;
 
2551
  int totnew=0, totver=0;
 
2552
  
 
2553
  if (stats) {
 
2554
    FORALLvertex_(qh newvertex_list)
 
2555
      totver++;
 
2556
    FORALLnew_facets 
 
2557
      totnew++;
 
2558
    zadd_(Zvisvertextot, totver);
 
2559
    zmax_(Zvisvertexmax, totver);
 
2560
    zadd_(Znewfacettot, totnew);
 
2561
    zmax_(Znewfacetmax, totnew);
 
2562
  }
 
2563
  FORALLvertex_(qh newvertex_list)
 
2564
    vertex->newlist= False;
 
2565
  qh newvertex_list= NULL;
 
2566
  FORALLnew_facets
 
2567
    newfacet->newfacet= False;
 
2568
  qh newfacet_list= NULL;
 
2569
  if (resetVisible) {
 
2570
    FORALLvisible_facets {
 
2571
      visible->f.replace= NULL;
 
2572
      visible->visible= False;
 
2573
    }
 
2574
    qh num_visible= 0;
 
2575
  }
 
2576
  qh visible_list= NULL; /* may still have visible facets via qh_triangulate */
 
2577
  qh NEWfacets= False;
 
2578
} /* resetlists */
 
2579
 
 
2580
/*-<a                             href="qh-poly.htm#TOC"
 
2581
  >-------------------------------</a><a name="setvoronoi_all">-</a>
 
2582
  
 
2583
  qh_setvoronoi_all()
 
2584
    compute Voronoi centers for all facets
 
2585
    includes upperDelaunay facets if qh.UPPERdelaunay ('Qu')
 
2586
 
 
2587
  returns:
 
2588
    facet->center is the Voronoi center
 
2589
    
 
2590
  notes:
 
2591
    this is unused/untested code
 
2592
      please email bradb@shore.net if this works ok for you
 
2593
  
 
2594
  use:
 
2595
    FORALLvertices {...} to locate the vertex for a point.  
 
2596
    FOREACHneighbor_(vertex) {...} to visit the Voronoi centers for a Voronoi cell.
 
2597
*/
 
2598
void qh_setvoronoi_all (void) {
 
2599
  facetT *facet;
 
2600
 
 
2601
  qh_clearcenters (qh_ASvoronoi);
 
2602
  qh_vertexneighbors();
 
2603
  
 
2604
  FORALLfacets {
 
2605
    if (!facet->normal || !facet->upperdelaunay || qh UPPERdelaunay) {
 
2606
      if (!facet->center)
 
2607
        facet->center= qh_facetcenter (facet->vertices);
 
2608
    }
 
2609
  }
 
2610
} /* setvoronoi_all */
 
2611
 
 
2612
#ifndef qh_NOmerge
 
2613
 
 
2614
/*-<a                             href="qh-poly.htm#TOC"
 
2615
  >-------------------------------</a><a name="triangulate">-</a>
 
2616
  
 
2617
  qh_triangulate()
 
2618
    triangulate non-simplicial facets on qh.facet_list, 
 
2619
    if qh.CENTERtype=qh_ASvoronoi, sets Voronoi centers of non-simplicial facets
 
2620
 
 
2621
  returns:
 
2622
    all facets simplicial
 
2623
    each tricoplanar facet has ->f.triowner == owner of ->center,normal,etc.
 
2624
 
 
2625
  notes:
 
2626
    call after qh_check_output since may switch to Voronoi centers
 
2627
    Output may overwrite ->f.triowner with ->f.area
 
2628
*/
 
2629
void qh_triangulate (void /*qh facet_list*/) {
 
2630
  facetT *facet, *nextfacet, *owner;
 
2631
  int onlygood= qh ONLYgood;
 
2632
  facetT *neighbor, *visible= NULL, *facet1, *facet2, *new_facet_list= NULL;
 
2633
  facetT *orig_neighbor= NULL, *otherfacet;
 
2634
  vertexT *new_vertex_list= NULL;
 
2635
  mergeT *merge; 
 
2636
  mergeType mergetype;
 
2637
  int neighbor_i, neighbor_n;
 
2638
 
 
2639
  trace1((qh ferr, "qh_triangulate: triangulate non-simplicial facets\n"));
 
2640
  if (qh hull_dim == 2)
 
2641
    return;
 
2642
  if (qh VORONOI) {  /* otherwise lose Voronoi centers [could rebuild vertex set from tricoplanar] */
 
2643
    qh_clearcenters (qh_ASvoronoi);
 
2644
    qh_vertexneighbors();
 
2645
  }
 
2646
  qh ONLYgood= False; /* for makenew_nonsimplicial */
 
2647
  qh visit_id++;
 
2648
  qh NEWfacets= True;
 
2649
  qh degen_mergeset= qh_settemp (qh TEMPsize);
 
2650
  qh newvertex_list= qh vertex_tail;
 
2651
  for (facet= qh facet_list; facet && facet->next; facet= nextfacet) { /* non-simplicial facets moved to end */
 
2652
    nextfacet= facet->next;
 
2653
    if (facet->visible || facet->simplicial)
 
2654
      continue;
 
2655
    /* triangulate all non-simplicial facets, otherwise merging does not work, e.g., RBOX c P-0.1 P+0.1 P+0.1 D3 | QHULL d Qt Tv */
 
2656
    if (!new_facet_list)
 
2657
      new_facet_list= facet;  /* will be moved to end */
 
2658
    qh_triangulate_facet (facet, &new_vertex_list);
 
2659
  }
 
2660
  trace2((qh ferr, "qh_triangulate: delete null facets from f%d -- apex same as second vertex\n", getid_(new_facet_list)));
 
2661
  for (facet= new_facet_list; facet && facet->next; facet= nextfacet) { /* null facets moved to end */
 
2662
    nextfacet= facet->next;
 
2663
    if (facet->visible) 
 
2664
      continue;
 
2665
    if (facet->ridges) {
 
2666
      if (qh_setsize(facet->ridges) > 0) {
 
2667
        fprintf( qh ferr, "qhull error (qh_triangulate): ridges still defined for f%d\n", facet->id);
 
2668
        qh_errexit (qh_ERRqhull, facet, NULL);
 
2669
      }
 
2670
      qh_setfree (&facet->ridges);
 
2671
    }
 
2672
    if (SETfirst_(facet->vertices) == SETsecond_(facet->vertices)) {
 
2673
      zinc_(Ztrinull);
 
2674
      qh_triangulate_null (facet);
 
2675
    }
 
2676
  }
 
2677
  trace2((qh ferr, "qh_triangulate: delete %d or more mirror facets -- same vertices and neighbors\n", qh_setsize(qh degen_mergeset)));
 
2678
  qh visible_list= qh facet_tail;
 
2679
  while ((merge= (mergeT*)qh_setdellast (qh degen_mergeset))) {
 
2680
    facet1= merge->facet1;
 
2681
    facet2= merge->facet2;
 
2682
    mergetype= merge->type;
 
2683
    qh_memfree (merge, sizeof(mergeT));
 
2684
    if (mergetype == MRGmirror) {
 
2685
      zinc_(Ztrimirror);
 
2686
      qh_triangulate_mirror (facet1, facet2);
 
2687
    }
 
2688
  }
 
2689
  qh_settempfree(&qh degen_mergeset);
 
2690
  trace2((qh ferr, "qh_triangulate: update neighbor lists for vertices from v%d\n", getid_(new_vertex_list)));
 
2691
  qh newvertex_list= new_vertex_list;  /* all vertices of new facets */
 
2692
  qh visible_list= NULL;
 
2693
  qh_updatevertices(/*qh newvertex_list, empty newfacet_list and visible_list*/);
 
2694
  qh_resetlists (False, !qh_RESETvisible /*qh newvertex_list, empty newfacet_list and visible_list*/);
 
2695
 
 
2696
  trace2((qh ferr, "qh_triangulate: identify degenerate tricoplanar facets from f%d\n", getid_(new_facet_list)));
 
2697
  trace2((qh ferr, "qh_triangulate: and replace facet->f.triowner with tricoplanar facets that own center, normal, etc.\n"));
 
2698
  FORALLfacet_(new_facet_list) {
 
2699
    if (facet->tricoplanar && !facet->visible) {
 
2700
      FOREACHneighbor_i_(facet) {
 
2701
        if (neighbor_i == 0) {  /* first iteration */
 
2702
          if (neighbor->tricoplanar)
 
2703
            orig_neighbor= neighbor->f.triowner;
 
2704
          else
 
2705
            orig_neighbor= neighbor;
 
2706
        }else {
 
2707
          if (neighbor->tricoplanar)
 
2708
            otherfacet= neighbor->f.triowner;
 
2709
          else
 
2710
            otherfacet= neighbor;
 
2711
          if (orig_neighbor == otherfacet) {
 
2712
            zinc_(Ztridegen);
 
2713
            facet->degenerate= True;
 
2714
            break;
 
2715
          }
 
2716
        }
 
2717
      }
 
2718
    }
 
2719
  }
 
2720
 
 
2721
  trace2((qh ferr, "qh_triangulate: delete visible facets -- non-simplicial, null, and mirrored facets\n"));
 
2722
  owner= NULL;
 
2723
  visible= NULL;
 
2724
  for (facet= new_facet_list; facet && facet->next; facet= nextfacet) { /* may delete facet */
 
2725
    nextfacet= facet->next;
 
2726
    if (facet->visible) {
 
2727
      if (facet->tricoplanar) { /* a null or mirrored facet */
 
2728
        qh_delfacet(facet);
 
2729
        qh num_visible--;
 
2730
      }else {  /* a non-simplicial facet followed by its tricoplanars */
 
2731
        if (visible && !owner) {
 
2732
          /*  RBOX 200 s D5 t1001471447 | QHULL Qt C-0.01 Qx Qc Tv Qt -- f4483 had 6 vertices/neighbors and 8 ridges */
 
2733
          trace2((qh ferr, "qh_triangulate: all tricoplanar facets degenerate for non-simplicial facet f%d\n",
 
2734
                       visible->id));
 
2735
          qh_delfacet(visible);
 
2736
          qh num_visible--;
 
2737
        }
 
2738
        visible= facet;
 
2739
        owner= NULL;
 
2740
      }
 
2741
    }else if (facet->tricoplanar) {
 
2742
      if (facet->f.triowner != visible) { 
 
2743
        fprintf( qh ferr, "qhull error (qh_triangulate): tricoplanar facet f%d not owned by its visible, non-simplicial facet f%d\n", facet->id, getid_(visible));
 
2744
        qh_errexit2 (qh_ERRqhull, facet, visible);
 
2745
      }
 
2746
      if (owner) 
 
2747
        facet->f.triowner= owner;
 
2748
      else if (!facet->degenerate) {
 
2749
        owner= facet;
 
2750
        nextfacet= visible->next; /* rescan tricoplanar facets with owner */
 
2751
        facet->keepcentrum= True;  /* one facet owns ->normal, etc. */
 
2752
        facet->coplanarset= visible->coplanarset;
 
2753
        facet->outsideset= visible->outsideset;
 
2754
        visible->coplanarset= NULL;
 
2755
        visible->outsideset= NULL;
 
2756
        if (!qh TRInormals) { /* center and normal copied to tricoplanar facets */
 
2757
          visible->center= NULL;
 
2758
          visible->normal= NULL;
 
2759
        }
 
2760
        qh_delfacet(visible);
 
2761
        qh num_visible--;
 
2762
      }
 
2763
    }
 
2764
  }
 
2765
  if (visible && !owner) {
 
2766
    trace2((qh ferr, "qh_triangulate: all tricoplanar facets degenerate for last non-simplicial facet f%d\n",
 
2767
                 visible->id));
 
2768
    qh_delfacet(visible);
 
2769
    qh num_visible--;
 
2770
  }
 
2771
  qh NEWfacets= False;
 
2772
  qh ONLYgood= onlygood; /* restore value */
 
2773
  if (qh CHECKfrequently) 
 
2774
    qh_checkpolygon (qh facet_list);
 
2775
} /* triangulate */
 
2776
 
 
2777
 
 
2778
/*-<a                             href="qh-poly.htm#TOC"
 
2779
  >-------------------------------</a><a name="triangulate_facet">-</a>
 
2780
  
 
2781
  qh_triangulate_facet (facetA)
 
2782
    triangulate a non-simplicial facet
 
2783
      if qh.CENTERtype=qh_ASvoronoi, sets its Voronoi center
 
2784
  returns:
 
2785
    qh.newfacet_list == simplicial facets
 
2786
      facet->tricoplanar set and ->keepcentrum false
 
2787
      facet->degenerate set if duplicated apex
 
2788
      facet->f.trivisible set to facetA
 
2789
      facet->center copied from facetA (created if qh_ASvoronoi)
 
2790
        qh_eachvoronoi, qh_detvridge, qh_detvridge3 assume centers copied
 
2791
      facet->normal,offset,maxoutside copied from facetA
 
2792
 
 
2793
  notes:
 
2794
      qh_makenew_nonsimplicial uses neighbor->seen for the same
 
2795
 
 
2796
  see also:
 
2797
      qh_addpoint() -- add a point
 
2798
      qh_makenewfacets() -- construct a cone of facets for a new vertex
 
2799
 
 
2800
  design:
 
2801
      if qh_ASvoronoi, 
 
2802
         compute Voronoi center (facet->center)
 
2803
      select first vertex (highest ID to preserve ID ordering of ->vertices)
 
2804
      triangulate from vertex to ridges
 
2805
      copy facet->center, normal, offset
 
2806
      update vertex neighbors
 
2807
*/
 
2808
void qh_triangulate_facet (facetT *facetA, vertexT **first_vertex) {
 
2809
  facetT *newfacet;
 
2810
  facetT *neighbor, **neighborp;
 
2811
  vertexT *apex;
 
2812
  int numnew=0;
 
2813
 
 
2814
  trace3((qh ferr, "qh_triangulate_facet: triangulate facet f%d\n", facetA->id));
 
2815
 
 
2816
  if (qh IStracing >= 4)
 
2817
    qh_printfacet (qh ferr, facetA);
 
2818
  FOREACHneighbor_(facetA) {
 
2819
    neighbor->seen= False;
 
2820
    neighbor->coplanar= False;
 
2821
  }
 
2822
  if (qh CENTERtype == qh_ASvoronoi && !facetA->center  /* matches upperdelaunay in qh_setfacetplane() */
 
2823
        && fabs_(facetA->normal[qh hull_dim -1]) >= qh ANGLEround * qh_ZEROdelaunay) {
 
2824
    facetA->center= qh_facetcenter (facetA->vertices);
 
2825
  }
 
2826
  qh_willdelete (facetA, NULL);
 
2827
  qh newfacet_list= qh facet_tail;
 
2828
  facetA->visitid= qh visit_id;
 
2829
  apex= SETfirst_(facetA->vertices);
 
2830
  qh_makenew_nonsimplicial (facetA, apex, &numnew);
 
2831
  SETfirst_(facetA->neighbors)= NULL;
 
2832
  FORALLnew_facets {
 
2833
    newfacet->tricoplanar= True;
 
2834
    newfacet->f.trivisible= facetA;
 
2835
    newfacet->degenerate= False;
 
2836
    newfacet->upperdelaunay= facetA->upperdelaunay;
 
2837
    newfacet->good= facetA->good;
 
2838
    if (qh TRInormals) { 
 
2839
      newfacet->keepcentrum= True;
 
2840
      newfacet->normal= qh_copypoints (facetA->normal, 1, qh hull_dim);
 
2841
      if (qh CENTERtype == qh_AScentrum) 
 
2842
        newfacet->center= qh_getcentrum (newfacet);
 
2843
      else
 
2844
        newfacet->center= qh_copypoints (facetA->center, 1, qh hull_dim);
 
2845
    }else {
 
2846
      newfacet->keepcentrum= False;
 
2847
      newfacet->normal= facetA->normal;
 
2848
      newfacet->center= facetA->center;
 
2849
    }
 
2850
    newfacet->offset= facetA->offset;
 
2851
#if qh_MAXoutside
 
2852
    newfacet->maxoutside= facetA->maxoutside;
 
2853
#endif
 
2854
  }
 
2855
  qh_matchnewfacets(/*qh newfacet_list*/);
 
2856
  zinc_(Ztricoplanar);
 
2857
  zadd_(Ztricoplanartot, numnew);
 
2858
  zmax_(Ztricoplanarmax, numnew);
 
2859
  qh visible_list= NULL;
 
2860
  if (!(*first_vertex))
 
2861
    (*first_vertex)= qh newvertex_list;
 
2862
  qh newvertex_list= NULL;
 
2863
  qh_updatevertices(/*qh newfacet_list, empty visible_list and newvertex_list*/);
 
2864
  qh_resetlists (False, !qh_RESETvisible /*qh newfacet_list, empty visible_list and newvertex_list*/);
 
2865
} /* triangulate_facet */
 
2866
 
 
2867
/*-<a                             href="qh-poly.htm#TOC"
 
2868
  >-------------------------------</a><a name="triangulate_link">-</a>
 
2869
  
 
2870
  qh_triangulate_link (oldfacetA, facetA, oldfacetB, facetB)
 
2871
    relink facetA to facetB via oldfacets
 
2872
  returns:
 
2873
    adds mirror facets to qh degen_mergeset (4-d and up only)
 
2874
  design:
 
2875
    if they are already neighbors, the opposing neighbors become MRGmirror facets
 
2876
*/
 
2877
void qh_triangulate_link (facetT *oldfacetA, facetT *facetA, facetT *oldfacetB, facetT *facetB) {
 
2878
  int errmirror= False;
 
2879
 
 
2880
  trace3((qh ferr, "qh_triangulate_link: relink old facets f%d and f%d between neighbors f%d and f%d\n", 
 
2881
         oldfacetA->id, oldfacetB->id, facetA->id, facetB->id));
 
2882
  if (qh_setin (facetA->neighbors, facetB)) {
 
2883
    if (!qh_setin (facetB->neighbors, facetA)) 
 
2884
      errmirror= True;
 
2885
    else
 
2886
      qh_appendmergeset (facetA, facetB, MRGmirror, NULL);
 
2887
  }else if (qh_setin (facetB->neighbors, facetA)) 
 
2888
    errmirror= True;
 
2889
  if (errmirror) {
 
2890
    fprintf( qh ferr, "qhull error (qh_triangulate_link): mirror facets f%d and f%d do not match for old facets f%d and f%d\n",
 
2891
       facetA->id, facetB->id, oldfacetA->id, oldfacetB->id);
 
2892
    qh_errexit2 (qh_ERRqhull, facetA, facetB);
 
2893
  }
 
2894
  qh_setreplace (facetB->neighbors, oldfacetB, facetA);
 
2895
  qh_setreplace (facetA->neighbors, oldfacetA, facetB);
 
2896
} /* triangulate_link */
 
2897
 
 
2898
/*-<a                             href="qh-poly.htm#TOC"
 
2899
  >-------------------------------</a><a name="triangulate_mirror">-</a>
 
2900
  
 
2901
  qh_triangulate_mirror (facetA, facetB)
 
2902
    delete mirrored facets from qh_triangulate_null() and qh_triangulate_mirror
 
2903
      a mirrored facet shares the same vertices of a logical ridge
 
2904
  design:
 
2905
    since a null facet duplicates the first two vertices, the opposing neighbors absorb the null facet
 
2906
    if they are already neighbors, the opposing neighbors become MRGmirror facets
 
2907
*/
 
2908
void qh_triangulate_mirror (facetT *facetA, facetT *facetB) {
 
2909
  facetT *neighbor, *neighborB;
 
2910
  int neighbor_i, neighbor_n;
 
2911
 
 
2912
  trace3((qh ferr, "qh_triangulate_mirror: delete mirrored facets f%d and f%d\n", 
 
2913
         facetA->id, facetB->id));
 
2914
  FOREACHneighbor_i_(facetA) {
 
2915
    neighborB= SETelemt_(facetB->neighbors, neighbor_i, facetT);
 
2916
    if (neighbor == neighborB)
 
2917
      continue; /* occurs twice */
 
2918
    qh_triangulate_link (facetA, neighbor, facetB, neighborB);
 
2919
  }
 
2920
  qh_willdelete (facetA, NULL);
 
2921
  qh_willdelete (facetB, NULL);
 
2922
} /* triangulate_mirror */
 
2923
 
 
2924
/*-<a                             href="qh-poly.htm#TOC"
 
2925
  >-------------------------------</a><a name="triangulate_null">-</a>
 
2926
  
 
2927
  qh_triangulate_null (facetA)
 
2928
    remove null facetA from qh_triangulate_facet()
 
2929
      a null facet has vertex #1 (apex) == vertex #2
 
2930
  returns:
 
2931
    adds facetA to ->visible for deletion after qh_updatevertices
 
2932
    qh degen_mergeset contains mirror facets (4-d and up only)
 
2933
  design:
 
2934
    since a null facet duplicates the first two vertices, the opposing neighbors absorb the null facet
 
2935
    if they are already neighbors, the opposing neighbors become MRGmirror facets
 
2936
*/
 
2937
void qh_triangulate_null (facetT *facetA) {
 
2938
  facetT *neighbor, *otherfacet;
 
2939
 
 
2940
  trace3((qh ferr, "qh_triangulate_null: delete null facet f%d\n", facetA->id));
 
2941
  neighbor= SETfirst_(facetA->neighbors);
 
2942
  otherfacet= SETsecond_(facetA->neighbors);
 
2943
  qh_triangulate_link (facetA, neighbor, facetA, otherfacet);
 
2944
  qh_willdelete (facetA, NULL);
 
2945
} /* triangulate_null */
 
2946
 
 
2947
#else /* qh_NOmerge */
 
2948
void qh_triangulate (void) {
 
2949
}
 
2950
#endif /* qh_NOmerge */
 
2951
 
 
2952
   /*-<a                             href="qh-poly.htm#TOC"
 
2953
  >-------------------------------</a><a name="vertexintersect">-</a>
 
2954
  
 
2955
  qh_vertexintersect( vertexsetA, vertexsetB )
 
2956
    intersects two vertex sets (inverse id ordered)
 
2957
    vertexsetA is a temporary set at the top of qhmem.tempstack
 
2958
 
 
2959
  returns:
 
2960
    replaces vertexsetA with the intersection
 
2961
  
 
2962
  notes:
 
2963
    could overwrite vertexsetA if currently too slow
 
2964
*/
 
2965
void qh_vertexintersect(setT **vertexsetA,setT *vertexsetB) {
 
2966
  setT *intersection;
 
2967
 
 
2968
  intersection= qh_vertexintersect_new (*vertexsetA, vertexsetB);
 
2969
  qh_settempfree (vertexsetA);
 
2970
  *vertexsetA= intersection;
 
2971
  qh_settemppush (intersection);
 
2972
} /* vertexintersect */
 
2973
 
 
2974
/*-<a                             href="qh-poly.htm#TOC"
 
2975
  >-------------------------------</a><a name="vertexintersect_new">-</a>
 
2976
  
 
2977
  qh_vertexintersect_new(  )
 
2978
    intersects two vertex sets (inverse id ordered)
 
2979
 
 
2980
  returns:
 
2981
    a new set
 
2982
*/
 
2983
setT *qh_vertexintersect_new (setT *vertexsetA,setT *vertexsetB) {
 
2984
  setT *intersection= qh_setnew (qh hull_dim - 1);
 
2985
  vertexT **vertexA= SETaddr_(vertexsetA, vertexT); 
 
2986
  vertexT **vertexB= SETaddr_(vertexsetB, vertexT); 
 
2987
 
 
2988
  while (*vertexA && *vertexB) {
 
2989
    if (*vertexA  == *vertexB) {
 
2990
      qh_setappend(&intersection, *vertexA);
 
2991
      vertexA++; vertexB++;
 
2992
    }else {
 
2993
      if ((*vertexA)->id > (*vertexB)->id)
 
2994
        vertexA++;
 
2995
      else
 
2996
        vertexB++;
 
2997
    }
 
2998
  }
 
2999
  return intersection;
 
3000
} /* vertexintersect_new */
 
3001
 
 
3002
/*-<a                             href="qh-poly.htm#TOC"
 
3003
  >-------------------------------</a><a name="vertexneighbors">-</a>
 
3004
  
 
3005
  qh_vertexneighbors()
 
3006
    for each vertex in qh.facet_list, 
 
3007
      determine its neighboring facets 
 
3008
 
 
3009
  returns:
 
3010
    sets qh.VERTEXneighbors
 
3011
      nop if qh.VERTEXneighbors already set
 
3012
      qh_addpoint() will maintain them
 
3013
 
 
3014
  notes:
 
3015
    assumes all vertex->neighbors are NULL
 
3016
 
 
3017
  design:
 
3018
    for each facet
 
3019
      for each vertex
 
3020
        append facet to vertex->neighbors
 
3021
*/
 
3022
void qh_vertexneighbors (void /*qh facet_list*/) {
 
3023
  facetT *facet;
 
3024
  vertexT *vertex, **vertexp;
 
3025
 
 
3026
  if (qh VERTEXneighbors)
 
3027
    return;
 
3028
  trace1((qh ferr, "qh_vertexneighbors: determing neighboring facets for each vertex\n"));
 
3029
  qh vertex_visit++;
 
3030
  FORALLfacets {
 
3031
    if (facet->visible)
 
3032
      continue;
 
3033
    FOREACHvertex_(facet->vertices) {
 
3034
      if (vertex->visitid != qh vertex_visit) {
 
3035
        vertex->visitid= qh vertex_visit;
 
3036
        vertex->neighbors= qh_setnew (qh hull_dim);
 
3037
      }
 
3038
      qh_setappend (&vertex->neighbors, facet);
 
3039
    }
 
3040
  }
 
3041
  qh VERTEXneighbors= True;
 
3042
} /* vertexneighbors */
 
3043
 
 
3044
/*-<a                             href="qh-poly.htm#TOC"
 
3045
  >-------------------------------</a><a name="vertexsubset">-</a>
 
3046
  
 
3047
  qh_vertexsubset( vertexsetA, vertexsetB )
 
3048
    returns True if vertexsetA is a subset of vertexsetB
 
3049
    assumes vertexsets are sorted
 
3050
 
 
3051
  note:    
 
3052
    empty set is a subset of any other set
 
3053
*/
 
3054
boolT qh_vertexsubset(setT *vertexsetA, setT *vertexsetB) {
 
3055
  vertexT **vertexA= (vertexT **) SETaddr_(vertexsetA, vertexT);
 
3056
  vertexT **vertexB= (vertexT **) SETaddr_(vertexsetB, vertexT);
 
3057
 
 
3058
  while (True) {
 
3059
    if (!*vertexA)
 
3060
      return True;
 
3061
    if (!*vertexB)
 
3062
      return False;
 
3063
    if ((*vertexA)->id > (*vertexB)->id)
 
3064
      return False;
 
3065
    if (*vertexA  == *vertexB)
 
3066
      vertexA++;
 
3067
    vertexB++; 
 
3068
  }
 
3069
  return False; /* avoid warnings */
 
3070
} /* vertexsubset */