diff options
Diffstat (limited to 'indra/llmath/tests/mathmisc_test.cpp')
-rw-r--r-- | indra/llmath/tests/mathmisc_test.cpp | 1328 |
1 files changed, 664 insertions, 664 deletions
diff --git a/indra/llmath/tests/mathmisc_test.cpp b/indra/llmath/tests/mathmisc_test.cpp index f12140cf8f..163cf02350 100644 --- a/indra/llmath/tests/mathmisc_test.cpp +++ b/indra/llmath/tests/mathmisc_test.cpp @@ -1,4 +1,4 @@ -/** +/** * @file math.cpp * @author Phoenix * @date 2005-09-26 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,684 +40,684 @@ namespace tut { - struct math_data - { - }; - typedef test_group<math_data> math_test; - typedef math_test::object math_object; - tut::math_test tm("BasicLindenMath"); - - template<> template<> - void math_object::test<1>() - { - S32 val = 89543; - val = llabs(val); - ensure("integer absolute value 1", (89543 == val)); - val = -500; - val = llabs(val); - ensure("integer absolute value 2", (500 == val)); - } - - template<> template<> - void math_object::test<2>() - { - F32 val = -2583.4f; - val = llabs(val); - ensure("float absolute value 1", (2583.4f == val)); - val = 430903.f; - val = llabs(val); - ensure("float absolute value 2", (430903.f == val)); - } - - template<> template<> - void math_object::test<3>() - { - F64 val = 387439393.987329839; - val = llabs(val); - ensure("double absolute value 1", (387439393.987329839 == val)); - val = -8937843.9394878; - val = llabs(val); - ensure("double absolute value 2", (8937843.9394878 == val)); - } - - template<> template<> - void math_object::test<4>() - { - F32 val = 430903.9f; - S32 val1 = lltrunc(val); - ensure("float truncate value 1", (430903 == val1)); - val = -2303.9f; - val1 = lltrunc(val); - ensure("float truncate value 2", (-2303 == val1)); - } - - template<> template<> - void math_object::test<5>() - { - F64 val = 387439393.987329839 ; - S32 val1 = lltrunc(val); - ensure("float truncate value 1", (387439393 == val1)); - val = -387439393.987329839; - val1 = lltrunc(val); - ensure("float truncate value 2", (-387439393 == val1)); - } - - template<> template<> - void math_object::test<6>() - { - F32 val = 430903.2f; - S32 val1 = llfloor(val); - ensure("float llfloor value 1", (430903 == val1)); - val = -430903.9f; - val1 = llfloor(val); - ensure("float llfloor value 2", (-430904 == val1)); - } - - template<> template<> - void math_object::test<7>() - { - F32 val = 430903.2f; - S32 val1 = llceil(val); - ensure("float llceil value 1", (430904 == val1)); - val = -430903.9f; - val1 = llceil(val); - ensure("float llceil value 2", (-430903 == val1)); - } - - template<> template<> - void math_object::test<8>() - { - F32 val = 430903.2f; - S32 val1 = ll_round(val); - ensure("float ll_round value 1", (430903 == val1)); - val = -430903.9f; - val1 = ll_round(val); - ensure("float ll_round value 2", (-430904 == val1)); - } - - template<> template<> - void math_object::test<9>() - { - F32 val = 430905.2654f, nearest = 100.f; - val = ll_round(val, nearest); - ensure("float ll_round value 1", (430900 == val)); - val = -430905.2654f, nearest = 10.f; - val = ll_round(val, nearest); - ensure("float ll_round value 1", (-430910 == val)); - } - - template<> template<> - void math_object::test<10>() - { - F64 val = 430905.2654, nearest = 100.0; - val = ll_round(val, nearest); - ensure("double ll_round value 1", (430900 == val)); - val = -430905.2654, nearest = 10.0; - val = ll_round(val, nearest); - ensure("double ll_round value 1", (-430910.00000 == val)); - } - - template<> template<> - void math_object::test<11>() - { - const F32 F_PI = 3.1415926535897932384626433832795f; - F32 angle = 3506.f; - angle = llsimple_angle(angle); - ensure("llsimple_angle value 1", (angle <=F_PI && angle >= -F_PI)); - angle = -431.f; - angle = llsimple_angle(angle); - ensure("llsimple_angle value 1", (angle <=F_PI && angle >= -F_PI)); - } + struct math_data + { + }; + typedef test_group<math_data> math_test; + typedef math_test::object math_object; + tut::math_test tm("BasicLindenMath"); + + template<> template<> + void math_object::test<1>() + { + S32 val = 89543; + val = llabs(val); + ensure("integer absolute value 1", (89543 == val)); + val = -500; + val = llabs(val); + ensure("integer absolute value 2", (500 == val)); + } + + template<> template<> + void math_object::test<2>() + { + F32 val = -2583.4f; + val = llabs(val); + ensure("float absolute value 1", (2583.4f == val)); + val = 430903.f; + val = llabs(val); + ensure("float absolute value 2", (430903.f == val)); + } + + template<> template<> + void math_object::test<3>() + { + F64 val = 387439393.987329839; + val = llabs(val); + ensure("double absolute value 1", (387439393.987329839 == val)); + val = -8937843.9394878; + val = llabs(val); + ensure("double absolute value 2", (8937843.9394878 == val)); + } + + template<> template<> + void math_object::test<4>() + { + F32 val = 430903.9f; + S32 val1 = lltrunc(val); + ensure("float truncate value 1", (430903 == val1)); + val = -2303.9f; + val1 = lltrunc(val); + ensure("float truncate value 2", (-2303 == val1)); + } + + template<> template<> + void math_object::test<5>() + { + F64 val = 387439393.987329839 ; + S32 val1 = lltrunc(val); + ensure("float truncate value 1", (387439393 == val1)); + val = -387439393.987329839; + val1 = lltrunc(val); + ensure("float truncate value 2", (-387439393 == val1)); + } + + template<> template<> + void math_object::test<6>() + { + F32 val = 430903.2f; + S32 val1 = llfloor(val); + ensure("float llfloor value 1", (430903 == val1)); + val = -430903.9f; + val1 = llfloor(val); + ensure("float llfloor value 2", (-430904 == val1)); + } + + template<> template<> + void math_object::test<7>() + { + F32 val = 430903.2f; + S32 val1 = llceil(val); + ensure("float llceil value 1", (430904 == val1)); + val = -430903.9f; + val1 = llceil(val); + ensure("float llceil value 2", (-430903 == val1)); + } + + template<> template<> + void math_object::test<8>() + { + F32 val = 430903.2f; + S32 val1 = ll_round(val); + ensure("float ll_round value 1", (430903 == val1)); + val = -430903.9f; + val1 = ll_round(val); + ensure("float ll_round value 2", (-430904 == val1)); + } + + template<> template<> + void math_object::test<9>() + { + F32 val = 430905.2654f, nearest = 100.f; + val = ll_round(val, nearest); + ensure("float ll_round value 1", (430900 == val)); + val = -430905.2654f, nearest = 10.f; + val = ll_round(val, nearest); + ensure("float ll_round value 1", (-430910 == val)); + } + + template<> template<> + void math_object::test<10>() + { + F64 val = 430905.2654, nearest = 100.0; + val = ll_round(val, nearest); + ensure("double ll_round value 1", (430900 == val)); + val = -430905.2654, nearest = 10.0; + val = ll_round(val, nearest); + ensure("double ll_round value 1", (-430910.00000 == val)); + } + + template<> template<> + void math_object::test<11>() + { + const F32 F_PI = 3.1415926535897932384626433832795f; + F32 angle = 3506.f; + angle = llsimple_angle(angle); + ensure("llsimple_angle value 1", (angle <=F_PI && angle >= -F_PI)); + angle = -431.f; + angle = llsimple_angle(angle); + ensure("llsimple_angle value 1", (angle <=F_PI && angle >= -F_PI)); + } } namespace tut { - struct uuid_data - { - LLUUID id; - }; - typedef test_group<uuid_data> uuid_test; - typedef uuid_test::object uuid_object; - tut::uuid_test tu("LLUUID"); - - template<> template<> - void uuid_object::test<1>() - { - ensure("uuid null", id.isNull()); - id.generate(); - ensure("generate not null", id.notNull()); - id.setNull(); - ensure("set null", id.isNull()); - } - - template<> template<> - void uuid_object::test<2>() - { - id.generate(); - LLUUID a(id); - ensure_equals("copy equal", id, a); - a.generate(); - ensure_not_equals("generate not equal", id, a); - a = id; - ensure_equals("assignment equal", id, a); - } - - template<> template<> - void uuid_object::test<3>() - { - id.generate(); - LLUUID copy(id); - LLUUID mask; - mask.generate(); - copy ^= mask; - ensure_not_equals("mask not equal", id, copy); - copy ^= mask; - ensure_equals("mask back", id, copy); - } - - template<> template<> - void uuid_object::test<4>() - { - id.generate(); - std::string id_str = id.asString(); - LLUUID copy(id_str.c_str()); - ensure_equals("string serialization", id, copy); - } - + struct uuid_data + { + LLUUID id; + }; + typedef test_group<uuid_data> uuid_test; + typedef uuid_test::object uuid_object; + tut::uuid_test tu("LLUUID"); + + template<> template<> + void uuid_object::test<1>() + { + ensure("uuid null", id.isNull()); + id.generate(); + ensure("generate not null", id.notNull()); + id.setNull(); + ensure("set null", id.isNull()); + } + + template<> template<> + void uuid_object::test<2>() + { + id.generate(); + LLUUID a(id); + ensure_equals("copy equal", id, a); + a.generate(); + ensure_not_equals("generate not equal", id, a); + a = id; + ensure_equals("assignment equal", id, a); + } + + template<> template<> + void uuid_object::test<3>() + { + id.generate(); + LLUUID copy(id); + LLUUID mask; + mask.generate(); + copy ^= mask; + ensure_not_equals("mask not equal", id, copy); + copy ^= mask; + ensure_equals("mask back", id, copy); + } + + template<> template<> + void uuid_object::test<4>() + { + id.generate(); + std::string id_str = id.asString(); + LLUUID copy(id_str.c_str()); + ensure_equals("string serialization", id, copy); + } + } namespace tut { - struct crc_data - { - }; - typedef test_group<crc_data> crc_test; - typedef crc_test::object crc_object; - tut::crc_test tc("LLCrc"); - - template<> template<> - void crc_object::test<1>() - { - /* Test buffer update and individual char update */ - const char TEST_BUFFER[] = "hello &#$)$&Nd0"; - LLCRC c1, c2; - c1.update((U8*)TEST_BUFFER, sizeof(TEST_BUFFER) - 1); - char* rh = (char*)TEST_BUFFER; - while(*rh != '\0') - { - c2.update(*rh); - ++rh; - } - ensure_equals("crc update 1", c1.getCRC(), c2.getCRC()); - } - - template<> template<> - void crc_object::test<2>() - { - /* Test mixing of buffer and individual char update */ - const char TEST_BUFFER1[] = "Split Buffer one $^%$%#@$"; - const char TEST_BUFFER2[] = "Split Buffer two )(8723#5dsds"; - LLCRC c1, c2; - c1.update((U8*)TEST_BUFFER1, sizeof(TEST_BUFFER1) - 1); - char* rh = (char*)TEST_BUFFER2; - while(*rh != '\0') - { - c1.update(*rh); - ++rh; - } - - rh = (char*)TEST_BUFFER1; - while(*rh != '\0') - { - c2.update(*rh); - ++rh; - } - c2.update((U8*)TEST_BUFFER2, sizeof(TEST_BUFFER2) - 1); - - ensure_equals("crc update 2", c1.getCRC(), c2.getCRC()); - } + struct crc_data + { + }; + typedef test_group<crc_data> crc_test; + typedef crc_test::object crc_object; + tut::crc_test tc("LLCrc"); + + template<> template<> + void crc_object::test<1>() + { + /* Test buffer update and individual char update */ + const char TEST_BUFFER[] = "hello &#$)$&Nd0"; + LLCRC c1, c2; + c1.update((U8*)TEST_BUFFER, sizeof(TEST_BUFFER) - 1); + char* rh = (char*)TEST_BUFFER; + while(*rh != '\0') + { + c2.update(*rh); + ++rh; + } + ensure_equals("crc update 1", c1.getCRC(), c2.getCRC()); + } + + template<> template<> + void crc_object::test<2>() + { + /* Test mixing of buffer and individual char update */ + const char TEST_BUFFER1[] = "Split Buffer one $^%$%#@$"; + const char TEST_BUFFER2[] = "Split Buffer two )(8723#5dsds"; + LLCRC c1, c2; + c1.update((U8*)TEST_BUFFER1, sizeof(TEST_BUFFER1) - 1); + char* rh = (char*)TEST_BUFFER2; + while(*rh != '\0') + { + c1.update(*rh); + ++rh; + } + + rh = (char*)TEST_BUFFER1; + while(*rh != '\0') + { + c2.update(*rh); + ++rh; + } + c2.update((U8*)TEST_BUFFER2, sizeof(TEST_BUFFER2) - 1); + + ensure_equals("crc update 2", c1.getCRC(), c2.getCRC()); + } } namespace tut { - struct sphere_data - { - }; - typedef test_group<sphere_data> sphere_test; - typedef sphere_test::object sphere_object; - tut::sphere_test tsphere("LLSphere"); - - template<> template<> - void sphere_object::test<1>() - { - // test LLSphere::contains() and ::overlaps() - S32 number_of_tests = 10; - for (S32 test = 0; test < number_of_tests; ++test) - { - LLVector3 first_center(1.f, 1.f, 1.f); - F32 first_radius = 3.f; - LLSphere first_sphere( first_center, first_radius ); - - F32 half_millimeter = 0.0005f; - LLVector3 direction( ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f); - direction.normalize(); - - F32 distance = ll_frand(first_radius - 2.f * half_millimeter); - LLVector3 second_center = first_center + distance * direction; - F32 second_radius = first_radius - distance - half_millimeter; - LLSphere second_sphere( second_center, second_radius ); - ensure("first sphere should contain the second", first_sphere.contains(second_sphere)); - ensure("first sphere should overlap the second", first_sphere.overlaps(second_sphere)); - - distance = first_radius + ll_frand(first_radius); - second_center = first_center + distance * direction; - second_radius = distance - first_radius + half_millimeter; - second_sphere.set( second_center, second_radius ); - ensure("first sphere should NOT contain the second", !first_sphere.contains(second_sphere)); - ensure("first sphere should overlap the second", first_sphere.overlaps(second_sphere)); - - distance = first_radius + ll_frand(first_radius) + half_millimeter; - second_center = first_center + distance * direction; - second_radius = distance - first_radius - half_millimeter; - second_sphere.set( second_center, second_radius ); - ensure("first sphere should NOT contain the second", !first_sphere.contains(second_sphere)); - ensure("first sphere should NOT overlap the second", !first_sphere.overlaps(second_sphere)); - } - } - - template<> template<> - void sphere_object::test<2>() - { - skip("See SNOW-620. Neither the test nor the code being tested seem good. Also sim-only."); - - // test LLSphere::getBoundingSphere() - S32 number_of_tests = 100; - S32 number_of_spheres = 10; - F32 sphere_center_range = 32.f; - F32 sphere_radius_range = 5.f; - - for (S32 test = 0; test < number_of_tests; ++test) - { - // gegnerate a bunch of random sphere - std::vector< LLSphere > sphere_list; - for (S32 sphere_count=0; sphere_count < number_of_spheres; ++sphere_count) - { - LLVector3 direction( ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f); - direction.normalize(); - F32 distance = ll_frand(sphere_center_range); - LLVector3 center = distance * direction; - F32 radius = ll_frand(sphere_radius_range); - LLSphere sphere( center, radius ); - sphere_list.push_back(sphere); - } - - // compute the bounding sphere - LLSphere bounding_sphere = LLSphere::getBoundingSphere(sphere_list); - - // make sure all spheres are inside the bounding sphere - { - std::vector< LLSphere >::const_iterator sphere_itr; - for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr) - { - ensure("sphere should be contained by the bounding sphere", bounding_sphere.contains(*sphere_itr)); - } - } - - // TODO -- improve LLSphere::getBoundingSphere() to the point where - // we can reduce the 'expansion' in the two tests below to about - // 2 mm or less - - F32 expansion = 0.005f; - // move all spheres out a little bit - // and count how many are NOT contained - { - std::vector< LLVector3 > uncontained_directions; - std::vector< LLSphere >::iterator sphere_itr; - for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr) - { - LLVector3 direction = sphere_itr->getCenter() - bounding_sphere.getCenter(); - direction.normalize(); - - sphere_itr->setCenter( sphere_itr->getCenter() + expansion * direction ); - if (! bounding_sphere.contains( *sphere_itr ) ) - { - uncontained_directions.push_back(direction); - } - } - ensure("when moving spheres out there should be at least two uncontained spheres", - uncontained_directions.size() > 1); - - /* TODO -- when the bounding sphere algorithm is improved we can open up this test - * at the moment it occasionally fails when the sphere collection is tight and small - * (2 meters or less) - if (2 == uncontained_directions.size() ) - { - // if there were only two uncontained spheres then - // the two directions should be nearly opposite - F32 dir_dot = uncontained_directions[0] * uncontained_directions[1]; - ensure("two uncontained spheres should lie opposite the bounding center", dir_dot < -0.95f); - } - */ - } - - // compute the new bounding sphere - bounding_sphere = LLSphere::getBoundingSphere(sphere_list); - - // increase the size of all spheres a little bit - // and count how many are NOT contained - { - std::vector< LLVector3 > uncontained_directions; - std::vector< LLSphere >::iterator sphere_itr; - for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr) - { - LLVector3 direction = sphere_itr->getCenter() - bounding_sphere.getCenter(); - direction.normalize(); - - sphere_itr->setRadius( sphere_itr->getRadius() + expansion ); - if (! bounding_sphere.contains( *sphere_itr ) ) - { - uncontained_directions.push_back(direction); - } - } - ensure("when boosting sphere radii there should be at least two uncontained spheres", - uncontained_directions.size() > 1); - - /* TODO -- when the bounding sphere algorithm is improved we can open up this test - * at the moment it occasionally fails when the sphere collection is tight and small - * (2 meters or less) - if (2 == uncontained_directions.size() ) - { - // if there were only two uncontained spheres then - // the two directions should be nearly opposite - F32 dir_dot = uncontained_directions[0] * uncontained_directions[1]; - ensure("two uncontained spheres should lie opposite the bounding center", dir_dot < -0.95f); - } - */ - } - } - } + struct sphere_data + { + }; + typedef test_group<sphere_data> sphere_test; + typedef sphere_test::object sphere_object; + tut::sphere_test tsphere("LLSphere"); + + template<> template<> + void sphere_object::test<1>() + { + // test LLSphere::contains() and ::overlaps() + S32 number_of_tests = 10; + for (S32 test = 0; test < number_of_tests; ++test) + { + LLVector3 first_center(1.f, 1.f, 1.f); + F32 first_radius = 3.f; + LLSphere first_sphere( first_center, first_radius ); + + F32 half_millimeter = 0.0005f; + LLVector3 direction( ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f); + direction.normalize(); + + F32 distance = ll_frand(first_radius - 2.f * half_millimeter); + LLVector3 second_center = first_center + distance * direction; + F32 second_radius = first_radius - distance - half_millimeter; + LLSphere second_sphere( second_center, second_radius ); + ensure("first sphere should contain the second", first_sphere.contains(second_sphere)); + ensure("first sphere should overlap the second", first_sphere.overlaps(second_sphere)); + + distance = first_radius + ll_frand(first_radius); + second_center = first_center + distance * direction; + second_radius = distance - first_radius + half_millimeter; + second_sphere.set( second_center, second_radius ); + ensure("first sphere should NOT contain the second", !first_sphere.contains(second_sphere)); + ensure("first sphere should overlap the second", first_sphere.overlaps(second_sphere)); + + distance = first_radius + ll_frand(first_radius) + half_millimeter; + second_center = first_center + distance * direction; + second_radius = distance - first_radius - half_millimeter; + second_sphere.set( second_center, second_radius ); + ensure("first sphere should NOT contain the second", !first_sphere.contains(second_sphere)); + ensure("first sphere should NOT overlap the second", !first_sphere.overlaps(second_sphere)); + } + } + + template<> template<> + void sphere_object::test<2>() + { + skip("See SNOW-620. Neither the test nor the code being tested seem good. Also sim-only."); + + // test LLSphere::getBoundingSphere() + S32 number_of_tests = 100; + S32 number_of_spheres = 10; + F32 sphere_center_range = 32.f; + F32 sphere_radius_range = 5.f; + + for (S32 test = 0; test < number_of_tests; ++test) + { + // gegnerate a bunch of random sphere + std::vector< LLSphere > sphere_list; + for (S32 sphere_count=0; sphere_count < number_of_spheres; ++sphere_count) + { + LLVector3 direction( ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f); + direction.normalize(); + F32 distance = ll_frand(sphere_center_range); + LLVector3 center = distance * direction; + F32 radius = ll_frand(sphere_radius_range); + LLSphere sphere( center, radius ); + sphere_list.push_back(sphere); + } + + // compute the bounding sphere + LLSphere bounding_sphere = LLSphere::getBoundingSphere(sphere_list); + + // make sure all spheres are inside the bounding sphere + { + std::vector< LLSphere >::const_iterator sphere_itr; + for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr) + { + ensure("sphere should be contained by the bounding sphere", bounding_sphere.contains(*sphere_itr)); + } + } + + // TODO -- improve LLSphere::getBoundingSphere() to the point where + // we can reduce the 'expansion' in the two tests below to about + // 2 mm or less + + F32 expansion = 0.005f; + // move all spheres out a little bit + // and count how many are NOT contained + { + std::vector< LLVector3 > uncontained_directions; + std::vector< LLSphere >::iterator sphere_itr; + for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr) + { + LLVector3 direction = sphere_itr->getCenter() - bounding_sphere.getCenter(); + direction.normalize(); + + sphere_itr->setCenter( sphere_itr->getCenter() + expansion * direction ); + if (! bounding_sphere.contains( *sphere_itr ) ) + { + uncontained_directions.push_back(direction); + } + } + ensure("when moving spheres out there should be at least two uncontained spheres", + uncontained_directions.size() > 1); + + /* TODO -- when the bounding sphere algorithm is improved we can open up this test + * at the moment it occasionally fails when the sphere collection is tight and small + * (2 meters or less) + if (2 == uncontained_directions.size() ) + { + // if there were only two uncontained spheres then + // the two directions should be nearly opposite + F32 dir_dot = uncontained_directions[0] * uncontained_directions[1]; + ensure("two uncontained spheres should lie opposite the bounding center", dir_dot < -0.95f); + } + */ + } + + // compute the new bounding sphere + bounding_sphere = LLSphere::getBoundingSphere(sphere_list); + + // increase the size of all spheres a little bit + // and count how many are NOT contained + { + std::vector< LLVector3 > uncontained_directions; + std::vector< LLSphere >::iterator sphere_itr; + for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr) + { + LLVector3 direction = sphere_itr->getCenter() - bounding_sphere.getCenter(); + direction.normalize(); + + sphere_itr->setRadius( sphere_itr->getRadius() + expansion ); + if (! bounding_sphere.contains( *sphere_itr ) ) + { + uncontained_directions.push_back(direction); + } + } + ensure("when boosting sphere radii there should be at least two uncontained spheres", + uncontained_directions.size() > 1); + + /* TODO -- when the bounding sphere algorithm is improved we can open up this test + * at the moment it occasionally fails when the sphere collection is tight and small + * (2 meters or less) + if (2 == uncontained_directions.size() ) + { + // if there were only two uncontained spheres then + // the two directions should be nearly opposite + F32 dir_dot = uncontained_directions[0] * uncontained_directions[1]; + ensure("two uncontained spheres should lie opposite the bounding center", dir_dot < -0.95f); + } + */ + } + } + } } namespace tut { - F32 SMALL_RADIUS = 1.0f; - F32 MEDIUM_RADIUS = 5.0f; - F32 LARGE_RADIUS = 10.0f; - - struct line_data - { - }; - typedef test_group<line_data> line_test; - typedef line_test::object line_object; - tut::line_test tline("LLLine"); - - template<> template<> - void line_object::test<1>() - { - // this is a test for LLLine::intersects(point) which returns TRUE - // if the line passes within some tolerance of point - - // these tests will have some floating point error, - // so we need to specify how much error is ok - F32 allowable_relative_error = 0.00001f; - S32 number_of_tests = 100; - for (S32 test = 0; test < number_of_tests; ++test) - { - // generate some random point to be on the line - LLVector3 point_on_line( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - point_on_line.normalize(); - point_on_line *= ll_frand(LARGE_RADIUS); - - // generate some random point to "intersect" - LLVector3 random_direction ( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - random_direction.normalize(); - - LLVector3 random_offset( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - random_offset.normalize(); - random_offset *= ll_frand(SMALL_RADIUS); - - LLVector3 point = point_on_line + MEDIUM_RADIUS * random_direction - + random_offset; - - // compute the axis of approach (a unit vector between the points) - LLVector3 axis_of_approach = point - point_on_line; - axis_of_approach.normalize(); - - // compute the direction of the the first line (perp to axis_of_approach) - LLVector3 first_dir( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - first_dir.normalize(); - F32 dot = first_dir * axis_of_approach; - first_dir -= dot * axis_of_approach; // subtract component parallel to axis - first_dir.normalize(); - - // construct the line - LLVector3 another_point_on_line = point_on_line + ll_frand(LARGE_RADIUS) * first_dir; - LLLine line(another_point_on_line, point_on_line); - - // test that the intersection point is within MEDIUM_RADIUS + SMALL_RADIUS - F32 test_radius = MEDIUM_RADIUS + SMALL_RADIUS; - test_radius += (LARGE_RADIUS * allowable_relative_error); - ensure("line should pass near intersection point", line.intersects(point, test_radius)); - - test_radius = allowable_relative_error * (point - point_on_line).length(); - ensure("line should intersect point used to define it", line.intersects(point_on_line, test_radius)); - } - } - - template<> template<> - void line_object::test<2>() - { + F32 SMALL_RADIUS = 1.0f; + F32 MEDIUM_RADIUS = 5.0f; + F32 LARGE_RADIUS = 10.0f; + + struct line_data + { + }; + typedef test_group<line_data> line_test; + typedef line_test::object line_object; + tut::line_test tline("LLLine"); + + template<> template<> + void line_object::test<1>() + { + // this is a test for LLLine::intersects(point) which returns TRUE + // if the line passes within some tolerance of point + + // these tests will have some floating point error, + // so we need to specify how much error is ok + F32 allowable_relative_error = 0.00001f; + S32 number_of_tests = 100; + for (S32 test = 0; test < number_of_tests; ++test) + { + // generate some random point to be on the line + LLVector3 point_on_line( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + point_on_line.normalize(); + point_on_line *= ll_frand(LARGE_RADIUS); + + // generate some random point to "intersect" + LLVector3 random_direction ( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + random_direction.normalize(); + + LLVector3 random_offset( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + random_offset.normalize(); + random_offset *= ll_frand(SMALL_RADIUS); + + LLVector3 point = point_on_line + MEDIUM_RADIUS * random_direction + + random_offset; + + // compute the axis of approach (a unit vector between the points) + LLVector3 axis_of_approach = point - point_on_line; + axis_of_approach.normalize(); + + // compute the direction of the the first line (perp to axis_of_approach) + LLVector3 first_dir( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + first_dir.normalize(); + F32 dot = first_dir * axis_of_approach; + first_dir -= dot * axis_of_approach; // subtract component parallel to axis + first_dir.normalize(); + + // construct the line + LLVector3 another_point_on_line = point_on_line + ll_frand(LARGE_RADIUS) * first_dir; + LLLine line(another_point_on_line, point_on_line); + + // test that the intersection point is within MEDIUM_RADIUS + SMALL_RADIUS + F32 test_radius = MEDIUM_RADIUS + SMALL_RADIUS; + test_radius += (LARGE_RADIUS * allowable_relative_error); + ensure("line should pass near intersection point", line.intersects(point, test_radius)); + + test_radius = allowable_relative_error * (point - point_on_line).length(); + ensure("line should intersect point used to define it", line.intersects(point_on_line, test_radius)); + } + } + + template<> template<> + void line_object::test<2>() + { /* These tests fail intermittently on all platforms - see DEV-16600 Commenting this out until dev has time to investigate. - - // this is a test for LLLine::nearestApproach(LLLIne) method - // which computes the point on a line nearest another line - - // these tests will have some floating point error, - // so we need to specify how much error is ok - // TODO -- make nearestApproach() algorithm more accurate so - // we can tighten the allowable_error. Most tests are tighter - // than one milimeter, however when doing randomized testing - // you can walk into inaccurate cases. - F32 allowable_relative_error = 0.001f; - S32 number_of_tests = 100; - for (S32 test = 0; test < number_of_tests; ++test) - { - // generate two points to be our known nearest approaches - LLVector3 some_point( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - some_point.normalize(); - some_point *= ll_frand(LARGE_RADIUS); - - LLVector3 another_point( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - another_point.normalize(); - another_point *= ll_frand(LARGE_RADIUS); - - // compute the axis of approach (a unit vector between the points) - LLVector3 axis_of_approach = another_point - some_point; - axis_of_approach.normalize(); - - // compute the direction of the the first line (perp to axis_of_approach) - LLVector3 first_dir( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - F32 dot = first_dir * axis_of_approach; - first_dir -= dot * axis_of_approach; // subtract component parallel to axis - first_dir.normalize(); // normalize - - // compute the direction of the the second line - LLVector3 second_dir( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - dot = second_dir * axis_of_approach; - second_dir -= dot * axis_of_approach; - second_dir.normalize(); - - // make sure the lines aren't too parallel, - dot = fabsf(first_dir * second_dir); - if (dot > 0.99f) - { - // skip this test, we're not interested in testing - // the intractible cases - continue; - } - - // construct the lines - LLVector3 first_point = some_point + ll_frand(LARGE_RADIUS) * first_dir; - LLLine first_line(first_point, some_point); - - LLVector3 second_point = another_point + ll_frand(LARGE_RADIUS) * second_dir; - LLLine second_line(second_point, another_point); - - // compute the points of nearest approach - LLVector3 some_computed_point = first_line.nearestApproach(second_line); - LLVector3 another_computed_point = second_line.nearestApproach(first_line); - - // compute the error - F32 first_error = (some_point - some_computed_point).length(); - F32 scale = llmax((some_point - another_point).length(), some_point.length()); - scale = llmax(scale, another_point.length()); - scale = llmax(scale, 1.f); - F32 first_relative_error = first_error / scale; - - F32 second_error = (another_point - another_computed_point).length(); - F32 second_relative_error = second_error / scale; - - //if (first_relative_error > allowable_relative_error) - //{ - // std::cout << "first_error = " << first_error - // << " first_relative_error = " << first_relative_error - // << " scale = " << scale - // << " dir_dot = " << (first_dir * second_dir) - // << std::endl; - //} - //if (second_relative_error > allowable_relative_error) - //{ - // std::cout << "second_error = " << second_error - // << " second_relative_error = " << second_relative_error - // << " scale = " << scale - // << " dist = " << (some_point - another_point).length() - // << " dir_dot = " << (first_dir * second_dir) - // << std::endl; - //} - - // test that the errors are small - - ensure("first line should accurately compute its closest approach", - first_relative_error <= allowable_relative_error); - ensure("second line should accurately compute its closest approach", - second_relative_error <= allowable_relative_error); - } + + // this is a test for LLLine::nearestApproach(LLLIne) method + // which computes the point on a line nearest another line + + // these tests will have some floating point error, + // so we need to specify how much error is ok + // TODO -- make nearestApproach() algorithm more accurate so + // we can tighten the allowable_error. Most tests are tighter + // than one milimeter, however when doing randomized testing + // you can walk into inaccurate cases. + F32 allowable_relative_error = 0.001f; + S32 number_of_tests = 100; + for (S32 test = 0; test < number_of_tests; ++test) + { + // generate two points to be our known nearest approaches + LLVector3 some_point( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + some_point.normalize(); + some_point *= ll_frand(LARGE_RADIUS); + + LLVector3 another_point( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + another_point.normalize(); + another_point *= ll_frand(LARGE_RADIUS); + + // compute the axis of approach (a unit vector between the points) + LLVector3 axis_of_approach = another_point - some_point; + axis_of_approach.normalize(); + + // compute the direction of the the first line (perp to axis_of_approach) + LLVector3 first_dir( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + F32 dot = first_dir * axis_of_approach; + first_dir -= dot * axis_of_approach; // subtract component parallel to axis + first_dir.normalize(); // normalize + + // compute the direction of the the second line + LLVector3 second_dir( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + dot = second_dir * axis_of_approach; + second_dir -= dot * axis_of_approach; + second_dir.normalize(); + + // make sure the lines aren't too parallel, + dot = fabsf(first_dir * second_dir); + if (dot > 0.99f) + { + // skip this test, we're not interested in testing + // the intractible cases + continue; + } + + // construct the lines + LLVector3 first_point = some_point + ll_frand(LARGE_RADIUS) * first_dir; + LLLine first_line(first_point, some_point); + + LLVector3 second_point = another_point + ll_frand(LARGE_RADIUS) * second_dir; + LLLine second_line(second_point, another_point); + + // compute the points of nearest approach + LLVector3 some_computed_point = first_line.nearestApproach(second_line); + LLVector3 another_computed_point = second_line.nearestApproach(first_line); + + // compute the error + F32 first_error = (some_point - some_computed_point).length(); + F32 scale = llmax((some_point - another_point).length(), some_point.length()); + scale = llmax(scale, another_point.length()); + scale = llmax(scale, 1.f); + F32 first_relative_error = first_error / scale; + + F32 second_error = (another_point - another_computed_point).length(); + F32 second_relative_error = second_error / scale; + + //if (first_relative_error > allowable_relative_error) + //{ + // std::cout << "first_error = " << first_error + // << " first_relative_error = " << first_relative_error + // << " scale = " << scale + // << " dir_dot = " << (first_dir * second_dir) + // << std::endl; + //} + //if (second_relative_error > allowable_relative_error) + //{ + // std::cout << "second_error = " << second_error + // << " second_relative_error = " << second_relative_error + // << " scale = " << scale + // << " dist = " << (some_point - another_point).length() + // << " dir_dot = " << (first_dir * second_dir) + // << std::endl; + //} + + // test that the errors are small + + ensure("first line should accurately compute its closest approach", + first_relative_error <= allowable_relative_error); + ensure("second line should accurately compute its closest approach", + second_relative_error <= allowable_relative_error); + } */ - } - - F32 ALMOST_PARALLEL = 0.99f; - template<> template<> - void line_object::test<3>() - { - // this is a test for LLLine::getIntersectionBetweenTwoPlanes() method - - // first some known tests - LLLine xy_plane(LLVector3(0.f, 0.f, 2.f), LLVector3(0.f, 0.f, 3.f)); - LLLine yz_plane(LLVector3(2.f, 0.f, 0.f), LLVector3(3.f, 0.f, 0.f)); - LLLine zx_plane(LLVector3(0.f, 2.f, 0.f), LLVector3(0.f, 3.f, 0.f)); - - LLLine x_line; - LLLine y_line; - LLLine z_line; - - bool x_success = LLLine::getIntersectionBetweenTwoPlanes(x_line, xy_plane, zx_plane); - bool y_success = LLLine::getIntersectionBetweenTwoPlanes(y_line, yz_plane, xy_plane); - bool z_success = LLLine::getIntersectionBetweenTwoPlanes(z_line, zx_plane, yz_plane); - - ensure("xy and zx planes should intersect", x_success); - ensure("yz and xy planes should intersect", y_success); - ensure("zx and yz planes should intersect", z_success); - - LLVector3 direction = x_line.getDirection(); - ensure("x_line should be parallel to x_axis", fabs(direction.mV[VX]) == 1.f - && 0.f == direction.mV[VY] - && 0.f == direction.mV[VZ] ); - direction = y_line.getDirection(); - ensure("y_line should be parallel to y_axis", 0.f == direction.mV[VX] - && fabs(direction.mV[VY]) == 1.f - && 0.f == direction.mV[VZ] ); - direction = z_line.getDirection(); - ensure("z_line should be parallel to z_axis", 0.f == direction.mV[VX] - && 0.f == direction.mV[VY] - && fabs(direction.mV[VZ]) == 1.f ); - - // next some random tests - F32 allowable_relative_error = 0.0001f; - S32 number_of_tests = 20; - for (S32 test = 0; test < number_of_tests; ++test) - { - // generate the known line - LLVector3 some_point( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - some_point.normalize(); - some_point *= ll_frand(LARGE_RADIUS); - LLVector3 another_point( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - another_point.normalize(); - another_point *= ll_frand(LARGE_RADIUS); - LLLine known_intersection(some_point, another_point); - - // compute a plane that intersect the line - LLVector3 point_on_plane( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - point_on_plane.normalize(); - point_on_plane *= ll_frand(LARGE_RADIUS); - LLVector3 plane_normal = (point_on_plane - some_point) % known_intersection.getDirection(); - plane_normal.normalize(); - LLLine first_plane(point_on_plane, point_on_plane + plane_normal); - - // compute a different plane that intersect the line - LLVector3 point_on_different_plane( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - point_on_different_plane.normalize(); - point_on_different_plane *= ll_frand(LARGE_RADIUS); - LLVector3 different_plane_normal = (point_on_different_plane - another_point) % known_intersection.getDirection(); - different_plane_normal.normalize(); - LLLine second_plane(point_on_different_plane, point_on_different_plane + different_plane_normal); - - if (fabs(plane_normal * different_plane_normal) > ALMOST_PARALLEL) - { - // the two planes are approximately parallel, so we won't test this case - continue; - } - - LLLine measured_intersection; - bool success = LLLine::getIntersectionBetweenTwoPlanes( - measured_intersection, - first_plane, - second_plane); - - ensure("plane intersection should succeed", success); - - F32 dot = fabs(known_intersection.getDirection() * measured_intersection.getDirection()); - ensure("measured intersection should be parallel to known intersection", - dot > ALMOST_PARALLEL); - - ensure("measured intersection should pass near known point", - measured_intersection.intersects(some_point, LARGE_RADIUS * allowable_relative_error)); - } - } + } + + F32 ALMOST_PARALLEL = 0.99f; + template<> template<> + void line_object::test<3>() + { + // this is a test for LLLine::getIntersectionBetweenTwoPlanes() method + + // first some known tests + LLLine xy_plane(LLVector3(0.f, 0.f, 2.f), LLVector3(0.f, 0.f, 3.f)); + LLLine yz_plane(LLVector3(2.f, 0.f, 0.f), LLVector3(3.f, 0.f, 0.f)); + LLLine zx_plane(LLVector3(0.f, 2.f, 0.f), LLVector3(0.f, 3.f, 0.f)); + + LLLine x_line; + LLLine y_line; + LLLine z_line; + + bool x_success = LLLine::getIntersectionBetweenTwoPlanes(x_line, xy_plane, zx_plane); + bool y_success = LLLine::getIntersectionBetweenTwoPlanes(y_line, yz_plane, xy_plane); + bool z_success = LLLine::getIntersectionBetweenTwoPlanes(z_line, zx_plane, yz_plane); + + ensure("xy and zx planes should intersect", x_success); + ensure("yz and xy planes should intersect", y_success); + ensure("zx and yz planes should intersect", z_success); + + LLVector3 direction = x_line.getDirection(); + ensure("x_line should be parallel to x_axis", fabs(direction.mV[VX]) == 1.f + && 0.f == direction.mV[VY] + && 0.f == direction.mV[VZ] ); + direction = y_line.getDirection(); + ensure("y_line should be parallel to y_axis", 0.f == direction.mV[VX] + && fabs(direction.mV[VY]) == 1.f + && 0.f == direction.mV[VZ] ); + direction = z_line.getDirection(); + ensure("z_line should be parallel to z_axis", 0.f == direction.mV[VX] + && 0.f == direction.mV[VY] + && fabs(direction.mV[VZ]) == 1.f ); + + // next some random tests + F32 allowable_relative_error = 0.0001f; + S32 number_of_tests = 20; + for (S32 test = 0; test < number_of_tests; ++test) + { + // generate the known line + LLVector3 some_point( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + some_point.normalize(); + some_point *= ll_frand(LARGE_RADIUS); + LLVector3 another_point( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + another_point.normalize(); + another_point *= ll_frand(LARGE_RADIUS); + LLLine known_intersection(some_point, another_point); + + // compute a plane that intersect the line + LLVector3 point_on_plane( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + point_on_plane.normalize(); + point_on_plane *= ll_frand(LARGE_RADIUS); + LLVector3 plane_normal = (point_on_plane - some_point) % known_intersection.getDirection(); + plane_normal.normalize(); + LLLine first_plane(point_on_plane, point_on_plane + plane_normal); + + // compute a different plane that intersect the line + LLVector3 point_on_different_plane( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + point_on_different_plane.normalize(); + point_on_different_plane *= ll_frand(LARGE_RADIUS); + LLVector3 different_plane_normal = (point_on_different_plane - another_point) % known_intersection.getDirection(); + different_plane_normal.normalize(); + LLLine second_plane(point_on_different_plane, point_on_different_plane + different_plane_normal); + + if (fabs(plane_normal * different_plane_normal) > ALMOST_PARALLEL) + { + // the two planes are approximately parallel, so we won't test this case + continue; + } + + LLLine measured_intersection; + bool success = LLLine::getIntersectionBetweenTwoPlanes( + measured_intersection, + first_plane, + second_plane); + + ensure("plane intersection should succeed", success); + + F32 dot = fabs(known_intersection.getDirection() * measured_intersection.getDirection()); + ensure("measured intersection should be parallel to known intersection", + dot > ALMOST_PARALLEL); + + ensure("measured intersection should pass near known point", + measured_intersection.intersects(some_point, LARGE_RADIUS * allowable_relative_error)); + } + } } |