1 /* OpenSceneGraph example, osgunittests.
2 *
3 *  Permission is hereby granted, free of charge, to any person obtaining a copy
4 *  of this software and associated documentation files (the "Software"), to deal
5 *  in the Software without restriction, including without limitation the rights
6 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 *  copies of the Software, and to permit persons to whom the Software is
8 *  furnished to do so, subject to the following conditions:
9 *
10 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16 *  THE SOFTWARE.
17 */
18 
19 #include <osg/ArgumentParser>
20 #include <osg/ApplicationUsage>
21 
22 #include <osg/Vec3>
23 #include <osg/Matrix>
24 #include <osg/Polytope>
25 #include <osg/Timer>
26 #include <osg/io_utils>
27 
28 #include <OpenThreads/Thread>
29 
30 #include "UnitTestFramework.h"
31 #include "performance.h"
32 #include "MultiThreadRead.h"
33 
34 #include <iostream>
35 
36 extern void runFileNameUtilsTest(osg::ArgumentParser& arguments);
37 
testFrustum(double left,double right,double bottom,double top,double zNear,double zFar)38 void testFrustum(double left,double right,double bottom,double top,double zNear,double zFar)
39 {
40     osg::Matrix f;
41     f.makeFrustum(left,right,bottom,top,zNear,zFar);
42 
43     double c_left=0;
44     double c_right=0;
45     double c_top=0;
46     double c_bottom=0;
47     double c_zNear=0;
48     double c_zFar=0;
49 
50 
51     std::cout << "testFrustum"<<f.getFrustum(c_left,c_right,c_bottom,c_top,c_zNear,c_zFar)<<std::endl;
52     std::cout << "  left = "<<left<<" compute "<<c_left<<std::endl;
53     std::cout << "  right = "<<right<<" compute "<<c_right<<std::endl;
54 
55     std::cout << "  bottom = "<<bottom<<" compute "<<c_bottom<<std::endl;
56     std::cout << "  top = "<<top<<" compute "<<c_top<<std::endl;
57 
58     std::cout << "  zNear = "<<zNear<<" compute "<<c_zNear<<std::endl;
59     std::cout << "  zFar = "<<zFar<<" compute "<<c_zFar<<std::endl;
60 
61     std::cout << std::endl;
62 }
63 
testOrtho(double left,double right,double bottom,double top,double zNear,double zFar)64 void testOrtho(double left,double right,double bottom,double top,double zNear,double zFar)
65 {
66     osg::Matrix f;
67     f.makeOrtho(left,right,bottom,top,zNear,zFar);
68 
69     double c_left=0;
70     double c_right=0;
71     double c_top=0;
72     double c_bottom=0;
73     double c_zNear=0;
74     double c_zFar=0;
75 
76     std::cout << "testOrtho "<< f.getOrtho(c_left,c_right,c_bottom,c_top,c_zNear,c_zFar) << std::endl;
77     std::cout << "  left = "<<left<<" compute "<<c_left<<std::endl;
78     std::cout << "  right = "<<right<<" compute "<<c_right<<std::endl;
79 
80     std::cout << "  bottom = "<<bottom<<" compute "<<c_bottom<<std::endl;
81     std::cout << "  top = "<<top<<" compute "<<c_top<<std::endl;
82 
83     std::cout << "  zNear = "<<zNear<<" compute "<<c_zNear<<std::endl;
84     std::cout << "  zFar = "<<zFar<<" compute "<<c_zFar<<std::endl;
85 
86     std::cout << std::endl;
87 }
88 
testPerspective(double fovy,double aspect,double zNear,double zFar)89 void testPerspective(double fovy,double aspect,double zNear,double zFar)
90 {
91     osg::Matrix f;
92     f.makePerspective(fovy,aspect,zNear,zFar);
93 
94     double c_fovy=0;
95     double c_aspect=0;
96     double c_zNear=0;
97     double c_zFar=0;
98 
99     std::cout << "testPerspective "<< f.getPerspective(c_fovy,c_aspect,c_zNear,c_zFar) << std::endl;
100     std::cout << "  fovy = "<<fovy<<" compute "<<c_fovy<<std::endl;
101     std::cout << "  aspect = "<<aspect<<" compute "<<c_aspect<<std::endl;
102 
103     std::cout << "  zNear = "<<zNear<<" compute "<<c_zNear<<std::endl;
104     std::cout << "  zFar = "<<zFar<<" compute "<<c_zFar<<std::endl;
105 
106     std::cout << std::endl;
107 }
108 
testLookAt(const osg::Vec3 & eye,const osg::Vec3 & center,const osg::Vec3 & up)109 void testLookAt(const osg::Vec3& eye,const osg::Vec3& center,const osg::Vec3& up)
110 {
111     osg::Matrix mv;
112     mv.makeLookAt(eye,center,up);
113 
114     osg::Vec3 c_eye,c_center,c_up;
115     mv.getLookAt(c_eye,c_center,c_up);
116 
117     std::cout << "testLookAt"<<std::endl;
118     std::cout << "  eye "<<eye<< " compute "<<c_eye<<std::endl;
119     std::cout << "  center "<<center<< " compute "<<c_center<<std::endl;
120     std::cout << "  up "<<up<< " compute "<<c_up<<std::endl;
121 
122     std::cout << std::endl;
123 
124 }
125 
126 
testMatrixInvert(const osg::Matrix & matrix)127 void testMatrixInvert(const osg::Matrix& matrix)
128 {
129     //Invert it twice using the two inversion functions and view the results
130     osg::notify(osg::NOTICE)<<"testMatrixInvert("<<std::endl;
131     osg::notify(osg::NOTICE)<<matrix<<std::endl;
132     osg::notify(osg::NOTICE)<<")"<<std::endl;
133 
134     osg::Matrix invM1_0;
135     invM1_0.invert(matrix);
136     osg::notify(osg::NOTICE)<<"Matrix::invert"<<std::endl;
137     osg::notify(osg::NOTICE)<<invM1_0<<std::endl;
138     osg::Matrix default_result = matrix*invM1_0;
139     osg::notify(osg::NOTICE)<<"matrix * invert="<<std::endl;
140     osg::notify(osg::NOTICE)<<default_result<<std::endl;;
141 
142 }
143 
sizeOfTest()144 void sizeOfTest()
145 {
146   std::cout<<"sizeof(bool)=="<<sizeof(bool)<<std::endl;
147   std::cout<<"sizeof(char)=="<<sizeof(char)<<std::endl;
148   std::cout<<"sizeof(short)=="<<sizeof(short)<<std::endl;
149   std::cout<<"sizeof(short int)=="<<sizeof(short int)<<std::endl;
150   std::cout<<"sizeof(int)=="<<sizeof(int)<<std::endl;
151   std::cout<<"sizeof(long)=="<<sizeof(long)<<std::endl;
152   std::cout<<"sizeof(long int)=="<<sizeof(long int)<<std::endl;
153 
154 #if defined(_MSC_VER)
155   // long long isn't supported on VS6.0...
156   std::cout<<"sizeof(__int64)=="<<sizeof(__int64)<<std::endl;
157 #else
158   std::cout<<"sizeof(long long)=="<<sizeof(long long)<<std::endl;
159 #endif
160   std::cout<<"sizeof(float)=="<<sizeof(float)<<std::endl;
161   std::cout<<"sizeof(double)=="<<sizeof(double)<<std::endl;
162 
163   std::cout<<"sizeof(std::istream::pos_type)=="<<sizeof(std::istream::pos_type)<<std::endl;
164   std::cout<<"sizeof(std::istream::off_type)=="<<sizeof(std::istream::off_type)<<std::endl;
165   std::cout<<"sizeof(OpenThreads::Mutex)=="<<sizeof(OpenThreads::Mutex)<<std::endl;
166 
167   std::cout<<"sizeof(std::string)=="<<sizeof(std::string)<<std::endl;
168 
169 }
170 
171 /// Exercise the Matrix.getRotate function.
172 /// Compare the output of:
173 ///  q1 * q2
174 /// versus
175 ///  (mat(q1)*mat(q2)*scale).getRotate()
176 /// for a range of rotations
testGetQuatFromMatrix(const osg::Vec3d & scale)177 void testGetQuatFromMatrix(const osg::Vec3d& scale)
178 {
179 
180     // Options
181 
182     // acceptable error range
183     double eps=1e-6;
184 
185     // scale matrix
186     // To not test with scale, use 1,1,1
187     // Not sure if 0's or negative values are acceptable
188     osg::Matrixd scalemat;
189     scalemat.makeScale(scale);
190 
191     // range of rotations
192 #if 1
193     // wide range
194     double rol1start = 0.0;
195     double rol1stop = 360.0;
196     double rol1step = 20.0;
197 
198     double pit1start = 0.0;
199     double pit1stop = 90.0;
200     double pit1step = 20.0;
201 
202     double yaw1start = 0.0;
203     double yaw1stop = 360.0;
204     double yaw1step = 20.0;
205 
206     double rol2start = 0.0;
207     double rol2stop = 360.0;
208     double rol2step = 20.0;
209 
210     double pit2start = 0.0;
211     double pit2stop = 90.0;
212     double pit2step = 20.0;
213 
214     double yaw2start = 0.0;
215     double yaw2stop = 360.0;
216     double yaw2step = 20.0;
217 #else
218     // focussed range
219     double rol1start = 0.0;
220     double rol1stop = 0.0;
221     double rol1step = 0.1;
222 
223     double pit1start = 0.0;
224     double pit1stop = 5.0;
225     double pit1step = 5.0;
226 
227     double yaw1start = 89.0;
228     double yaw1stop = 91.0;
229     double yaw1step = 0.1;
230 
231     double rol2start = 0.0;
232     double rol2stop = 0.0;
233     double rol2step = 0.1;
234 
235     double pit2start = 0.0;
236     double pit2stop = 0.0;
237     double pit2step = 0.1;
238 
239     double yaw2start = 89.0;
240     double yaw2stop = 91.0;
241     double yaw2step = 0.1;
242 #endif
243 
244     std::cout << std::endl << "Starting testGetQuatFromMatrix, it can take a while ..." << std::endl;
245 
246     osg::Timer_t tstart, tstop;
247     tstart = osg::Timer::instance()->tick();
248     int count=0;
249     for (double rol1 = rol1start; rol1 <= rol1stop; rol1 += rol1step) {
250         for (double pit1 = pit1start; pit1 <= pit1stop; pit1 += pit1step) {
251             for (double yaw1 = yaw1start; yaw1 <= yaw1stop; yaw1 += yaw1step) {
252                 for (double rol2 = rol2start; rol2 <= rol2stop; rol2 += rol2step) {
253                     for (double pit2 = pit2start; pit2 <= pit2stop; pit2 += pit2step) {
254                         for (double yaw2 = yaw2start; yaw2 <= yaw2stop; yaw2 += yaw2step)
255                         {
256                             count++;
257                             // create two quats based on the roll, pitch and yaw values
258                             osg::Quat rot_quat1 =
259                             osg::Quat(osg::DegreesToRadians(rol1),osg::Vec3d(1,0,0),
260                                   osg::DegreesToRadians(pit1),osg::Vec3d(0,1,0),
261                                   osg::DegreesToRadians(yaw1),osg::Vec3d(0,0,1));
262 
263                             osg::Quat rot_quat2 =
264                             osg::Quat(osg::DegreesToRadians(rol2),osg::Vec3d(1,0,0),
265                                   osg::DegreesToRadians(pit2),osg::Vec3d(0,1,0),
266                                   osg::DegreesToRadians(yaw2),osg::Vec3d(0,0,1));
267 
268                             // create an output quat using quaternion math
269                             osg::Quat out_quat1;
270                             out_quat1 = rot_quat2 * rot_quat1;
271 
272                             // create two matrices based on the input quats
273                             osg::Matrixd mat1,mat2;
274                             mat1.makeRotate(rot_quat1);
275                             mat2.makeRotate(rot_quat2);
276 
277                             // create an output quat by matrix multiplication and getRotate
278                             osg::Matrixd out_mat;
279                             out_mat = mat2 * mat1;
280                             // add matrix scale for even more nastiness
281                             out_mat = out_mat * scalemat;
282                             osg::Quat out_quat2;
283                             out_quat2 = out_mat.getRotate();
284 
285                             // If the quaternion W is <0, then we should reflect
286                             // to get it into the positive W.
287                             // Unfortunately, when W is very small (close to 0), the sign
288                             // does not really make sense because of precision problems
289                             // and the reflection might not work.
290                             if(out_quat1.w()<0) out_quat1 = out_quat1 * -1.0;
291                             if(out_quat2.w()<0) out_quat2 = out_quat2 * -1.0;
292 
293                             // if the output quat length is not one
294                             // or if the components do not match,
295                             // something is amiss
296 
297                             bool componentsOK = false;
298                             if ( ((fabs(out_quat1.x()-out_quat2.x())) < eps) &&
299                                  ((fabs(out_quat1.y()-out_quat2.y())) < eps) &&
300                                  ((fabs(out_quat1.z()-out_quat2.z())) < eps) &&
301                                  ((fabs(out_quat1.w()-out_quat2.w())) < eps) )
302                                     {
303                                 componentsOK = true;
304                             }
305                             // We should also test for q = -q which is valid, so reflect
306                             // one quat.
307                             out_quat2 = out_quat2 * -1.0;
308                             if ( ((fabs(out_quat1.x()-out_quat2.x())) < eps) &&
309                                  ((fabs(out_quat1.y()-out_quat2.y())) < eps) &&
310                                  ((fabs(out_quat1.z()-out_quat2.z())) < eps) &&
311                                  ((fabs(out_quat1.w()-out_quat2.w())) < eps) )
312                             {
313                                 componentsOK = true;
314                             }
315 
316                             bool lengthOK = false;
317                             if (fabs(1.0-out_quat2.length()) < eps)
318                             {
319                                 lengthOK = true;
320                             }
321 
322                             if (!lengthOK || !componentsOK)
323                             {
324                                 std::cout << "testGetQuatFromMatrix problem at: \n"
325                                       << " r1=" << rol1
326                                       << " p1=" << pit1
327                                       << " y1=" << yaw1
328                                       << " r2=" << rol2
329                                       << " p2=" << pit2
330                                       << " y2=" << yaw2 << "\n";
331                                 std::cout << "quats:        " << out_quat1 << " length: " << out_quat1.length() << "\n";
332                                 std::cout << "mats and get: " << out_quat2 << " length: " << out_quat2.length() << "\n\n";
333                             }
334                         }
335                     }
336                 }
337             }
338         }
339     }
340     tstop = osg::Timer::instance()->tick();
341     double duration = osg::Timer::instance()->delta_s(tstart,tstop);
342     std::cout << "Time for testGetQuatFromMatrix with " << count << " iterations: " << duration << std::endl << std::endl;
343 }
344 
testQuatRotate(const osg::Vec3d & from,const osg::Vec3d & to)345 void testQuatRotate(const osg::Vec3d& from, const osg::Vec3d& to)
346 {
347     osg::Quat q_nicolas;
348     q_nicolas.makeRotate(from,to);
349 
350     osg::Quat q_original;
351     q_original.makeRotate_original(from,to);
352 
353     std::cout<<"osg::Quat::makeRotate("<<from<<", "<<to<<")"<<std::endl;
354     std::cout<<"  q_nicolas = "<<q_nicolas<<std::endl;
355     std::cout<<"  q_original = "<<q_original<<std::endl;
356     std::cout<<"  from * M4x4(q_nicolas) = "<<from * osg::Matrixd::rotate(q_nicolas)<<std::endl;
357     std::cout<<"  from * M4x4(q_original) = "<<from * osg::Matrixd::rotate(q_original)<<std::endl;
358 }
359 
testQuat(const osg::Vec3d & quat_scale)360 void testQuat(const osg::Vec3d& quat_scale)
361 {
362     osg::Quat q1;
363     q1.makeRotate(osg::DegreesToRadians(30.0),0.0f,0.0f,1.0f);
364 
365     osg::Quat q2;
366     q2.makeRotate(osg::DegreesToRadians(133.0),0.0f,1.0f,1.0f);
367 
368     osg::Quat q1_2 = q1*q2;
369     osg::Quat q2_1 = q2*q1;
370 
371     osg::Matrix m1 = osg::Matrix::rotate(q1);
372     osg::Matrix m2 = osg::Matrix::rotate(q2);
373 
374     osg::Matrix m1_2 = m1*m2;
375     osg::Matrix m2_1 = m2*m1;
376 
377     osg::Quat qm1_2;
378     qm1_2.set(m1_2);
379 
380     osg::Quat qm2_1;
381     qm2_1.set(m2_1);
382 
383     std::cout<<"q1*q2 = "<<q1_2<<std::endl;
384     std::cout<<"q2*q1 = "<<q2_1<<std::endl;
385     std::cout<<"m1*m2 = "<<qm1_2<<std::endl;
386     std::cout<<"m2*m1 = "<<qm2_1<<std::endl;
387 
388 
389     testQuatRotate(osg::Vec3d(1.0,0.0,0.0),osg::Vec3d(0.0,1.0,0.0));
390     testQuatRotate(osg::Vec3d(0.0,1.0,0.0),osg::Vec3d(1.0,0.0,0.0));
391     testQuatRotate(osg::Vec3d(0.0,0.0,1.0),osg::Vec3d(0.0,1.0,0.0));
392     testQuatRotate(osg::Vec3d(1.0,1.0,1.0),osg::Vec3d(1.0,0.0,0.0));
393     testQuatRotate(osg::Vec3d(1.0,0.0,0.0),osg::Vec3d(1.0,0.0,0.0));
394     testQuatRotate(osg::Vec3d(1.0,0.0,0.0),osg::Vec3d(-1.0,0.0,0.0));
395     testQuatRotate(osg::Vec3d(-1.0,0.0,0.0),osg::Vec3d(1.0,0.0,0.0));
396     testQuatRotate(osg::Vec3d(0.0,1.0,0.0),osg::Vec3d(0.0,-1.0,0.0));
397     testQuatRotate(osg::Vec3d(0.0,-1.0,0.0),osg::Vec3d(0.0,1.0,0.0));
398     testQuatRotate(osg::Vec3d(0.0,0.0,1.0),osg::Vec3d(0.0,0.0,-1.0));
399     testQuatRotate(osg::Vec3d(0.0,0.0,-1.0),osg::Vec3d(0.0,0.0,1.0));
400 
401     // Test a range of rotations
402     testGetQuatFromMatrix(quat_scale);
403 
404     // This is a specific test case for a matrix containing scale and rotation
405     osg::Matrix matrix(0.5, 0.0, 0.0, 0.0,
406                        0.0, 0.5, 0.0, 0.0,
407                        0.0, 0.0, 0.5, 0.0,
408                        1.0, 1.0, 1.0, 1.0);
409 
410     osg::Quat quat = matrix.getRotate();
411 
412     osg::notify(osg::NOTICE)<<"Matrix = "<<matrix<<"rotation = "<<quat<<", expected quat = (0,0,0,1)"<<std::endl;
413 }
414 
testDecompose()415 void testDecompose()
416 {
417     double angx = osg::DegreesToRadians(30.0);
418     double angy = osg::DegreesToRadians(30.0);
419     double angz = osg::DegreesToRadians(30.0);
420 
421     osg::Quat qx, qy, qz;
422     qx.makeRotate(angx, osg::Vec3f (1.0f, 0.0f, 0.0f));
423     qy.makeRotate(angy, osg::Vec3f (0.0f, 1.0f, 0.0f));
424     qz.makeRotate(angz, osg::Vec3f (0.0f, 0.0f, 1.0f));
425 
426     osg::Quat rotation = qx * qy * qz;
427 
428     osg::Matrixf matf;
429     matf.makeRotate(rotation);
430 
431     printf ("Test - Matrix::decompos(), input rotation  : %f %f %f %f\n", rotation._v[0], rotation._v[1], rotation._v[2], rotation._v[3]);
432 
433     osg::Vec3f transf;
434     osg::Quat  rotf;
435     osg::Vec3f sclf;
436     osg::Quat  sof;
437     matf.decompose (transf, rotf, sclf, sof);
438     printf ("Matrixf::decomposef\n");
439     printf ("Translation      : %f %f %f\n", transf.x(), transf.y(), transf.z());
440     printf ("Rotation         : %f %f %f %f\n", rotf._v[0], rotf._v[1], rotf._v[2], rotf._v[3]);
441     printf ("Scale            : %f %f %f\n", sclf.x(), sclf.y(), sclf.z());
442     printf ("Scale Orientation: %f %f %f %f\n", sof._v[0], sof._v[1], sof._v[2], sof._v[3]);
443 
444     osg::Matrixd matd;
445     matd.makeRotate(rotation);
446 
447     osg::Vec3f transd;
448     osg::Quat  rotd;
449     osg::Vec3f scld;
450     osg::Quat  sod;
451     matd.decompose (transd, rotd, scld, sod);
452     printf ("Matrixd::decompose\n");
453     printf ("Translation      : %f %f %f\n", transd.x(), transd.y(), transd.z());
454     printf ("Rotation         : %f %f %f %f\n", rotd._v[0], rotd._v[1], rotd._v[2], rotd._v[3]);
455     printf ("Scale            : %f %f %f\n", scld.x(), scld.y(), scld.z());
456     printf ("Scale Orientation: %f %f %f %f\n", sod._v[0], sod._v[1], sod._v[2], sod._v[3]);
457 
458     osg::notify(osg::NOTICE)<<std::endl;
459 }
460 
461 class MyThread : public OpenThreads::Thread {
462 public:
run(void)463     void run(void) { }
464 };
465 
466 class NotifyThread : public OpenThreads::Thread {
467 public:
468 
NotifyThread(osg::NotifySeverity level,const std::string & message)469     NotifyThread(osg::NotifySeverity level, const std::string& message):
470     _done(false),
471     _level(level),
472     _message(message) {}
473 
~NotifyThread()474     ~NotifyThread()
475     {
476         _done = true;
477         if (isRunning())
478         {
479             cancel();
480             join();
481         }
482     }
483 
run(void)484     void run(void)
485     {
486         std::cout << "Entering thread ..." <<_message<< std::endl;
487 
488         unsigned int count=0;
489 
490         while(!_done)
491         {
492             ++count;
493 #if 1
494             osg::notify(_level)<<_message<<this<<"\n";
495 #else
496             osg::notify(_level)<<_message<<this<<std::endl;
497 #endif
498         }
499 
500         std::cout << "Leaving thread ..." <<_message<< " count="<<count<<std::endl;
501     }
502 
503     bool                  _done;
504     osg::NotifySeverity   _level;
505     std::string           _message;
506 
507 };
508 
testThreadInitAndExit()509 void testThreadInitAndExit()
510 {
511     std::cout<<"******   Running thread start and delete test   ****** "<<std::endl;
512 
513     {
514         MyThread thread;
515         thread.startThread();
516     }
517 
518     // add a sleep to allow the thread start to fall over it its going to.
519     OpenThreads::Thread::microSleep(500000);
520 
521     std::cout<<"pass    thread start and delete test"<<std::endl<<std::endl;
522 
523 
524     std::cout<<"******   Running notify thread test   ****** "<<std::endl;
525 
526     {
527         NotifyThread thread1(osg::INFO,"thread one:");
528         NotifyThread thread2(osg::INFO,"thread two:");
529         NotifyThread thread3(osg::INFO,"thread three:");
530         NotifyThread thread4(osg::INFO,"thread four:");
531         thread1.startThread();
532         thread2.startThread();
533         thread3.startThread();
534         thread4.startThread();
535 
536         // add a sleep to allow the thread start to fall over it its going to.
537         OpenThreads::Thread::microSleep(5000000);
538     }
539 
540     std::cout<<"pass    noitfy thread test."<<std::endl<<std::endl;
541 }
542 
testPolytope()543 void testPolytope()
544 {
545     osg::Polytope pt;
546     pt.setToBoundingBox(osg::BoundingBox(-1000, -1000, -1000, 1000, 1000, 1000));
547     bool bContains = pt.contains(osg::Vec3(0, 0, 0));
548     if (bContains)
549     {
550         std::cout<<"Polytope pt.contains(osg::Vec3(0, 0, 0)) has succeeded."<<std::endl;
551     }
552     else
553     {
554         std::cout<<"Polytope pt.contains(osg::Vec3(0, 0, 0)) has failed."<<std::endl;
555     }
556 
557 }
558 
559 
main(int argc,char ** argv)560 int main( int argc, char** argv )
561 {
562     osg::ArgumentParser arguments(&argc,argv);
563 
564     // set up the usage document, in case we need to print out how to use this program.
565     arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which runs units tests.");
566     arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options]");
567     arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
568     arguments.getApplicationUsage()->addCommandLineOption("qt","Display qualified tests.");
569     arguments.getApplicationUsage()->addCommandLineOption("quat","Display extended quaternion tests.");
570     arguments.getApplicationUsage()->addCommandLineOption("quat_scaled sx sy sz","Display extended quaternion tests of pre scaled matrix.");
571     arguments.getApplicationUsage()->addCommandLineOption("sizeof","Display sizeof tests.");
572     arguments.getApplicationUsage()->addCommandLineOption("matrix","Display qualified tests.");
573     arguments.getApplicationUsage()->addCommandLineOption("performance","Display qualified tests.");
574     arguments.getApplicationUsage()->addCommandLineOption("read-threads <numthreads>","Run multi-thread reading test.");
575 
576 
577     if (arguments.argc()<=1)
578     {
579         arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
580         return 1;
581     }
582 
583     bool printQualifiedTest = false;
584     while (arguments.read("qt")) printQualifiedTest = true;
585 
586     bool printMatrixTest = false;
587     while (arguments.read("matrix")) printMatrixTest = true;
588 
589     bool printSizeOfTest = false;
590     while (arguments.read("sizeof")) printSizeOfTest = true;
591 
592     bool printFileNameUtilsTests = false;
593     while (arguments.read("filenames")) printFileNameUtilsTests = true;
594 
595     bool printQuatTest = false;
596     while (arguments.read("quat")) printQuatTest = true;
597 
598     int numReadThreads = 0;
599     while (arguments.read("read-threads", numReadThreads)) {}
600 
601     bool printPolytopeTest = false;
602     while (arguments.read("polytope")) printPolytopeTest = true;
603 
604     bool doTestThreadInitAndExit = false;
605     while (arguments.read("thread")) doTestThreadInitAndExit = true;
606 
607     osg::Vec3d quat_scale(1.0,1.0,1.0);
608     while (arguments.read("quat_scaled", quat_scale.x(), quat_scale.y(), quat_scale.z() )) printQuatTest = true;
609 
610     bool performanceTest = false;
611     while (arguments.read("p") || arguments.read("performance")) performanceTest = true;
612 
613     // if user request help write it out to cout.
614     if (arguments.read("-h") || arguments.read("--help"))
615     {
616         std::cout<<arguments.getApplicationUsage()->getCommandLineUsage()<<std::endl;
617         arguments.getApplicationUsage()->write(std::cout,arguments.getApplicationUsage()->getCommandLineOptions());
618         return 1;
619     }
620 
621     // any option left unread are converted into errors to write out later.
622     arguments.reportRemainingOptionsAsUnrecognized();
623 
624     // report any errors if they have occurred when parsing the program arguments.
625     if (arguments.errors())
626     {
627         arguments.writeErrorMessages(std::cout);
628         return 1;
629     }
630 
631     if (printQuatTest)
632     {
633         testQuat(quat_scale);
634     }
635 
636     if (printMatrixTest)
637     {
638         std::cout<<"******   Running matrix tests   ******"<<std::endl;
639 
640         testFrustum(-1,1,-1,1,1,1000);
641         testFrustum(0,1,1,2,2.5,100000);
642 
643         testOrtho(0,1,1,2,2.1,1000);
644         testOrtho(-1,10,1,20,2.5,100000);
645 
646         testPerspective(20,1,1,1000);
647         testPerspective(90,2,1,1000);
648 
649         testLookAt(osg::Vec3(10.0,4.0,2.0),osg::Vec3(10.0,4.0,2.0)+osg::Vec3(0.0,1.0,0.0),osg::Vec3(0.0,0.0,1.0));
650         testLookAt(osg::Vec3(10.0,4.0,2.0),osg::Vec3(10.0,4.0,2.0)+osg::Vec3(1.0,1.0,0.0),osg::Vec3(0.0,0.0,1.0));
651 
652         testMatrixInvert(osg::Matrix(0.999848,  -0.002700,  0.017242, -0.1715,
653                                      0,         0.987960,   0.154710,  0.207295,
654                                      -0.017452, -0.154687,  0.987809, -0.98239,
655                                      0,         0,          0,         1));
656 
657         testMatrixInvert(osg::Matrix(0.999848,  -0.002700,  0.017242,   0.0,
658                                      0.0,        0.987960,   0.154710,   0.0,
659                                      -0.017452, -0.154687,  0.987809,   0.0,
660                                      -0.1715,    0.207295,  -0.98239,   1.0));
661 
662         testDecompose();
663 
664     }
665 
666     if (printSizeOfTest)
667     {
668         std::cout<<"**** sizeof() tests  ******"<<std::endl;
669 
670         sizeOfTest();
671 
672         std::cout<<std::endl;
673     }
674 
675 
676     if (performanceTest)
677     {
678         std::cout<<"**** performance tests  ******"<<std::endl;
679 
680         runPerformanceTests();
681     }
682 
683     if (numReadThreads>0)
684     {
685         runMultiThreadReadTests(numReadThreads, arguments);
686         return 0;
687     }
688 
689 
690     if (printPolytopeTest)
691     {
692         testPolytope();
693     }
694 
695 
696     if (printQualifiedTest)
697     {
698          std::cout<<"*****   Qualified Tests  ******"<<std::endl;
699 
700          osgUtx::QualifiedTestPrinter printer;
701          osgUtx::TestGraph::instance().root()->accept( printer );
702          std::cout<<std::endl;
703     }
704 
705     if (printFileNameUtilsTests)
706     {
707         runFileNameUtilsTest(arguments);
708     }
709 
710 
711     if (doTestThreadInitAndExit)
712     {
713         testThreadInitAndExit();
714     }
715 
716     std::cout<<"******   Running tests   ******"<<std::endl;
717 
718     // Global Data or Context
719     osgUtx::TestContext ctx;
720     osgUtx::TestRunner runner( ctx );
721     runner.specify("root");
722 
723     osgUtx::TestGraph::instance().root()->accept( runner );
724 
725     return 0;
726 }
727