1 /****************************************************************************
2 **
3 ** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
4 ** $Id: //main/2015/qhull/src/qhulltest/Qhull_test.cpp#4 $$Change: 2062 $
5 ** $DateTime: 2016/01/17 13:13:18 $$Author: bbarber $
6 **
7 ****************************************************************************/
8
9 //pre-compiled headers
10 #include <iostream>
11 #include "qhulltest/RoadTest.h" // QT_VERSION
12
13 #include "libqhullcpp/Qhull.h"
14 #include "libqhullcpp/QhullError.h"
15 #include "libqhullcpp/RboxPoints.h"
16 #include "libqhullcpp/QhullFacetList.h"
17
18 using std::cout;
19 using std::endl;
20 using std::string;
21
22 namespace orgQhull {
23
24 //! Test C++ interface to Qhull
25 //! See eg/q_test for tests of Qhull commands
26 class Qhull_test : public RoadTest
27 {
28 Q_OBJECT
29
30 #//!\name Test slots
31 private slots:
32 void cleanup();
33 void t_construct();
34 void t_attribute();
35 void t_message();
36 void t_getSet();
37 void t_getQh();
38 void t_getValue();
39 void t_foreach();
40 void t_modify();
41 };//Qhull_test
42
43 void
add_Qhull_test()44 add_Qhull_test()
45 {
46 new Qhull_test(); // RoadTest::s_testcases
47 }
48
49 //Executed after each testcase
50 void Qhull_test::
cleanup()51 cleanup()
52 {
53 RoadTest::cleanup();
54 }
55
56 void Qhull_test::
t_construct()57 t_construct()
58 {
59 {
60 Qhull q;
61 QCOMPARE(q.dimension(),0);
62 QVERIFY(q.qh()!=0);
63 QCOMPARE(QString(q.qhullCommand()),QString(""));
64 QCOMPARE(QString(q.rboxCommand()),QString(""));
65 try{
66 QCOMPARE(q.area(),0.0);
67 QFAIL("area() did not fail.");
68 }catch (const std::exception &e) {
69 cout << "INFO : Caught " << e.what();
70 }
71 }
72 {
73 RboxPoints rbox("10000");
74 Qhull q(rbox, "QR0"); // Random points in a randomly rotated cube.
75 QCOMPARE(q.dimension(),3);
76 QVERIFY(q.volume() < 1.0);
77 QVERIFY(q.volume() > 0.99);
78 }
79 {
80 double points[] = {
81 0, 0,
82 1, 0,
83 1, 1
84 };
85 Qhull q("triangle", 2, 3, points, "");
86 QCOMPARE(q.dimension(),2);
87 QCOMPARE(q.facetCount(),3);
88 QCOMPARE(q.vertexCount(),3);
89 QCOMPARE(q.dimension(),2);
90 QCOMPARE(q.area(), 2.0+sqrt(2.0)); // length of boundary
91 QCOMPARE(q.volume(), 0.5); // the 2-d area
92 }
93 }//t_construct
94
95 void Qhull_test::
t_attribute()96 t_attribute()
97 {
98 RboxPoints rcube("c");
99 {
100 double normals[] = {
101 0, -1, -0.5,
102 -1, 0, -0.5,
103 1, 0, -0.5,
104 0, 1, -0.5
105 };
106 Qhull q;
107 Coordinates feasible;
108 feasible << 0.0 << 0.0;
109 q.setFeasiblePoint(feasible);
110 Coordinates c(std::vector<double>(2, 0.0));
111 QVERIFY(q.feasiblePoint()==c);
112 q.setOutputStream(&cout);
113 q.runQhull("normals of square", 3, 4, normals, "H"); // halfspace intersect
114 QVERIFY(q.feasiblePoint()==c); // from qh.feasible_point after runQhull()
115 QCOMPARE(q.facetList().count(), 4); // Vertices of square
116 cout << "Expecting summary of halfspace intersection\n";
117 q.outputQhull();
118 q.qh()->disableOutputStream(); // Same as q.disableOutputStream()
119 cout << "Expecting no output from qh_fprintf() in Qhull.cpp\n";
120 q.outputQhull();
121 }
122 }//t_attribute
123
124 //! No QhullMessage for errors outside of qhull
125 void Qhull_test::
t_message()126 t_message()
127 {
128 RboxPoints rcube("c");
129 {
130 Qhull q;
131 QCOMPARE(q.qhullMessage(), string(""));
132 QCOMPARE(q.qhullStatus(), qh_ERRnone);
133 QVERIFY(!q.hasQhullMessage());
134 try{
135 q.runQhull(rcube, "Fd");
136 QFAIL("runQhull Fd did not fail.");
137 }catch (const std::exception &e) {
138 const char *s= e.what();
139 cout << "INFO : Caught " << s;
140 QCOMPARE(QString::fromStdString(s).left(6), QString("QH6029"));
141 // FIXUP QH11025 -- review decision to clearQhullMessage at QhullError() // Cleared when copied to QhullError
142 QVERIFY(!q.hasQhullMessage());
143 // QCOMPARE(q.qhullMessage(), QString::fromStdString(s).remove(0, 7));
144 // QCOMPARE(q.qhullStatus(), 6029);
145 q.clearQhullMessage();
146 QVERIFY(!q.hasQhullMessage());
147 }
148 q.appendQhullMessage("Append 1");
149 QVERIFY(q.hasQhullMessage());
150 QCOMPARE(QString::fromStdString(q.qhullMessage()), QString("Append 1"));
151 q.appendQhullMessage("\nAppend 2\n");
152 QCOMPARE(QString::fromStdString(q.qhullMessage()), QString("Append 1\nAppend 2\n"));
153 q.clearQhullMessage();
154 QVERIFY(!q.hasQhullMessage());
155 QCOMPARE(QString::fromStdString(q.qhullMessage()), QString(""));
156 }
157 {
158 cout << "INFO : Error stream without output stream\n";
159 Qhull q;
160 q.setErrorStream(&cout);
161 q.setOutputStream(0);
162 try{
163 q.runQhull(rcube, "Fd");
164 QFAIL("runQhull Fd did not fail.");
165 }catch (const QhullError &e) {
166 cout << "INFO : Caught " << e;
167 QCOMPARE(e.errorCode(), 6029);
168 }
169 //FIXUP QH11025 Qhullmessage cleared when QhullError thrown. Switched to e
170 //QVERIFY(q.hasQhullMessage());
171 //QCOMPARE(QString::fromStdString(q.qhullMessage()).left(6), QString("QH6029"));
172 q.clearQhullMessage();
173 QVERIFY(!q.hasQhullMessage());
174 }
175 {
176 cout << "INFO : Error output sent to output stream without error stream\n";
177 Qhull q;
178 q.setErrorStream(0);
179 q.setOutputStream(&cout);
180 try{
181 q.runQhull(rcube, "Tz H0");
182 QFAIL("runQhull TZ did not fail.");
183 }catch (const std::exception &e) {
184 const char *s= e.what();
185 cout << "INFO : Caught " << s;
186 QCOMPARE(QString::fromLatin1(s).left(6), QString("QH6023"));
187 }
188 //FIXUP QH11025 Qhullmessage cleared when QhullError thrown. Switched to e
189 //QVERIFY(q.hasQhullMessage());
190 //QCOMPARE(QString::fromStdString(q.qhullMessage()).left(17), QString("qhull: no message"));
191 //QCOMPARE(q.qhullStatus(), 6023);
192 q.clearQhullMessage();
193 QVERIFY(!q.hasQhullMessage());
194 }
195 {
196 cout << "INFO : No error stream or output stream\n";
197 Qhull q;
198 q.setErrorStream(0);
199 q.setOutputStream(0);
200 try{
201 q.runQhull(rcube, "Fd");
202 QFAIL("outputQhull did not fail.");
203 }catch (const std::exception &e) {
204 const char *s= e.what();
205 cout << "INFO : Caught " << s;
206 QCOMPARE(QString::fromLatin1(s).left(6), QString("QH6029"));
207 }
208 //FIXUP QH11025 Qhullmessage cleared when QhullError thrown. Switched to e
209 //QVERIFY(q.hasQhullMessage());
210 //QCOMPARE(QString::fromStdString(q.qhullMessage()).left(9), QString("qhull err"));
211 //QCOMPARE(q.qhullStatus(), 6029);
212 q.clearQhullMessage();
213 QVERIFY(!q.hasQhullMessage());
214 }
215 }//t_message
216
217 void Qhull_test::
t_getSet()218 t_getSet()
219 {
220 RboxPoints rcube("c");
221 {
222 Qhull q;
223 QVERIFY(!q.initialized());
224 q.runQhull(rcube, "s");
225 QVERIFY(q.initialized());
226 QCOMPARE(q.dimension(), 3);
227 QhullPoint p= q.origin();
228 QCOMPARE(p.dimension(), 3);
229 QCOMPARE(p[0]+p[1]+p[2], 0.0);
230 q.setErrorStream(&cout);
231 q.outputQhull();
232 }
233 {
234 Qhull q;
235 q.runQhull(rcube, "");
236 q.setOutputStream(&cout);
237 q.outputQhull();
238 }
239 }//t_getSet
240
241 void Qhull_test::
t_getQh()242 t_getQh()
243 {
244 RboxPoints rcube("c");
245 {
246 Qhull q;
247 q.runQhull(rcube, "s");
248 QCOMPARE(QString(q.qhullCommand()), QString("qhull s"));
249 QCOMPARE(QString(q.rboxCommand()), QString("rbox \"c\""));
250 QCOMPARE(q.facetCount(), 6);
251 QCOMPARE(q.vertexCount(), 8);
252 // Sample fields from Qhull's qhT [libqhull.h]
253 QCOMPARE(q.qh()->ALLpoints, 0u);
254 QCOMPARE(q.qh()->GOODpoint, 0);
255 QCOMPARE(q.qh()->IStracing, 0);
256 QCOMPARE(q.qh()->MAXcoplanar+1.0, 1.0); // fuzzy compare
257 QCOMPARE(q.qh()->MERGING, 1u);
258 QCOMPARE(q.qh()->input_dim, 3);
259 QCOMPARE(QString(q.qh()->qhull_options).left(8), QString(" run-id"));
260 QCOMPARE(q.qh()->num_facets, 6);
261 QCOMPARE(q.qh()->hasTriangulation, 0u);
262 QCOMPARE(q.qh()->max_outside - q.qh()->min_vertex + 1.0, 1.0); // fuzzy compare
263 QCOMPARE(*q.qh()->gm_matrix+1.0, 1.0); // fuzzy compare
264 }
265 }//t_getQh
266
267 void Qhull_test::
t_getValue()268 t_getValue()
269 {
270 RboxPoints rcube("c");
271 {
272 Qhull q;
273 q.runQhull(rcube, "");
274 QCOMPARE(q.area(), 6.0);
275 QCOMPARE(q.volume(), 1.0);
276 }
277 }//t_getValue
278
279 void Qhull_test::
t_foreach()280 t_foreach()
281 {
282 RboxPoints rcube("c");
283 {
284 Qhull q;
285 QCOMPARE(q.beginFacet(),q.endFacet());
286 QCOMPARE(q.beginVertex(),q.endVertex());
287 q.runQhull(rcube, "");
288 QCOMPARE(q.facetList().count(), 6);
289
290 // defineVertexNeighborFacets() tested in QhullVertex_test::t_io()
291
292 QhullFacetList facets(q.beginFacet(), q.endFacet());
293 QCOMPARE(facets.count(), 6);
294 QCOMPARE(q.firstFacet(), q.beginFacet());
295 QhullVertexList vertices(q.beginVertex(), q.endVertex());
296 QCOMPARE(vertices.count(), 8);
297 QCOMPARE(q.firstVertex(), q.beginVertex());
298 QhullPoints ps= q.points();
299 QCOMPARE(ps.count(), 8);
300 QhullPointSet ps2= q.otherPoints();
301 QCOMPARE(ps2.count(), 0);
302 // ps2= q.otherPoints(); //disabled, would not copy the points
303 QCOMPARE(q.facetCount(), 6);
304 QCOMPARE(q.vertexCount(), 8);
305 coordT *c= q.pointCoordinateBegin(); // of q.points()
306 QVERIFY(*c==0.5 || *c==-0.5);
307 coordT *c3= q.pointCoordinateEnd();
308 QVERIFY(c3[-1]==0.5 || c3[-1]==-0.5);
309 QCOMPARE(c3-c, 8*3);
310 QCOMPARE(q.vertexList().count(), 8);
311 }
312 }//t_foreach
313
314 void Qhull_test::
t_modify()315 t_modify()
316 {
317 //addPoint() tested in t_foreach
318 RboxPoints diamond("d");
319 Qhull q(diamond, "o");
320 q.setOutputStream(&cout);
321 cout << "Expecting vertexList and facetList of a 3-d diamond.\n";
322 q.outputQhull();
323 cout << "Expecting normals of a 3-d diamond.\n";
324 q.outputQhull("n");
325 // runQhull tested in t_attribute(), t_message(), etc.
326 }//t_modify
327
328 }//orgQhull
329
330 // Redefine Qhull's usermem_r.c in order to report erroneous calls to qh_exit
qh_exit(int exitcode)331 void qh_exit(int exitcode) {
332 cout << "FAIL! : Qhull called qh_exit(). Qhull's error handling not available.\n.. See the corresponding Qhull:qhull_message or setErrorStream().\n";
333 exit(exitcode);
334 }
qh_fprintf_stderr(int msgcode,const char * fmt,...)335 void qh_fprintf_stderr(int msgcode, const char *fmt, ... ) {
336 va_list args;
337
338 va_start(args, fmt);
339 if(msgcode)
340 fprintf(stderr, "QH%.4d ", msgcode);
341 vfprintf(stderr, fmt, args);
342 va_end(args);
343 } /* fprintf_stderr */
qh_free(void * mem)344 void qh_free(void *mem) {
345 free(mem);
346 }
qh_malloc(size_t size)347 void *qh_malloc(size_t size) {
348 return malloc(size);
349 }
350
351 #if 0
352 template<> char * QTest::
353 toString(const std::string &s)
354 {
355 QByteArray ba = s.c_str();
356 return qstrdup(ba.data());
357 }
358 #endif
359
360 #include "moc/Qhull_test.moc"
361