1 /****************************************************************************
2 **
3 ** Copyright (c) 2008-2020 C.B. Barber. All rights reserved.
4 ** $Id: //main/2019/qhull/src/libqhullcpp/QhullFacet.cpp#5 $$Change: 3009 $
5 ** $DateTime: 2020/07/30 19:25:22 $$Author: bbarber $
6 **
7 ****************************************************************************/
8 
9 #//! QhullFacet -- Qhull's facet structure, facetT, as a C++ class
10 
11 #include "libqhullcpp/QhullFacet.h"
12 
13 #include "libqhullcpp/QhullError.h"
14 #include "libqhullcpp/Qhull.h"
15 #include "libqhullcpp/QhullSet.h"
16 #include "libqhullcpp/QhullPoint.h"
17 #include "libqhullcpp/QhullPointSet.h"
18 #include "libqhullcpp/QhullRidge.h"
19 #include "libqhullcpp/QhullFacetSet.h"
20 #include "libqhullcpp/QhullVertex.h"
21 
22 #include <ostream>
23 
24 using std::endl;
25 using std::ostream;
26 
27 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
28 #pragma warning( disable : 4611)  // interaction between '_setjmp' and C++ object destruction is non-portable
29 #pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
30 #endif
31 
32 namespace orgQhull {
33 
34 #//!\name Class objects
35 facetT QhullFacet::
36 s_empty_facet= {
37 #if !qh_COMPUTEfurthest         // must match facetT -Wmissing-field-initializers
38         0.0,
39 #endif
40 #if qh_MAXoutside
41         0.0,
42 #endif
43         0.0,NULL,{0.0},
44         NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,0,0,
45         false,false,false,false,false,
46         false,false,false,false,false,
47         false,false,false,false,false,
48         false,false,false,false,false,
49         false,false,false};
50 
51 #//!\name Constructors
52 
53 QhullFacet::
QhullFacet(const Qhull & q)54 QhullFacet(const Qhull &q)
55 : qh_facet(&s_empty_facet)
56 , qh_qh(q.qh())
57 {
58 }
59 
60 QhullFacet::
QhullFacet(const Qhull & q,facetT * f)61 QhullFacet(const Qhull &q, facetT *f)
62 : qh_facet(f ? f : &s_empty_facet)
63 , qh_qh(q.qh())
64 {
65 }
66 
67 #//!\name GetSet
68 
69 //! Return voronoi center or facet centrum.  Derived from qh_printcenter [io_r.c]
70 //! if printFormat=qh_PRINTtriangles and qh.DELAUNAY, returns centrum of a Delaunay facet
71 //! Sets center if needed
72 //! Code duplicated for PrintCenter and getCenter
73 //! Returns QhullPoint() if none or qh_INFINITE
74 QhullPoint QhullFacet::
getCenter(qh_PRINT printFormat)75 getCenter(qh_PRINT printFormat)
76 {
77     if(!qh_qh){
78         // returns QhullPoint()
79     }else if(qh_qh->CENTERtype==qh_ASvoronoi){
80         if(!qh_facet->normal || !qh_facet->upperdelaunay || !qh_qh->ATinfinity){
81             if(!qh_facet->center){
82                 QH_TRY_(qh_qh){ // no object creation -- destructors skipped on longjmp()
83                     qh_facet->center= qh_facetcenter(qh_qh, qh_facet->vertices);
84                 }
85                 qh_qh->NOerrexit= true;
86                 qh_qh->maybeThrowQhullMessage(QH_TRY_status);
87             }
88             return QhullPoint(qh_qh, qh_qh->hull_dim-1, qh_facet->center);
89         }
90     }else if(qh_qh->CENTERtype==qh_AScentrum){
91         volatile int numCoords= qh_qh->hull_dim;
92         if(printFormat==qh_PRINTtriangles && qh_qh->DELAUNAY){
93             numCoords--;
94         }
95         if(!qh_facet->center){
96             QH_TRY_(qh_qh){ // no object creation -- destructors skipped on longjmp()
97                 qh_facet->center= qh_getcentrum(qh_qh, getFacetT());
98             }
99             qh_qh->NOerrexit= true;
100             qh_qh->maybeThrowQhullMessage(QH_TRY_status);
101         }
102         return QhullPoint(qh_qh, numCoords, qh_facet->center);
103     }
104     return QhullPoint();
105  }//getCenter
106 
107 //! Return innerplane clearly below the vertices
108 //! from io_r.c[qh_PRINTinner]
109 QhullHyperplane QhullFacet::
innerplane() const110 innerplane() const
111 {
112     QhullHyperplane h;
113     if(qh_qh){
114         realT inner;
115         // Does not error, TRY_QHULL_ not needed
116         qh_outerinner(qh_qh, const_cast<facetT *>(getFacetT()), NULL, &inner);
117         h= hyperplane();
118         h.setOffset(h.offset()-inner); //inner is negative
119     }
120     return h;
121 }//innerplane
122 
123 QhullFacet QhullFacet::
nextFacet2d(QhullVertex * nextVertex) const124 nextFacet2d(QhullVertex *nextVertex) const
125 {
126     QhullFacet f;
127     if(qh_qh && qh_facet){
128         vertexT *vertex;
129         // Does not error, TRY_QHULL_ not needed
130         facetT *facet= qh_nextfacet2d(getFacetT(), &vertex);
131         f.setFacetT(qh_qh, facet);
132         nextVertex->setVertexT(qh_qh, vertex);
133     }
134     return f;
135 }//nextFacet2d
136 
137 //! Return outerplane clearly above all points
138 //! from io_r.c[qh_PRINTouter]
139 QhullHyperplane QhullFacet::
outerplane() const140 outerplane() const
141 {
142     QhullHyperplane h;
143     if(qh_qh){
144         realT outer;
145         // Does not error, TRY_QHULL_ not needed
146         qh_outerinner(qh_qh, const_cast<facetT *>(getFacetT()), &outer, NULL);
147         h= hyperplane();
148         h.setOffset(h.offset()-outer); //outer is positive
149     }
150     return h;
151 }//outerplane
152 
153 //! Set by qh_triangulate for option 'Qt'.
154 //! Errors if tricoplanar and facetArea() or qh_getarea() called first.
155 QhullFacet QhullFacet::
tricoplanarOwner() const156 tricoplanarOwner() const
157 {
158     if(qh_facet->tricoplanar){
159         if(qh_facet->isarea){
160             throw QhullError(10018, "Qhull error: facetArea() or qh_getarea() previously called.  triCoplanarOwner() is not available.");
161         }
162         return QhullFacet(qh_qh, qh_facet->f.triowner);
163     }
164     return QhullFacet(qh_qh);
165 }//tricoplanarOwner
166 
167 QhullPoint QhullFacet::
voronoiVertex()168 voronoiVertex()
169 {
170     if(qh_qh && qh_qh->CENTERtype!=qh_ASvoronoi){
171           throw QhullError(10052, "Error: QhullFacet.voronoiVertex() requires option 'v' (qh_ASvoronoi)");
172     }
173     return getCenter();
174 }//voronoiVertex
175 
176 #//!\name Value
177 
178 //! Disables tricoplanarOwner()
179 double QhullFacet::
facetArea()180 facetArea()
181 {
182     if(qh_qh && !qh_facet->isarea){
183         QH_TRY_(qh_qh){ // no object creation -- destructors skipped on longjmp()
184             qh_facet->f.area= qh_facetarea(qh_qh, qh_facet);
185             qh_facet->isarea= True;
186         }
187         qh_qh->NOerrexit= true;
188         qh_qh->maybeThrowQhullMessage(QH_TRY_status);
189     }
190     return qh_facet->f.area;
191 }//facetArea
192 
193 #//!\name Foreach
194 
195 QhullPointSet QhullFacet::
coplanarPoints() const196 coplanarPoints() const
197 {
198     return QhullPointSet(qh_qh, qh_facet->coplanarset);
199 }//coplanarPoints
200 
201 QhullFacetSet QhullFacet::
neighborFacets() const202 neighborFacets() const
203 {
204     return QhullFacetSet(qh_qh, qh_facet->neighbors);
205 }//neighborFacets
206 
207 QhullPointSet QhullFacet::
outsidePoints() const208 outsidePoints() const
209 {
210     return QhullPointSet(qh_qh, qh_facet->outsideset);
211 }//outsidePoints
212 
213 QhullRidgeSet QhullFacet::
ridges() const214 ridges() const
215 {
216     return QhullRidgeSet(qh_qh, qh_facet->ridges);
217 }//ridges
218 
219 QhullVertexSet QhullFacet::
vertices() const220 vertices() const
221 {
222     return QhullVertexSet(qh_qh, qh_facet->vertices);
223 }//vertices
224 
225 }//namespace orgQhull
226 
227 #//!\name operator<<
228 
229 using std::ostream;
230 
231 using orgQhull::QhullFacet;
232 using orgQhull::QhullFacetSet;
233 using orgQhull::QhullPoint;
234 using orgQhull::QhullPointSet;
235 using orgQhull::QhullRidge;
236 using orgQhull::QhullRidgeSet;
237 using orgQhull::QhullSetBase;
238 using orgQhull::QhullVertexSet;
239 
240 ostream &
operator <<(ostream & os,const QhullFacet::PrintFacet & pr)241 operator<<(ostream &os, const QhullFacet::PrintFacet &pr)
242 {
243     os << pr.message;
244     QhullFacet f= *pr.facet;
245     if(f.getFacetT()==0){ // Special values from set iterator
246         os << " NULLfacet" << endl;
247         return os;
248     }
249     if(f.getFacetT()==qh_MERGEridge){
250         os << " MERGEridge" << endl;
251         return os;
252     }
253     if(f.getFacetT()==qh_DUPLICATEridge){
254         os << " DUPLICATEridge" << endl;
255         return os;
256     }
257     os << f.printHeader();
258     if(!f.ridges().isEmpty()){
259         os << f.printRidges();
260     }
261     return os;
262 }//operator<< PrintFacet
263 
264 //! Print Voronoi center or facet centrum to stream.  Same as qh_printcenter [_r.]
265 //! Code duplicated for PrintCenter and getCenter
266 //! Sets center if needed
267 ostream &
operator <<(ostream & os,const QhullFacet::PrintCenter & pr)268 operator<<(ostream &os, const QhullFacet::PrintCenter &pr)
269 {
270     facetT *f= pr.facet->getFacetT();
271     if(pr.facet->qh()->CENTERtype!=qh_ASvoronoi && pr.facet->qh()->CENTERtype!=qh_AScentrum){
272         return os;
273     }
274     if(pr.message){
275         os << pr.message;
276     }
277     int numCoords;
278     if(pr.facet->qh()->CENTERtype==qh_ASvoronoi){
279         numCoords= pr.facet->qh()->hull_dim-1;
280         if(!f->normal || !f->upperdelaunay || !pr.facet->qh()->ATinfinity){
281             if(!f->center){
282                 f->center= qh_facetcenter(pr.facet->qh(), f->vertices);
283             }
284             for(int k=0; k<numCoords; k++){
285                 os << f->center[k] << " "; // QH11010 FIX: qh_REAL_1
286             }
287         }else{
288             for(int k=0; k<numCoords; k++){
289                 os << qh_INFINITE << " "; // QH11010 FIX: qh_REAL_1
290             }
291         }
292     }else{ // qh CENTERtype==qh_AScentrum
293         numCoords= pr.facet->qh()->hull_dim;
294         if(pr.print_format==qh_PRINTtriangles && pr.facet->qh()->DELAUNAY){
295             numCoords--;
296         }
297         if(!f->center){
298             f->center= qh_getcentrum(pr.facet->qh(), f);
299         }
300         for(int k=0; k<numCoords; k++){
301             os << f->center[k] << " "; // QH11010 FIX: qh_REAL_1
302         }
303     }
304     if(pr.print_format==qh_PRINTgeom && numCoords==2){
305         os << " 0";
306     }
307     os << endl;
308     return os;
309 }//operator<< PrintCenter
310 
311 //! Print flags for facet to stream.  Space prefix.  From qh_printfacetheader [io_r.c]
312 ostream &
operator <<(ostream & os,const QhullFacet::PrintFlags & p)313 operator<<(ostream &os, const QhullFacet::PrintFlags &p)
314 {
315     const facetT *f= p.facet->getFacetT();
316     if(p.message){
317         os << p.message;
318     }
319 
320     os << (p.facet->isTopOrient() ? " top" : " bottom");
321     if(p.facet->isSimplicial()){
322         os << " simplicial";
323     }
324     if(p.facet->isTriCoplanar()){
325         os << " tricoplanar";
326     }
327     if(p.facet->isUpperDelaunay()){
328         os << " upperDelaunay";
329     }
330     if(f->visible){
331         os << " visible";
332     }
333     if(f->newfacet){
334         os << " new";
335     }
336     if(f->tested){
337         os << " tested";
338     }
339     if(!f->good){
340         os << " notG";
341     }
342     if(f->seen && p.facet->qh()->IStracing){
343         os << " seen";
344     }
345     if(f->seen2 && p.facet->qh()->IStracing){
346       os << " seen";
347     }
348     if(f->isarea){
349       os << " isarea";
350     }
351     if(f->coplanarhorizon){
352         os << " coplanarhorizon";
353     }
354     if(f->mergehorizon){
355         os << " mergehorizon";
356     }
357     if(f->cycledone){
358       os << " cycledone";
359     }
360     if(f->keepcentrum){
361         os << " keepcentrum";
362     }
363     if(f->dupridge){
364         os << " dupridge";
365     }
366     if(f->mergeridge && !f->mergeridge2){
367         os << " mergeridge1";
368     }
369     if(f->mergeridge2){
370         os << " mergeridge2";
371     }
372     if(f->newmerge){
373         os << " newmerge";
374     }
375     if(f->flipped){
376         os << " flipped";
377     }
378     if(f->notfurthest){
379         os << " notfurthest";
380     }
381     if(f->degenerate){
382         os << " degenerate";
383     }
384     if(f->redundant){
385         os << " redundant";
386     }
387     os << endl;
388     return os;
389 }//operator<< PrintFlags
390 
391 //! Print header for facet to stream. Space prefix.  From qh_printfacetheader [io_r.c]
392 ostream &
operator <<(ostream & os,const QhullFacet::PrintHeader & pr)393 operator<<(ostream &os, const QhullFacet::PrintHeader &pr)
394 {
395     QhullFacet facet= *pr.facet;
396     facetT *f= facet.getFacetT();
397     os << "- f" << facet.id() << endl;
398     os << facet.printFlags("    - flags:");
399     if(f->isarea){
400         os << "    - area: " << f->f.area << endl; //QH11010 FIX: 2.2g
401     }else if(pr.facet->qh()->NEWfacets && f->visible && f->f.replace){
402         os << "    - replacement: f" << f->f.replace->id << endl;
403     }else if(f->newfacet){
404         if(f->f.samecycle && f->f.samecycle != f){
405             os << "    - shares same visible/horizon as f" << f->f.samecycle->id << endl;
406         }
407     }else if(f->tricoplanar /* !isarea */){
408         if(f->f.triowner){
409             os << "    - owner of normal & centrum is facet f" << f->f.triowner->id << endl;
410         }
411     }else if(f->f.newcycle){
412         os << "    - was horizon to f" << f->f.newcycle->id << endl;
413     }
414     if(f->nummerge){
415         os << "    - merges: " << f->nummerge << endl;
416     }
417     os << facet.hyperplane().print("    - normal: ", "\n    - offset: "); // QH11010 FIX: %10.7g
418     if(pr.facet->qh()->CENTERtype==qh_ASvoronoi || f->center){
419         os << facet.printCenter(qh_PRINTfacets, "    - center: ");
420     }
421 #if qh_MAXoutside
422     if(f->maxoutside > pr.facet->qh()->DISTround){
423         os << "    - maxoutside: " << f->maxoutside << endl; //QH11010 FIX: %10.7g
424     }
425 #endif
426     QhullPointSet ps= facet.outsidePoints();
427     if(!ps.isEmpty()){
428         QhullPoint furthest= ps.last();
429         if(ps.size() < 6){
430             os << "    - outside set(furthest p" << furthest.id() << "):" << endl;
431             for(QhullPointSet::iterator i=ps.begin(); i!=ps.end(); ++i){
432                 QhullPoint p= *i;
433                 os << p.print("     ");
434             }
435         }else if(ps.size()<21){
436             os << ps.print("    - outside set:");
437         }else{
438             os << "    - outside set:  " << ps.size() << " points.";
439             os << furthest.print("  Furthest");
440         }
441 #if !qh_COMPUTEfurthest
442         os << "    - furthest distance= " << f->furthestdist << endl; //QH11010 FIX: %2.2g
443 #endif
444     }
445     QhullPointSet cs= facet.coplanarPoints();
446     if(!cs.isEmpty()){
447         QhullPoint furthest= cs.last();
448         if(cs.size() < 6){
449             os << "    - coplanar set(furthest p" << furthest.id() << "):" << endl;
450             for(QhullPointSet::iterator i=cs.begin(); i!=cs.end(); ++i){
451                 QhullPoint p= *i;
452                 os << p.print("     ");
453             }
454         }else if(cs.size()<21){
455             os << cs.print("    - coplanar set:");
456         }else{
457             os << "    - coplanar set:  " << cs.size() << " points.";
458             os << furthest.print("  Furthest");
459         }
460         // QH11027 FIX: Can/should zinc_(Zdistio) be called from C++ interface
461         double d= facet.distance(furthest);
462         os << "      furthest distance= " << d << endl; //QH11010 FIX: %2.2g
463     }
464     QhullVertexSet vs= facet.vertices();
465     if(!vs.isEmpty()){
466         os << vs.print("    - vertices:");
467     }
468     QhullFacetSet fs= facet.neighborFacets();
469     fs.selectAll();
470     if(!fs.isEmpty()){
471         os << fs.printIdentifiers("    - neighboring facets:");
472     }
473     return os;
474 }//operator<< PrintHeader
475 
476 
477 //! Print ridges of facet to stream.  Same as qh_printfacetridges [io_r.c]
478 ostream &
operator <<(ostream & os,const QhullFacet::PrintRidges & pr)479 operator<<(ostream &os, const QhullFacet::PrintRidges &pr)
480 {
481     const QhullFacet facet= *pr.facet;
482     facetT *f= facet.getFacetT();
483     QhullRidgeSet rs= facet.ridges();
484     if(!rs.isEmpty()){
485         if(f->visible && pr.facet->qh()->NEWfacets){
486             os << "    - ridges(ids may be garbage):";
487             for(QhullRidgeSet::iterator i=rs.begin(); i!=rs.end(); ++i){
488                 QhullRidge r= *i;
489                 os << " r" << r.id();
490             }
491             os << endl;
492         }else{
493             os << "    - ridges:" << endl;
494         }
495 
496         // Keep track of printed ridges
497         for(QhullRidgeSet::iterator i=rs.begin(); i!=rs.end(); ++i){
498             QhullRidge r= *i;
499             r.getRidgeT()->seen= false;
500         }
501         int ridgeCount= 0;
502         if(facet.dimension()==3){
503             for(QhullRidge r= rs.first(); !r.getRidgeT()->seen; r= r.nextRidge3d(facet)){
504                 r.getRidgeT()->seen= true;
505                 os << r.print("");
506                 ++ridgeCount;
507                 if(!r.hasNextRidge3d(facet)){
508                     break;
509                 }
510             }
511         }else{
512             QhullFacetSet ns(facet.neighborFacets());
513             for(QhullFacetSet::iterator i=ns.begin(); i!=ns.end(); ++i){
514                 QhullFacet neighbor= *i;
515                 QhullRidgeSet nrs(neighbor.ridges());
516                 for(QhullRidgeSet::iterator j=nrs.begin(); j!=nrs.end(); ++j){
517                     QhullRidge r= *j;
518                     if(r.otherFacet(neighbor)==facet){
519                         r.getRidgeT()->seen= true;
520                         os << r.print("");
521                         ridgeCount++;
522                     }
523                 }
524             }
525         }
526         if(ridgeCount!=rs.count()){
527             os << "     - all ridges:";
528             for(QhullRidgeSet::iterator i=rs.begin(); i!=rs.end(); ++i){
529                 QhullRidge r= *i;
530                 os << " r" << r.id();
531             }
532             os << endl;
533         }
534         for(QhullRidgeSet::iterator i=rs.begin(); i!=rs.end(); ++i){
535             QhullRidge r= *i;
536             if(!r.getRidgeT()->seen){
537                 os << r.print("");
538             }
539         }
540     }
541     return os;
542 }//operator<< PrintRidges
543 
544 // "No conversion" error if defined inline
545 ostream &
operator <<(ostream & os,QhullFacet & f)546 operator<<(ostream &os, QhullFacet &f)
547 {
548     os << f.print("");
549     return os;
550 }//<< QhullFacet
551