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
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
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
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
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
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
00357 LLSphere bounding_sphere = LLSphere::getBoundingSphere(sphere_list);
00358
00359
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
00369
00370
00371
00372 F32 expansion = 0.005f;
00373
00374
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
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403 }
00404
00405
00406 bounding_sphere = LLSphere::getBoundingSphere(sphere_list);
00407
00408
00409
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
00428
00429
00430
00431
00432
00433
00434
00435
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
00460
00461
00462
00463
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
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
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
00491 LLVector3 axis_of_approach = point - point_on_line;
00492 axis_of_approach.normalize();
00493
00494
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;
00501 first_dir.normalize();
00502
00503
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
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
00521
00522
00523
00524
00525
00526
00527
00528
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
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
00547 LLVector3 axis_of_approach = another_point - some_point;
00548 axis_of_approach.normalize();
00549
00550
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;
00556 first_dir.normalize();
00557
00558
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
00567 dot = fabsf(first_dir * second_dir);
00568 if (dot > 0.99f)
00569 {
00570
00571
00572 continue;
00573 }
00574
00575
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
00583 LLVector3 some_computed_point = first_line.nearestApproach(second_line);
00584 LLVector3 another_computed_point = second_line.nearestApproach(first_line);
00585
00586
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
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
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
00627
00628
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
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
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
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
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
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