/**************************************************************************** ** ** Copyright (c) 2008-2015 C.B. Barber. All rights reserved. ** $Id: //main/2015/qhull/src/qhulltest/QhullFacet_test.cpp#4 $$Change: 2062 $ ** $DateTime: 2016/01/17 13:13:18 $$Author: bbarber $ ** ****************************************************************************/ //pre-compiled headers #include #include "qhulltest/RoadTest.h" // QT_VERSION #include "libqhullcpp/QhullFacet.h" #include "libqhullcpp/QhullError.h" #include "libqhullcpp/Coordinates.h" #include "libqhullcpp/RboxPoints.h" #include "libqhullcpp/QhullFacetList.h" #include "libqhullcpp/QhullFacetSet.h" #include "libqhullcpp/QhullPointSet.h" #include "libqhullcpp/QhullRidge.h" #include "libqhullcpp/Qhull.h" using std::cout; using std::endl; using std::ostringstream; using std::ostream; using std::string; namespace orgQhull { class QhullFacet_test : public RoadTest { Q_OBJECT #//!\name Test slots private slots: void cleanup(); void t_construct_qh(); void t_constructConvert(); void t_getSet(); void t_value(); void t_foreach(); void t_io(); };//QhullFacet_test void add_QhullFacet_test() { new QhullFacet_test(); // RoadTest::s_testcases } //Executed after each testcase void QhullFacet_test:: cleanup() { RoadTest::cleanup(); } void QhullFacet_test:: t_construct_qh() { // Qhull.runQhull() constructs QhullFacets as facetT QhullQh qh; QhullFacet f(&qh); QVERIFY(!f.isValid()); QCOMPARE(f.dimension(),0); }//t_construct_qh void QhullFacet_test:: t_constructConvert() { // Qhull.runQhull() constructs QhullFacets as facetT Qhull q2; QhullFacet f(q2); QVERIFY(!f.isValid()); QCOMPARE(f.dimension(),0); RboxPoints rcube("c"); Qhull q(rcube,"Qt QR0"); // triangulation of rotated unit cube QhullFacet f2(q.beginFacet()); QCOMPARE(f2.dimension(),3); f= f2; // copy assignment QVERIFY(f.isValid()); QCOMPARE(f.dimension(),3); QhullFacet f5= f2; QVERIFY(f5==f2); QVERIFY(f5==f); QhullFacet f3(q, f2.getFacetT()); QCOMPARE(f,f3); QhullFacet f4(q, f2.getBaseT()); QCOMPARE(f,f4); }//t_constructConvert void QhullFacet_test:: t_getSet() { RboxPoints rcube("c"); { Qhull q(rcube,"Qt QR0"); // triangulation of rotated unit cube cout << " rbox c | qhull Qt QR0 QR" << q.rotateRandom() << " distanceEpsilon " << q.distanceEpsilon() << endl; QCOMPARE(q.facetCount(), 12); QCOMPARE(q.vertexCount(), 8); QhullFacetListIterator i(q.facetList()); while(i.hasNext()){ const QhullFacet f= i.next(); cout << f.id() << endl; QCOMPARE(f.dimension(),3); QVERIFY(f.id()>0 && f.id()<=39); QVERIFY(f.isValid()); if(i.hasNext()){ QCOMPARE(f.next(), i.peekNext()); QVERIFY(f.next()!=f); } QVERIFY(i.hasPrevious()); QCOMPARE(f, i.peekPrevious()); } // test tricoplanarOwner QhullFacet facet = q.beginFacet(); QhullFacet tricoplanarOwner = facet.tricoplanarOwner(); int tricoplanarCount= 0; i.toFront(); while(i.hasNext()){ const QhullFacet f= i.next(); if(f.tricoplanarOwner()==tricoplanarOwner){ tricoplanarCount++; } } QCOMPARE(tricoplanarCount, 2); int tricoplanarCount2= 0; foreach (QhullFacet f, q.facetList()){ // Qt only QhullHyperplane h= f.hyperplane(); cout << "Hyperplane: " << h; QCOMPARE(h.count(), 3); QCOMPARE(h.offset(), -0.5); double n= h.norm(); QCOMPARE(n, 1.0); QhullHyperplane hi= f.innerplane(); QCOMPARE(hi.count(), 3); double innerOffset= hi.offset()+0.5; cout << "InnerPlane: " << hi << " innerOffset+0.5 " << innerOffset << endl; QVERIFY(innerOffset >= 0.0-(2*q.distanceEpsilon())); // A guessed epsilon. It needs to account for roundoff due to rotation of the vertices QhullHyperplane ho= f.outerplane(); QCOMPARE(ho.count(), 3); double outerOffset= ho.offset()+0.5; cout << "OuterPlane: " << ho << " outerOffset+0.5 " << outerOffset << endl; QVERIFY(outerOffset <= 0.0+(2*q.distanceEpsilon())); // A guessed epsilon. It needs to account for roundoff due to rotation of the vertices QVERIFY(outerOffset-innerOffset < 1e-7); for(int k= 0; k<3; k++){ QVERIFY(ho[k]==hi[k]); QVERIFY(ho[k]==h[k]); } QhullPoint center= f.getCenter(); cout << "Center: " << center; double d= f.distance(center); QVERIFY(d < innerOffset-outerOffset); QhullPoint center2= f.getCenter(qh_PRINTcentrums); QCOMPARE(center, center2); if(f.tricoplanarOwner()==tricoplanarOwner){ tricoplanarCount2++; } cout << endl; } QCOMPARE(tricoplanarCount2, 2); Qhull q2(rcube,"d Qz Qt QR0"); // 3-d triangulation of Delaunay triangulation (the cube) cout << " rbox c | qhull d Qz Qt QR0 QR" << q2.rotateRandom() << " distanceEpsilon " << q2.distanceEpsilon() << endl; QhullFacet f2= q2.firstFacet(); QhullPoint center3= f2.getCenter(qh_PRINTtriangles); QCOMPARE(center3.dimension(), 3); QhullPoint center4= f2.getCenter(); QCOMPARE(center4.dimension(), 4); for(int k= 0; k<3; k++){ QVERIFY(center4[k]==center3[k]); } Qhull q3(rcube,"v Qz QR0"); // Voronoi diagram of a cube (one vertex) cout << " rbox c | qhull v Qz QR0 QR" << q3.rotateRandom() << " distanceEpsilon " << q3.distanceEpsilon() << endl; q3.setFactorEpsilon(400); // Voronoi vertices are not necessarily within distance episilon QhullPoint origin= q3.inputOrigin(); int voronoiCount= 0; foreach(QhullFacet f, q3.facetList()){ //Qt only if(f.isGood()){ ++voronoiCount; QhullPoint p= f.voronoiVertex(); cout << p.print("Voronoi vertex: ") << " Is it within " << q3.factorEpsilon() << " * distanceEpsilon (" << q3.distanceEpsilon() << ") of the origin?" << endl; QCOMPARE(p, origin); } } QCOMPARE(voronoiCount, 1); } }//t_getSet void QhullFacet_test:: t_value() { RboxPoints rcube("c"); { Qhull q(rcube, ""); coordT c[]= {0.0, 0.0, 0.0}; foreach (QhullFacet f, q.facetList()){ // Qt only double d= f.distance(q.origin()); QCOMPARE(d, -0.5); double d0= f.distance(c); QCOMPARE(d0, -0.5); double facetArea= f.facetArea(); QCOMPARE(facetArea, 1.0); #if qh_MAXoutside double maxoutside= f.getFacetT()->maxoutside; QVERIFY(maxoutside<1e-7); #endif } } }//t_value void QhullFacet_test:: t_foreach() { RboxPoints rcube("c W0 300"); // cube plus 300 points on its surface { Qhull q(rcube, "QR0 Qc"); // keep coplanars, thick facet, and rotate the cube int coplanarCount= 0; foreach(const QhullFacet f, q.facetList()){ QhullPointSet coplanars= f.coplanarPoints(); coplanarCount += coplanars.count(); QhullFacetSet neighbors= f.neighborFacets(); QCOMPARE(neighbors.count(), 4); QhullPointSet outsides= f.outsidePoints(); QCOMPARE(outsides.count(), 0); QhullRidgeSet ridges= f.ridges(); QCOMPARE(ridges.count(), 4); QhullVertexSet vertices= f.vertices(); QCOMPARE(vertices.count(), 4); int ridgeCount= 0; QhullRidge r= ridges.first(); for(int r0= r.id(); ridgeCount==0 || r.id()!=r0; r= r.nextRidge3d(f)){ ++ridgeCount; if(!r.hasNextRidge3d(f)){ QFAIL("Unexpected simplicial facet. They only have ridges to non-simplicial neighbors."); } } QCOMPARE(ridgeCount, 4); } QCOMPARE(coplanarCount, 300); } }//t_foreach void QhullFacet_test:: t_io() { RboxPoints rcube("c"); { Qhull q(rcube, ""); QhullFacet f= q.beginFacet(); cout << f; ostringstream os; os << f.print("\nWith a message\n"); os << "\nPrint header for the same facet\n"; os << f.printHeader(); os << "\nPrint each component\n"; os << f.printFlags(" - flags:"); os << f.printCenter(qh_PRINTfacets, " - center: "); os << f.printRidges(); cout << os.str(); ostringstream os2; os2 << f; QString facetString2= QString::fromStdString(os2.str()); facetString2.replace(QRegExp("\\s\\s+"), " "); ostringstream os3; q.qh()->setOutputStream(&os3); q.outputQhull("f"); QString facetsString= QString::fromStdString(os3.str()); QString facetString3= facetsString.mid(facetsString.indexOf("- f1\n")); facetString3= facetString3.left(facetString3.indexOf("\n- f")+1); facetString3.replace(QRegExp("\\s\\s+"), " "); QCOMPARE(facetString2, facetString3); } }//t_io // toQhullFacet is static_cast only }//orgQhull #include "moc/QhullFacet_test.moc"