math.cpp

Go to the documentation of this file.
00001 
00034 #include "linden_common.h"
00035 #include "lltut.h"
00036 
00037 #include "llcrc.h"
00038 #include "llline.h"
00039 #include "llmath.h"
00040 #include "llrand.h"
00041 #include "llsphere.h"
00042 #include "lluuid.h"
00043 #include "v3math.h"
00044 
00045 namespace tut
00046 {
00047         struct math_data
00048         {
00049         };
00050         typedef test_group<math_data> math_test;
00051         typedef math_test::object math_object;
00052         tut::math_test tm("basic_linden_math");
00053 
00054         template<> template<>
00055         void math_object::test<1>()
00056         {
00057                 S32 val = 89543;
00058                 val = llabs(val);
00059                 ensure("integer absolute value 1", (89543 == val));
00060                 val = -500;
00061                 val = llabs(val);
00062                 ensure("integer absolute value 2", (500 == val));
00063         }
00064 
00065         template<> template<>
00066         void math_object::test<2>()
00067         {
00068                 F32 val = -2583.4f;
00069                 val = llabs(val);
00070                 ensure("float absolute value 1", (2583.4f == val));
00071                 val = 430903.f;
00072                 val = llabs(val);
00073                 ensure("float absolute value 2", (430903.f == val));
00074         }
00075 
00076         template<> template<>
00077         void math_object::test<3>()
00078         {
00079                 F64 val = 387439393.987329839;
00080                 val = llabs(val);
00081                 ensure("double absolute value 1", (387439393.987329839 == val));
00082                 val = -8937843.9394878;
00083                 val = llabs(val);
00084                 ensure("double absolute value 2", (8937843.9394878 == val));
00085         }
00086 
00087         template<> template<>
00088         void math_object::test<4>()
00089         {
00090                 F32 val = 430903.9f;
00091                 S32 val1 = lltrunc(val);
00092                 ensure("float truncate value 1", (430903 == val1));
00093                 val = -2303.9f;
00094                 val1 = lltrunc(val);
00095                 ensure("float truncate value 2", (-2303  == val1));
00096         }
00097 
00098         template<> template<>
00099         void math_object::test<5>()
00100         {
00101                 F64 val = 387439393.987329839 ;
00102                 S32 val1 = lltrunc(val);
00103                 ensure("float truncate value 1", (387439393 == val1));
00104                 val = -387439393.987329839;
00105                 val1 = lltrunc(val);
00106                 ensure("float truncate value 2", (-387439393  == val1));
00107         }
00108 
00109         template<> template<>
00110         void math_object::test<6>()
00111         {
00112                 F32 val = 430903.2f;
00113                 S32 val1 = llfloor(val);
00114                 ensure("float llfloor value 1", (430903 == val1));
00115                 val = -430903.9f;
00116                 val1 = llfloor(val);
00117                 ensure("float llfloor value 2", (-430904 == val1));
00118         }
00119 
00120         template<> template<>
00121         void math_object::test<7>()
00122         {
00123                 F32 val = 430903.2f;
00124                 S32 val1 = llceil(val);
00125                 ensure("float llceil value 1", (430904 == val1));
00126                 val = -430903.9f;
00127                 val1 = llceil(val);
00128                 ensure("float llceil value 2", (-430903 == val1));
00129         }
00130 
00131         template<> template<>
00132         void math_object::test<8>()
00133         {
00134                 F32 val = 430903.2f;
00135                 S32 val1 = llround(val);
00136                 ensure("float llround value 1", (430903 == val1));
00137                 val = -430903.9f;
00138                 val1 = llround(val);
00139                 ensure("float llround value 2", (-430904 == val1));
00140         }
00141 
00142         template<> template<>
00143         void math_object::test<9>()
00144         {
00145                 F32 val = 430905.2654f, nearest = 100.f;
00146                 val = llround(val, nearest);
00147                 ensure("float llround value 1", (430900 == val));
00148                 val = -430905.2654f, nearest = 10.f;
00149                 val = llround(val, nearest);
00150                 ensure("float llround value 1", (-430910 == val));
00151         }
00152 
00153         template<> template<>
00154         void math_object::test<10>()
00155         {
00156                 F64 val = 430905.2654, nearest = 100.0;
00157                 val = llround(val, nearest);
00158                 ensure("double llround value 1", (430900 == val));
00159                 val = -430905.2654, nearest = 10.0;
00160                 val = llround(val, nearest);
00161                 ensure("double llround value 1", (-430910.00000 == val));
00162         }
00163 
00164         template<> template<>
00165         void math_object::test<11>()
00166         {
00167                 const F32       F_PI            = 3.1415926535897932384626433832795f;
00168                 F32 angle = 3506.f;
00169                 angle =  llsimple_angle(angle);
00170                 ensure("llsimple_angle  value 1", (angle <=F_PI && angle >= -F_PI));
00171                 angle = -431.f;
00172                 angle =  llsimple_angle(angle);
00173                 ensure("llsimple_angle  value 1", (angle <=F_PI && angle >= -F_PI));
00174         }
00175 }
00176 
00177 namespace tut
00178 {
00179         struct uuid_data
00180         {
00181                 LLUUID id;
00182         };
00183         typedef test_group<uuid_data> uuid_test;
00184         typedef uuid_test::object uuid_object;
00185         tut::uuid_test tu("uuid");
00186 
00187         template<> template<>
00188         void uuid_object::test<1>()
00189         {
00190                 ensure("uuid null", id.isNull());
00191                 id.generate();
00192                 ensure("generate not null", id.notNull());
00193                 id.setNull();
00194                 ensure("set null", id.isNull());
00195         }
00196 
00197         template<> template<>
00198         void uuid_object::test<2>()
00199         {
00200                 id.generate();
00201                 LLUUID a(id);
00202                 ensure_equals("copy equal", id, a);
00203                 a.generate();
00204                 ensure_not_equals("generate not equal", id, a);
00205                 a = id;
00206                 ensure_equals("assignment equal", id, a);
00207         }
00208 
00209         template<> template<>
00210         void uuid_object::test<3>()
00211         {
00212                 id.generate();
00213                 LLUUID copy(id);
00214                 LLUUID mask;
00215                 mask.generate();
00216                 copy ^= mask;
00217                 ensure_not_equals("mask not equal", id, copy);
00218                 copy ^= mask;
00219                 ensure_equals("mask back", id, copy);
00220         }
00221 
00222         template<> template<>
00223         void uuid_object::test<4>()
00224         {
00225                 id.generate();
00226                 std::string id_str = id.asString();
00227                 LLUUID copy(id_str.c_str());
00228                 ensure_equals("string serialization", id, copy);
00229         }
00230         
00231 }
00232 
00233 namespace tut
00234 {
00235         struct crc_data
00236         {
00237         };
00238         typedef test_group<crc_data> crc_test;
00239         typedef crc_test::object crc_object;
00240         tut::crc_test tc("crc");
00241 
00242         template<> template<>
00243         void crc_object::test<1>()
00244         {
00245                 /* Test buffer update and individual char update */
00246                 const char TEST_BUFFER[] = "hello &#$)$&Nd0";
00247                 LLCRC c1, c2;
00248                 c1.update((U8*)TEST_BUFFER, sizeof(TEST_BUFFER) - 1);
00249                 char* rh = (char*)TEST_BUFFER;
00250                 while(*rh != '\0')
00251                 {
00252                         c2.update(*rh);
00253                         ++rh;
00254                 }
00255                 ensure_equals("crc update 1", c1.getCRC(), c2.getCRC());
00256         }
00257 
00258         template<> template<>
00259         void crc_object::test<2>()
00260         {
00261                 /* Test mixing of buffer and individual char update */
00262                 const char TEST_BUFFER1[] = "Split Buffer one $^%$%#@$";
00263                 const char TEST_BUFFER2[] = "Split Buffer two )(8723#5dsds";
00264                 LLCRC c1, c2;
00265                 c1.update((U8*)TEST_BUFFER1, sizeof(TEST_BUFFER1) - 1);
00266                 char* rh = (char*)TEST_BUFFER2;
00267                 while(*rh != '\0')
00268                 {
00269                         c1.update(*rh);
00270                         ++rh;
00271                 }
00272 
00273                 rh = (char*)TEST_BUFFER1;
00274                 while(*rh != '\0')
00275                 {
00276                         c2.update(*rh);
00277                         ++rh;
00278                 }
00279                 c2.update((U8*)TEST_BUFFER2, sizeof(TEST_BUFFER2) - 1);
00280 
00281                 ensure_equals("crc update 2", c1.getCRC(), c2.getCRC());
00282         }
00283 }
00284 
00285 namespace tut
00286 {
00287         struct sphere_data
00288         {
00289         };
00290         typedef test_group<sphere_data> sphere_test;
00291         typedef sphere_test::object sphere_object;
00292         tut::sphere_test tsphere("LLSphere");
00293 
00294         template<> template<>
00295         void sphere_object::test<1>()
00296         {
00297                 // test LLSphere::contains() and ::overlaps()
00298                 S32 number_of_tests = 10;
00299                 for (S32 test = 0; test < number_of_tests; ++test)
00300                 {
00301                         LLVector3 first_center(1.f, 1.f, 1.f);
00302                         F32 first_radius = 3.f;
00303                         LLSphere first_sphere( first_center, first_radius );
00304         
00305                         F32 half_millimeter = 0.0005f;
00306                         LLVector3 direction( ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f);
00307                         direction.normalize();
00308         
00309                         F32 distance = ll_frand(first_radius - 2.f * half_millimeter);
00310                         LLVector3 second_center = first_center + distance * direction;
00311                         F32 second_radius = first_radius - distance - half_millimeter;
00312                         LLSphere second_sphere( second_center, second_radius );
00313                         ensure("first sphere should contain the second", first_sphere.contains(second_sphere));
00314                         ensure("first sphere should overlap the second", first_sphere.overlaps(second_sphere));
00315         
00316                         distance = first_radius + ll_frand(first_radius);
00317                         second_center = first_center + distance * direction;
00318                         second_radius = distance - first_radius + half_millimeter;
00319                         second_sphere.set( second_center, second_radius );
00320                         ensure("first sphere should NOT contain the second", !first_sphere.contains(second_sphere));
00321                         ensure("first sphere should overlap the second", first_sphere.overlaps(second_sphere));
00322         
00323                         distance = first_radius + ll_frand(first_radius) + half_millimeter;
00324                         second_center = first_center + distance * direction;
00325                         second_radius = distance - first_radius - half_millimeter;
00326                         second_sphere.set( second_center, second_radius );
00327                         ensure("first sphere should NOT contain the second", !first_sphere.contains(second_sphere));
00328                         ensure("first sphere should NOT overlap the second", !first_sphere.overlaps(second_sphere));
00329                 }
00330         }
00331 
00332         template<> template<>
00333         void sphere_object::test<2>()
00334         {
00335                 // test LLSphere::getBoundingSphere()
00336                 S32 number_of_tests = 100;
00337                 S32 number_of_spheres = 10;
00338                 F32 sphere_center_range = 32.f;
00339                 F32 sphere_radius_range = 5.f;
00340 
00341                 for (S32 test = 0; test < number_of_tests; ++test)
00342                 {
00343                         // gegnerate a bunch of random sphere
00344                         std::vector< LLSphere > sphere_list;
00345                         for (S32 sphere_count=0; sphere_count < number_of_spheres; ++sphere_count)
00346                         {
00347                                 LLVector3 direction( ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f);
00348                                 direction.normalize();
00349                                 F32 distance = ll_frand(sphere_center_range);
00350                                 LLVector3 center = distance * direction;
00351                                 F32 radius = ll_frand(sphere_radius_range);
00352                                 LLSphere sphere( center, radius );
00353                                 sphere_list.push_back(sphere);
00354                         }
00355 
00356                         // compute the bounding sphere
00357                         LLSphere bounding_sphere = LLSphere::getBoundingSphere(sphere_list);
00358 
00359                         // make sure all spheres are inside the bounding sphere
00360                         {
00361                                 std::vector< LLSphere >::const_iterator sphere_itr;
00362                                 for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr)
00363                                 {
00364                                         ensure("sphere should be contained by the bounding sphere", bounding_sphere.contains(*sphere_itr));
00365                                 }
00366                         }
00367 
00368                         // TODO -- improve LLSphere::getBoundingSphere() to the point where
00369                         // we can reduce the 'expansion' in the two tests below to about 
00370                         // 2 mm or less
00371 
00372                         F32 expansion = 0.005f;
00373                         // move all spheres out a little bit 
00374                         // and count how many are NOT contained
00375                         {
00376                                 std::vector< LLVector3 > uncontained_directions;
00377                                 std::vector< LLSphere >::iterator sphere_itr;
00378                                 for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr)
00379                                 {
00380                                         LLVector3 direction = sphere_itr->getCenter() - bounding_sphere.getCenter();
00381                                         direction.normalize();
00382         
00383                                         sphere_itr->setCenter( sphere_itr->getCenter() + expansion * direction );
00384                                         if (! bounding_sphere.contains( *sphere_itr ) )
00385                                         {
00386                                                 uncontained_directions.push_back(direction);
00387                                         }
00388                                 }
00389                                 ensure("when moving spheres out there should be at least two uncontained spheres", 
00390                                                 uncontained_directions.size() > 1);
00391 
00392                                 /* TODO -- when the bounding sphere algorithm is improved we can open up this test
00393                                  * at the moment it occasionally fails when the sphere collection is tight and small
00394                                  * (2 meters or less)
00395                                 if (2 == uncontained_directions.size() )
00396                                 {
00397                                         // if there were only two uncontained spheres then
00398                                         // the two directions should be nearly opposite
00399                                         F32 dir_dot = uncontained_directions[0] * uncontained_directions[1];
00400                                         ensure("two uncontained spheres should lie opposite the bounding center", dir_dot < -0.95f);
00401                                 }
00402                                 */
00403                         }
00404 
00405                         // compute the new bounding sphere
00406                         bounding_sphere = LLSphere::getBoundingSphere(sphere_list);
00407 
00408                         // increase the size of all spheres a little bit
00409                         // and count how many are NOT contained
00410                         {
00411                                 std::vector< LLVector3 > uncontained_directions;
00412                                 std::vector< LLSphere >::iterator sphere_itr;
00413                                 for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr)
00414                                 {
00415                                         LLVector3 direction = sphere_itr->getCenter() - bounding_sphere.getCenter();
00416                                         direction.normalize();
00417         
00418                                         sphere_itr->setRadius( sphere_itr->getRadius() + expansion );
00419                                         if (! bounding_sphere.contains( *sphere_itr ) )
00420                                         {
00421                                                 uncontained_directions.push_back(direction);
00422                                         }
00423                                 }
00424                                 ensure("when boosting sphere radii there should be at least two uncontained spheres", 
00425                                                 uncontained_directions.size() > 1);
00426 
00427                                 /* TODO -- when the bounding sphere algorithm is improved we can open up this test
00428                                  * at the moment it occasionally fails when the sphere collection is tight and small
00429                                  * (2 meters or less)
00430                                 if (2 == uncontained_directions.size() )
00431                                 {
00432                                         // if there were only two uncontained spheres then
00433                                         // the two directions should be nearly opposite
00434                                         F32 dir_dot = uncontained_directions[0] * uncontained_directions[1];
00435                                         ensure("two uncontained spheres should lie opposite the bounding center", dir_dot < -0.95f);
00436                                 }
00437                                 */
00438                         }
00439                 }
00440         }
00441 }
00442 
00443 namespace tut
00444 {
00445         F32 SMALL_RADIUS = 1.0f;
00446         F32 MEDIUM_RADIUS = 5.0f;
00447         F32 LARGE_RADIUS = 10.0f;
00448 
00449         struct line_data
00450         {
00451         };
00452         typedef test_group<line_data> line_test;
00453         typedef line_test::object line_object;
00454         tut::line_test tline("LLLine");
00455 
00456         template<> template<>
00457         void line_object::test<1>()
00458         {
00459                 // this is a test for LLLine::intersects(point) which returns TRUE 
00460                 // if the line passes within some tolerance of point
00461 
00462                 // these tests will have some floating point error, 
00463                 // so we need to specify how much error is ok
00464                 F32 allowable_relative_error = 0.00001f;
00465                 S32 number_of_tests = 100;
00466                 for (S32 test = 0; test < number_of_tests; ++test)
00467                 {
00468                         // generate some random point to be on the line
00469                         LLVector3 point_on_line( ll_frand(2.f) - 1.f, 
00470                                                                          ll_frand(2.f) - 1.f, 
00471                                                                          ll_frand(2.f) - 1.f);
00472                         point_on_line.normalize();
00473                         point_on_line *= ll_frand(LARGE_RADIUS);
00474 
00475                         // generate some random point to "intersect"
00476                         LLVector3 random_direction ( ll_frand(2.f) - 1.f, 
00477                                                                                  ll_frand(2.f) - 1.f, 
00478                                                                                  ll_frand(2.f) - 1.f);
00479                         random_direction.normalize();
00480 
00481                         LLVector3 random_offset( ll_frand(2.f) - 1.f, 
00482                                                                          ll_frand(2.f) - 1.f, 
00483                                                                          ll_frand(2.f) - 1.f);
00484                         random_offset.normalize();
00485                         random_offset *= ll_frand(SMALL_RADIUS);
00486 
00487                         LLVector3 point = point_on_line + MEDIUM_RADIUS * random_direction
00488                                 + random_offset;
00489         
00490                         // compute the axis of approach (a unit vector between the points)
00491                         LLVector3 axis_of_approach = point - point_on_line;
00492                         axis_of_approach.normalize();
00493         
00494                         // compute the direction of the the first line (perp to axis_of_approach)
00495                         LLVector3 first_dir( ll_frand(2.f) - 1.f, 
00496                                                                  ll_frand(2.f) - 1.f, 
00497                                                                  ll_frand(2.f) - 1.f);
00498                         first_dir.normalize();
00499                         F32 dot = first_dir * axis_of_approach;         
00500                         first_dir -= dot * axis_of_approach;    // subtract component parallel to axis
00501                         first_dir.normalize();
00502         
00503                         // construct the line
00504                         LLVector3 another_point_on_line = point_on_line + ll_frand(LARGE_RADIUS) * first_dir;
00505                         LLLine line(another_point_on_line, point_on_line);
00506         
00507                         // test that the intersection point is within MEDIUM_RADIUS + SMALL_RADIUS
00508                         F32 test_radius = MEDIUM_RADIUS + SMALL_RADIUS;
00509                         test_radius += (LARGE_RADIUS * allowable_relative_error);
00510                         ensure("line should pass near intersection point", line.intersects(point, test_radius));
00511 
00512                         test_radius = allowable_relative_error * (point - point_on_line).length();
00513                         ensure("line should intersect point used to define it", line.intersects(point_on_line, test_radius));
00514                 }
00515         }
00516 
00517         template<> template<>
00518         void line_object::test<2>()
00519         {
00520                 // this is a test for LLLine::nearestApproach(LLLIne) method
00521                 // which computes the point on a line nearest another line
00522 
00523                 // these tests will have some floating point error, 
00524                 // so we need to specify how much error is ok
00525                 // TODO -- make nearestApproach() algorithm more accurate so
00526                 // we can tighten the allowable_error.  Most tests are tighter
00527                 // than one milimeter, however when doing randomized testing
00528                 // you can walk into inaccurate cases.
00529                 F32 allowable_relative_error = 0.001f;
00530                 S32 number_of_tests = 100;
00531                 for (S32 test = 0; test < number_of_tests; ++test)
00532                 {
00533                         // generate two points to be our known nearest approaches
00534                         LLVector3 some_point( ll_frand(2.f) - 1.f, 
00535                                                                   ll_frand(2.f) - 1.f, 
00536                                                                   ll_frand(2.f) - 1.f);
00537                         some_point.normalize();
00538                         some_point *= ll_frand(LARGE_RADIUS);
00539 
00540                         LLVector3 another_point( ll_frand(2.f) - 1.f, 
00541                                                                          ll_frand(2.f) - 1.f, 
00542                                                                          ll_frand(2.f) - 1.f);
00543                         another_point.normalize();
00544                         another_point *= ll_frand(LARGE_RADIUS);
00545 
00546                         // compute the axis of approach (a unit vector between the points)
00547                         LLVector3 axis_of_approach = another_point - some_point;
00548                         axis_of_approach.normalize();
00549         
00550                         // compute the direction of the the first line (perp to axis_of_approach)
00551                         LLVector3 first_dir( ll_frand(2.f) - 1.f, 
00552                                                                  ll_frand(2.f) - 1.f, 
00553                                                                  ll_frand(2.f) - 1.f);
00554                         F32 dot = first_dir * axis_of_approach;         
00555                         first_dir -= dot * axis_of_approach;            // subtract component parallel to axis
00556                         first_dir.normalize();                                          // normalize
00557         
00558                         // compute the direction of the the second line
00559                         LLVector3 second_dir( ll_frand(2.f) - 1.f, 
00560                                                                   ll_frand(2.f) - 1.f, 
00561                                                                   ll_frand(2.f) - 1.f);
00562                         dot = second_dir * axis_of_approach;            
00563                         second_dir -= dot * axis_of_approach;
00564                         second_dir.normalize();
00565 
00566                         // make sure the lines aren't too parallel, 
00567                         dot = fabsf(first_dir * second_dir);
00568                         if (dot > 0.99f)
00569                         {
00570                                 // skip this test, we're not interested in testing 
00571                                 // the intractible cases
00572                                 continue;
00573                         }
00574         
00575                         // construct the lines
00576                         LLVector3 first_point = some_point + ll_frand(LARGE_RADIUS) * first_dir;
00577                         LLLine first_line(first_point, some_point);
00578         
00579                         LLVector3 second_point = another_point + ll_frand(LARGE_RADIUS) * second_dir;
00580                         LLLine second_line(second_point, another_point);
00581         
00582                         // compute the points of nearest approach
00583                         LLVector3 some_computed_point = first_line.nearestApproach(second_line);
00584                         LLVector3 another_computed_point = second_line.nearestApproach(first_line);
00585         
00586                         // compute the error
00587                         F32 first_error = (some_point - some_computed_point).length();
00588                         F32 scale = llmax((some_point - another_point).length(), some_point.length());
00589                         scale = llmax(scale, another_point.length());
00590                         scale = llmax(scale, 1.f);
00591                         F32 first_relative_error = first_error / scale;
00592 
00593                         F32 second_error = (another_point - another_computed_point).length();
00594                         F32 second_relative_error = second_error / scale;
00595 
00596                         //if (first_relative_error > allowable_relative_error)
00597                         //{
00598                         //      std::cout << "first_error = " << first_error 
00599                         //              << "  first_relative_error = " << first_relative_error 
00600                         //              << "  scale = " << scale 
00601                         //              << "  dir_dot = " << (first_dir * second_dir)
00602                         //              << std::endl;
00603                         //}
00604                         //if (second_relative_error > allowable_relative_error)
00605                         //{
00606                         //      std::cout << "second_error = " << second_error 
00607                         //              << "  second_relative_error = " << second_relative_error 
00608                         //              << "  scale = " << scale 
00609                         //              << "  dist = " << (some_point - another_point).length()
00610                         //              << "  dir_dot = " << (first_dir * second_dir)
00611                         //              << std::endl;
00612                         //}
00613 
00614                         // test that the errors are small
00615                         ensure("first line should accurately compute its closest approach", 
00616                                         first_relative_error <= allowable_relative_error);
00617                         ensure("second line should accurately compute its closest approach", 
00618                                         second_relative_error <= allowable_relative_error);
00619                 }
00620         }
00621 
00622         F32 ALMOST_PARALLEL = 0.99f;
00623         template<> template<>
00624         void line_object::test<3>()
00625         {
00626                 // this is a test for LLLine::getIntersectionBetweenTwoPlanes() method
00627 
00628                 // first some known tests
00629                 LLLine xy_plane(LLVector3(0.f, 0.f, 2.f), LLVector3(0.f, 0.f, 3.f));
00630                 LLLine yz_plane(LLVector3(2.f, 0.f, 0.f), LLVector3(3.f, 0.f, 0.f));
00631                 LLLine zx_plane(LLVector3(0.f, 2.f, 0.f), LLVector3(0.f, 3.f, 0.f));
00632 
00633                 LLLine x_line;
00634                 LLLine y_line;
00635                 LLLine z_line;
00636 
00637                 bool x_success = LLLine::getIntersectionBetweenTwoPlanes(x_line, xy_plane, zx_plane);
00638                 bool y_success = LLLine::getIntersectionBetweenTwoPlanes(y_line, yz_plane, xy_plane);
00639                 bool z_success = LLLine::getIntersectionBetweenTwoPlanes(z_line, zx_plane, yz_plane);
00640 
00641                 ensure("xy and zx planes should intersect", x_success);
00642                 ensure("yz and xy planes should intersect", y_success);
00643                 ensure("zx and yz planes should intersect", z_success);
00644 
00645                 LLVector3 direction = x_line.getDirection();
00646                 ensure("x_line should be parallel to x_axis", fabs(direction.mV[VX]) == 1.f
00647                                                                       && 0.f == direction.mV[VY]
00648                                                                       && 0.f == direction.mV[VZ] );
00649                 direction = y_line.getDirection();
00650                 ensure("y_line should be parallel to y_axis", 0.f == direction.mV[VX]
00651                                                                                                           && fabs(direction.mV[VY]) == 1.f
00652                                                                       && 0.f == direction.mV[VZ] );
00653                 direction = z_line.getDirection();
00654                 ensure("z_line should be parallel to z_axis", 0.f == direction.mV[VX]
00655                                                                       && 0.f == direction.mV[VY]
00656                                                                                                           && fabs(direction.mV[VZ]) == 1.f );
00657 
00658                 // next some random tests
00659                 F32 allowable_relative_error = 0.0001f;
00660                 S32 number_of_tests = 20;
00661                 for (S32 test = 0; test < number_of_tests; ++test)
00662                 {
00663                         // generate the known line
00664                         LLVector3 some_point( ll_frand(2.f) - 1.f, 
00665                                                                   ll_frand(2.f) - 1.f, 
00666                                                                   ll_frand(2.f) - 1.f);
00667                         some_point.normalize();
00668                         some_point *= ll_frand(LARGE_RADIUS);
00669                         LLVector3 another_point( ll_frand(2.f) - 1.f, 
00670                                                                          ll_frand(2.f) - 1.f, 
00671                                                                          ll_frand(2.f) - 1.f);
00672                         another_point.normalize();
00673                         another_point *= ll_frand(LARGE_RADIUS);
00674                         LLLine known_intersection(some_point, another_point);
00675 
00676                         // compute a plane that intersect the line
00677                         LLVector3 point_on_plane( ll_frand(2.f) - 1.f, 
00678                                                                           ll_frand(2.f) - 1.f, 
00679                                                                           ll_frand(2.f) - 1.f);
00680                         point_on_plane.normalize();
00681                         point_on_plane *= ll_frand(LARGE_RADIUS);
00682                         LLVector3 plane_normal = (point_on_plane - some_point) % known_intersection.getDirection();
00683                         plane_normal.normalize();
00684                         LLLine first_plane(point_on_plane, point_on_plane + plane_normal);
00685 
00686                         // compute a different plane that intersect the line
00687                         LLVector3 point_on_different_plane( ll_frand(2.f) - 1.f, 
00688                                                                                                 ll_frand(2.f) - 1.f, 
00689                                                                                                 ll_frand(2.f) - 1.f);
00690                         point_on_different_plane.normalize();
00691                         point_on_different_plane *= ll_frand(LARGE_RADIUS);
00692                         LLVector3 different_plane_normal = (point_on_different_plane - another_point) % known_intersection.getDirection();
00693                         different_plane_normal.normalize();
00694                         LLLine second_plane(point_on_different_plane, point_on_different_plane + different_plane_normal);
00695 
00696                         if (fabs(plane_normal * different_plane_normal) > ALMOST_PARALLEL)
00697                         {
00698                                 // the two planes are approximately parallel, so we won't test this case
00699                                 continue;
00700                         }
00701 
00702                         LLLine measured_intersection;
00703                         bool success = LLLine::getIntersectionBetweenTwoPlanes(
00704                                         measured_intersection,
00705                                         first_plane,
00706                                         second_plane);
00707 
00708                         ensure("plane intersection should succeed", success);
00709 
00710                         F32 dot = fabs(known_intersection.getDirection() * measured_intersection.getDirection());
00711                         ensure("measured intersection should be parallel to known intersection",
00712                                         dot > ALMOST_PARALLEL);
00713 
00714                         ensure("measured intersection should pass near known point",
00715                                         measured_intersection.intersects(some_point, LARGE_RADIUS * allowable_relative_error));
00716                 }
00717         }
00718 }
00719 

Generated on Fri May 16 08:34:32 2008 for SecondLife by  doxygen 1.5.5