mathmisc_test.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:23k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file math.cpp
  3.  * @author Phoenix
  4.  * @date 2005-09-26
  5.  * @brief Tests for the llmath library.
  6.  *
  7.  * $LicenseInfo:firstyear=2005&license=viewergpl$
  8.  * 
  9.  * Copyright (c) 2005-2010, Linden Research, Inc.
  10.  * 
  11.  * Second Life Viewer Source Code
  12.  * The source code in this file ("Source Code") is provided by Linden Lab
  13.  * to you under the terms of the GNU General Public License, version 2.0
  14.  * ("GPL"), unless you have obtained a separate licensing agreement
  15.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  16.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  17.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  18.  * 
  19.  * There are special exceptions to the terms and conditions of the GPL as
  20.  * it is applied to this Source Code. View the full text of the exception
  21.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  22.  * online at
  23.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  24.  * 
  25.  * By copying, modifying or distributing this software, you acknowledge
  26.  * that you have read and understood your obligations described above,
  27.  * and agree to abide by those obligations.
  28.  * 
  29.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  30.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  31.  * COMPLETENESS OR PERFORMANCE.
  32.  * $/LicenseInfo$
  33.  */
  34. #include "linden_common.h"
  35. #include "../test/lltut.h"
  36. #include "llcrc.h"
  37. #include "llrand.h"
  38. #include "lluuid.h"
  39. #include "../llline.h"
  40. #include "../llmath.h"
  41. #include "../llsphere.h"
  42. #include "../v3math.h"
  43. namespace tut
  44. {
  45. struct math_data
  46. {
  47. };
  48. typedef test_group<math_data> math_test;
  49. typedef math_test::object math_object;
  50. tut::math_test tm("basic_linden_math");
  51. template<> template<>
  52. void math_object::test<1>()
  53. {
  54. S32 val = 89543;
  55. val = llabs(val);
  56. ensure("integer absolute value 1", (89543 == val));
  57. val = -500;
  58. val = llabs(val);
  59. ensure("integer absolute value 2", (500 == val));
  60. }
  61. template<> template<>
  62. void math_object::test<2>()
  63. {
  64. F32 val = -2583.4f;
  65. val = llabs(val);
  66. ensure("float absolute value 1", (2583.4f == val));
  67. val = 430903.f;
  68. val = llabs(val);
  69. ensure("float absolute value 2", (430903.f == val));
  70. }
  71. template<> template<>
  72. void math_object::test<3>()
  73. {
  74. F64 val = 387439393.987329839;
  75. val = llabs(val);
  76. ensure("double absolute value 1", (387439393.987329839 == val));
  77. val = -8937843.9394878;
  78. val = llabs(val);
  79. ensure("double absolute value 2", (8937843.9394878 == val));
  80. }
  81. template<> template<>
  82. void math_object::test<4>()
  83. {
  84. F32 val = 430903.9f;
  85. S32 val1 = lltrunc(val);
  86. ensure("float truncate value 1", (430903 == val1));
  87. val = -2303.9f;
  88. val1 = lltrunc(val);
  89. ensure("float truncate value 2", (-2303  == val1));
  90. }
  91. template<> template<>
  92. void math_object::test<5>()
  93. {
  94. F64 val = 387439393.987329839 ;
  95. S32 val1 = lltrunc(val);
  96. ensure("float truncate value 1", (387439393 == val1));
  97. val = -387439393.987329839;
  98. val1 = lltrunc(val);
  99. ensure("float truncate value 2", (-387439393  == val1));
  100. }
  101. template<> template<>
  102. void math_object::test<6>()
  103. {
  104. F32 val = 430903.2f;
  105. S32 val1 = llfloor(val);
  106. ensure("float llfloor value 1", (430903 == val1));
  107. val = -430903.9f;
  108. val1 = llfloor(val);
  109. ensure("float llfloor value 2", (-430904 == val1));
  110. }
  111. template<> template<>
  112. void math_object::test<7>()
  113. {
  114. F32 val = 430903.2f;
  115. S32 val1 = llceil(val);
  116. ensure("float llceil value 1", (430904 == val1));
  117. val = -430903.9f;
  118. val1 = llceil(val);
  119. ensure("float llceil value 2", (-430903 == val1));
  120. }
  121. template<> template<>
  122. void math_object::test<8>()
  123. {
  124. F32 val = 430903.2f;
  125. S32 val1 = llround(val);
  126. ensure("float llround value 1", (430903 == val1));
  127. val = -430903.9f;
  128. val1 = llround(val);
  129. ensure("float llround value 2", (-430904 == val1));
  130. }
  131. template<> template<>
  132. void math_object::test<9>()
  133. {
  134. F32 val = 430905.2654f, nearest = 100.f;
  135. val = llround(val, nearest);
  136. ensure("float llround value 1", (430900 == val));
  137. val = -430905.2654f, nearest = 10.f;
  138. val = llround(val, nearest);
  139. ensure("float llround value 1", (-430910 == val));
  140. }
  141. template<> template<>
  142. void math_object::test<10>()
  143. {
  144. F64 val = 430905.2654, nearest = 100.0;
  145. val = llround(val, nearest);
  146. ensure("double llround value 1", (430900 == val));
  147. val = -430905.2654, nearest = 10.0;
  148. val = llround(val, nearest);
  149. ensure("double llround value 1", (-430910.00000 == val));
  150. }
  151. template<> template<>
  152. void math_object::test<11>()
  153. {
  154. const F32 F_PI = 3.1415926535897932384626433832795f;
  155. F32 angle = 3506.f;
  156. angle =  llsimple_angle(angle);
  157. ensure("llsimple_angle  value 1", (angle <=F_PI && angle >= -F_PI));
  158. angle = -431.f;
  159. angle =  llsimple_angle(angle);
  160. ensure("llsimple_angle  value 1", (angle <=F_PI && angle >= -F_PI));
  161. }
  162. }
  163. namespace tut
  164. {
  165. struct uuid_data
  166. {
  167. LLUUID id;
  168. };
  169. typedef test_group<uuid_data> uuid_test;
  170. typedef uuid_test::object uuid_object;
  171. tut::uuid_test tu("uuid");
  172. template<> template<>
  173. void uuid_object::test<1>()
  174. {
  175. ensure("uuid null", id.isNull());
  176. id.generate();
  177. ensure("generate not null", id.notNull());
  178. id.setNull();
  179. ensure("set null", id.isNull());
  180. }
  181. template<> template<>
  182. void uuid_object::test<2>()
  183. {
  184. id.generate();
  185. LLUUID a(id);
  186. ensure_equals("copy equal", id, a);
  187. a.generate();
  188. ensure_not_equals("generate not equal", id, a);
  189. a = id;
  190. ensure_equals("assignment equal", id, a);
  191. }
  192. template<> template<>
  193. void uuid_object::test<3>()
  194. {
  195. id.generate();
  196. LLUUID copy(id);
  197. LLUUID mask;
  198. mask.generate();
  199. copy ^= mask;
  200. ensure_not_equals("mask not equal", id, copy);
  201. copy ^= mask;
  202. ensure_equals("mask back", id, copy);
  203. }
  204. template<> template<>
  205. void uuid_object::test<4>()
  206. {
  207. id.generate();
  208. std::string id_str = id.asString();
  209. LLUUID copy(id_str.c_str());
  210. ensure_equals("string serialization", id, copy);
  211. }
  212. }
  213. namespace tut
  214. {
  215. struct crc_data
  216. {
  217. };
  218. typedef test_group<crc_data> crc_test;
  219. typedef crc_test::object crc_object;
  220. tut::crc_test tc("crc");
  221. template<> template<>
  222. void crc_object::test<1>()
  223. {
  224. /* Test buffer update and individual char update */
  225. const char TEST_BUFFER[] = "hello &#$)$&Nd0";
  226. LLCRC c1, c2;
  227. c1.update((U8*)TEST_BUFFER, sizeof(TEST_BUFFER) - 1);
  228. char* rh = (char*)TEST_BUFFER;
  229. while(*rh != '')
  230. {
  231. c2.update(*rh);
  232. ++rh;
  233. }
  234. ensure_equals("crc update 1", c1.getCRC(), c2.getCRC());
  235. }
  236. template<> template<>
  237. void crc_object::test<2>()
  238. {
  239. /* Test mixing of buffer and individual char update */
  240. const char TEST_BUFFER1[] = "Split Buffer one $^%$%#@$";
  241. const char TEST_BUFFER2[] = "Split Buffer two )(8723#5dsds";
  242. LLCRC c1, c2;
  243. c1.update((U8*)TEST_BUFFER1, sizeof(TEST_BUFFER1) - 1);
  244. char* rh = (char*)TEST_BUFFER2;
  245. while(*rh != '')
  246. {
  247. c1.update(*rh);
  248. ++rh;
  249. }
  250. rh = (char*)TEST_BUFFER1;
  251. while(*rh != '')
  252. {
  253. c2.update(*rh);
  254. ++rh;
  255. }
  256. c2.update((U8*)TEST_BUFFER2, sizeof(TEST_BUFFER2) - 1);
  257. ensure_equals("crc update 2", c1.getCRC(), c2.getCRC());
  258. }
  259. }
  260. namespace tut
  261. {
  262. struct sphere_data
  263. {
  264. };
  265. typedef test_group<sphere_data> sphere_test;
  266. typedef sphere_test::object sphere_object;
  267. tut::sphere_test tsphere("LLSphere");
  268. template<> template<>
  269. void sphere_object::test<1>()
  270. {
  271. // test LLSphere::contains() and ::overlaps()
  272. S32 number_of_tests = 10;
  273. for (S32 test = 0; test < number_of_tests; ++test)
  274. {
  275. LLVector3 first_center(1.f, 1.f, 1.f);
  276. F32 first_radius = 3.f;
  277. LLSphere first_sphere( first_center, first_radius );
  278. F32 half_millimeter = 0.0005f;
  279. LLVector3 direction( ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f);
  280. direction.normalize();
  281. F32 distance = ll_frand(first_radius - 2.f * half_millimeter);
  282. LLVector3 second_center = first_center + distance * direction;
  283. F32 second_radius = first_radius - distance - half_millimeter;
  284. LLSphere second_sphere( second_center, second_radius );
  285. ensure("first sphere should contain the second", first_sphere.contains(second_sphere));
  286. ensure("first sphere should overlap the second", first_sphere.overlaps(second_sphere));
  287. distance = first_radius + ll_frand(first_radius);
  288. second_center = first_center + distance * direction;
  289. second_radius = distance - first_radius + half_millimeter;
  290. second_sphere.set( second_center, second_radius );
  291. ensure("first sphere should NOT contain the second", !first_sphere.contains(second_sphere));
  292. ensure("first sphere should overlap the second", first_sphere.overlaps(second_sphere));
  293. distance = first_radius + ll_frand(first_radius) + half_millimeter;
  294. second_center = first_center + distance * direction;
  295. second_radius = distance - first_radius - half_millimeter;
  296. second_sphere.set( second_center, second_radius );
  297. ensure("first sphere should NOT contain the second", !first_sphere.contains(second_sphere));
  298. ensure("first sphere should NOT overlap the second", !first_sphere.overlaps(second_sphere));
  299. }
  300. }
  301. template<> template<>
  302. void sphere_object::test<2>()
  303. {
  304. // test LLSphere::getBoundingSphere()
  305. S32 number_of_tests = 100;
  306. S32 number_of_spheres = 10;
  307. F32 sphere_center_range = 32.f;
  308. F32 sphere_radius_range = 5.f;
  309. for (S32 test = 0; test < number_of_tests; ++test)
  310. {
  311. // gegnerate a bunch of random sphere
  312. std::vector< LLSphere > sphere_list;
  313. for (S32 sphere_count=0; sphere_count < number_of_spheres; ++sphere_count)
  314. {
  315. LLVector3 direction( ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f);
  316. direction.normalize();
  317. F32 distance = ll_frand(sphere_center_range);
  318. LLVector3 center = distance * direction;
  319. F32 radius = ll_frand(sphere_radius_range);
  320. LLSphere sphere( center, radius );
  321. sphere_list.push_back(sphere);
  322. }
  323. // compute the bounding sphere
  324. LLSphere bounding_sphere = LLSphere::getBoundingSphere(sphere_list);
  325. // make sure all spheres are inside the bounding sphere
  326. {
  327. std::vector< LLSphere >::const_iterator sphere_itr;
  328. for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr)
  329. {
  330. ensure("sphere should be contained by the bounding sphere", bounding_sphere.contains(*sphere_itr));
  331. }
  332. }
  333. // TODO -- improve LLSphere::getBoundingSphere() to the point where
  334. // we can reduce the 'expansion' in the two tests below to about 
  335. // 2 mm or less
  336. F32 expansion = 0.005f;
  337. // move all spheres out a little bit 
  338. // and count how many are NOT contained
  339. {
  340. std::vector< LLVector3 > uncontained_directions;
  341. std::vector< LLSphere >::iterator sphere_itr;
  342. for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr)
  343. {
  344. LLVector3 direction = sphere_itr->getCenter() - bounding_sphere.getCenter();
  345. direction.normalize();
  346. sphere_itr->setCenter( sphere_itr->getCenter() + expansion * direction );
  347. if (! bounding_sphere.contains( *sphere_itr ) )
  348. {
  349. uncontained_directions.push_back(direction);
  350. }
  351. }
  352. ensure("when moving spheres out there should be at least two uncontained spheres", 
  353. uncontained_directions.size() > 1);
  354. /* TODO -- when the bounding sphere algorithm is improved we can open up this test
  355.  * at the moment it occasionally fails when the sphere collection is tight and small
  356.  * (2 meters or less)
  357. if (2 == uncontained_directions.size() )
  358. {
  359. // if there were only two uncontained spheres then
  360. // the two directions should be nearly opposite
  361. F32 dir_dot = uncontained_directions[0] * uncontained_directions[1];
  362. ensure("two uncontained spheres should lie opposite the bounding center", dir_dot < -0.95f);
  363. }
  364. */
  365. }
  366. // compute the new bounding sphere
  367. bounding_sphere = LLSphere::getBoundingSphere(sphere_list);
  368. // increase the size of all spheres a little bit
  369. // and count how many are NOT contained
  370. {
  371. std::vector< LLVector3 > uncontained_directions;
  372. std::vector< LLSphere >::iterator sphere_itr;
  373. for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr)
  374. {
  375. LLVector3 direction = sphere_itr->getCenter() - bounding_sphere.getCenter();
  376. direction.normalize();
  377. sphere_itr->setRadius( sphere_itr->getRadius() + expansion );
  378. if (! bounding_sphere.contains( *sphere_itr ) )
  379. {
  380. uncontained_directions.push_back(direction);
  381. }
  382. }
  383. ensure("when boosting sphere radii there should be at least two uncontained spheres", 
  384. uncontained_directions.size() > 1);
  385. /* TODO -- when the bounding sphere algorithm is improved we can open up this test
  386.  * at the moment it occasionally fails when the sphere collection is tight and small
  387.  * (2 meters or less)
  388. if (2 == uncontained_directions.size() )
  389. {
  390. // if there were only two uncontained spheres then
  391. // the two directions should be nearly opposite
  392. F32 dir_dot = uncontained_directions[0] * uncontained_directions[1];
  393. ensure("two uncontained spheres should lie opposite the bounding center", dir_dot < -0.95f);
  394. }
  395. */
  396. }
  397. }
  398. }
  399. }
  400. namespace tut
  401. {
  402. F32 SMALL_RADIUS = 1.0f;
  403. F32 MEDIUM_RADIUS = 5.0f;
  404. F32 LARGE_RADIUS = 10.0f;
  405. struct line_data
  406. {
  407. };
  408. typedef test_group<line_data> line_test;
  409. typedef line_test::object line_object;
  410. tut::line_test tline("LLLine");
  411. template<> template<>
  412. void line_object::test<1>()
  413. {
  414. // this is a test for LLLine::intersects(point) which returns TRUE 
  415. // if the line passes within some tolerance of point
  416. // these tests will have some floating point error, 
  417. // so we need to specify how much error is ok
  418. F32 allowable_relative_error = 0.00001f;
  419. S32 number_of_tests = 100;
  420. for (S32 test = 0; test < number_of_tests; ++test)
  421. {
  422. // generate some random point to be on the line
  423. LLVector3 point_on_line( ll_frand(2.f) - 1.f, 
  424.      ll_frand(2.f) - 1.f, 
  425.      ll_frand(2.f) - 1.f);
  426. point_on_line.normalize();
  427. point_on_line *= ll_frand(LARGE_RADIUS);
  428. // generate some random point to "intersect"
  429. LLVector3 random_direction ( ll_frand(2.f) - 1.f, 
  430.      ll_frand(2.f) - 1.f, 
  431.      ll_frand(2.f) - 1.f);
  432. random_direction.normalize();
  433. LLVector3 random_offset( ll_frand(2.f) - 1.f, 
  434.      ll_frand(2.f) - 1.f, 
  435.      ll_frand(2.f) - 1.f);
  436. random_offset.normalize();
  437. random_offset *= ll_frand(SMALL_RADIUS);
  438. LLVector3 point = point_on_line + MEDIUM_RADIUS * random_direction
  439. + random_offset;
  440. // compute the axis of approach (a unit vector between the points)
  441. LLVector3 axis_of_approach = point - point_on_line;
  442. axis_of_approach.normalize();
  443. // compute the direction of the the first line (perp to axis_of_approach)
  444. LLVector3 first_dir( ll_frand(2.f) - 1.f, 
  445.      ll_frand(2.f) - 1.f, 
  446.      ll_frand(2.f) - 1.f);
  447. first_dir.normalize();
  448. F32 dot = first_dir * axis_of_approach;
  449. first_dir -= dot * axis_of_approach; // subtract component parallel to axis
  450. first_dir.normalize();
  451. // construct the line
  452. LLVector3 another_point_on_line = point_on_line + ll_frand(LARGE_RADIUS) * first_dir;
  453. LLLine line(another_point_on_line, point_on_line);
  454. // test that the intersection point is within MEDIUM_RADIUS + SMALL_RADIUS
  455. F32 test_radius = MEDIUM_RADIUS + SMALL_RADIUS;
  456. test_radius += (LARGE_RADIUS * allowable_relative_error);
  457. ensure("line should pass near intersection point", line.intersects(point, test_radius));
  458. test_radius = allowable_relative_error * (point - point_on_line).length();
  459. ensure("line should intersect point used to define it", line.intersects(point_on_line, test_radius));
  460. }
  461. }
  462. template<> template<>
  463. void line_object::test<2>()
  464. {
  465.           /*
  466.             These tests fail intermittently on all platforms - see DEV-16600
  467.             Commenting this out until dev has time to investigate.
  468.             
  469. // this is a test for LLLine::nearestApproach(LLLIne) method
  470. // which computes the point on a line nearest another line
  471. // these tests will have some floating point error, 
  472. // so we need to specify how much error is ok
  473. // TODO -- make nearestApproach() algorithm more accurate so
  474. // we can tighten the allowable_error.  Most tests are tighter
  475. // than one milimeter, however when doing randomized testing
  476. // you can walk into inaccurate cases.
  477. F32 allowable_relative_error = 0.001f;
  478. S32 number_of_tests = 100;
  479. for (S32 test = 0; test < number_of_tests; ++test)
  480. {
  481. // generate two points to be our known nearest approaches
  482. LLVector3 some_point( ll_frand(2.f) - 1.f, 
  483.       ll_frand(2.f) - 1.f, 
  484.       ll_frand(2.f) - 1.f);
  485. some_point.normalize();
  486. some_point *= ll_frand(LARGE_RADIUS);
  487. LLVector3 another_point( ll_frand(2.f) - 1.f, 
  488.      ll_frand(2.f) - 1.f, 
  489.      ll_frand(2.f) - 1.f);
  490. another_point.normalize();
  491. another_point *= ll_frand(LARGE_RADIUS);
  492. // compute the axis of approach (a unit vector between the points)
  493. LLVector3 axis_of_approach = another_point - some_point;
  494. axis_of_approach.normalize();
  495. // compute the direction of the the first line (perp to axis_of_approach)
  496. LLVector3 first_dir( ll_frand(2.f) - 1.f, 
  497.      ll_frand(2.f) - 1.f, 
  498.      ll_frand(2.f) - 1.f);
  499. F32 dot = first_dir * axis_of_approach;
  500. first_dir -= dot * axis_of_approach; // subtract component parallel to axis
  501. first_dir.normalize(); // normalize
  502. // compute the direction of the the second line
  503. LLVector3 second_dir( ll_frand(2.f) - 1.f, 
  504.       ll_frand(2.f) - 1.f, 
  505.       ll_frand(2.f) - 1.f);
  506. dot = second_dir * axis_of_approach;
  507. second_dir -= dot * axis_of_approach;
  508. second_dir.normalize();
  509. // make sure the lines aren't too parallel, 
  510. dot = fabsf(first_dir * second_dir);
  511. if (dot > 0.99f)
  512. {
  513. // skip this test, we're not interested in testing 
  514. // the intractible cases
  515. continue;
  516. }
  517. // construct the lines
  518. LLVector3 first_point = some_point + ll_frand(LARGE_RADIUS) * first_dir;
  519. LLLine first_line(first_point, some_point);
  520. LLVector3 second_point = another_point + ll_frand(LARGE_RADIUS) * second_dir;
  521. LLLine second_line(second_point, another_point);
  522. // compute the points of nearest approach
  523. LLVector3 some_computed_point = first_line.nearestApproach(second_line);
  524. LLVector3 another_computed_point = second_line.nearestApproach(first_line);
  525. // compute the error
  526. F32 first_error = (some_point - some_computed_point).length();
  527. F32 scale = llmax((some_point - another_point).length(), some_point.length());
  528. scale = llmax(scale, another_point.length());
  529. scale = llmax(scale, 1.f);
  530. F32 first_relative_error = first_error / scale;
  531. F32 second_error = (another_point - another_computed_point).length();
  532. F32 second_relative_error = second_error / scale;
  533. //if (first_relative_error > allowable_relative_error)
  534. //{
  535. // std::cout << "first_error = " << first_error 
  536. // << "  first_relative_error = " << first_relative_error 
  537. // << "  scale = " << scale 
  538. // << "  dir_dot = " << (first_dir * second_dir)
  539. // << std::endl;
  540. //}
  541. //if (second_relative_error > allowable_relative_error)
  542. //{
  543. // std::cout << "second_error = " << second_error 
  544. // << "  second_relative_error = " << second_relative_error 
  545. // << "  scale = " << scale 
  546. // << "  dist = " << (some_point - another_point).length()
  547. // << "  dir_dot = " << (first_dir * second_dir)
  548. // << std::endl;
  549. //}
  550. // test that the errors are small
  551. ensure("first line should accurately compute its closest approach", 
  552. first_relative_error <= allowable_relative_error);
  553. ensure("second line should accurately compute its closest approach", 
  554. second_relative_error <= allowable_relative_error);
  555. }
  556.           */
  557. }
  558. F32 ALMOST_PARALLEL = 0.99f;
  559. template<> template<>
  560. void line_object::test<3>()
  561. {
  562. // this is a test for LLLine::getIntersectionBetweenTwoPlanes() method
  563. // first some known tests
  564. LLLine xy_plane(LLVector3(0.f, 0.f, 2.f), LLVector3(0.f, 0.f, 3.f));
  565. LLLine yz_plane(LLVector3(2.f, 0.f, 0.f), LLVector3(3.f, 0.f, 0.f));
  566. LLLine zx_plane(LLVector3(0.f, 2.f, 0.f), LLVector3(0.f, 3.f, 0.f));
  567. LLLine x_line;
  568. LLLine y_line;
  569. LLLine z_line;
  570. bool x_success = LLLine::getIntersectionBetweenTwoPlanes(x_line, xy_plane, zx_plane);
  571. bool y_success = LLLine::getIntersectionBetweenTwoPlanes(y_line, yz_plane, xy_plane);
  572. bool z_success = LLLine::getIntersectionBetweenTwoPlanes(z_line, zx_plane, yz_plane);
  573. ensure("xy and zx planes should intersect", x_success);
  574. ensure("yz and xy planes should intersect", y_success);
  575. ensure("zx and yz planes should intersect", z_success);
  576. LLVector3 direction = x_line.getDirection();
  577. ensure("x_line should be parallel to x_axis", fabs(direction.mV[VX]) == 1.f
  578.                                       && 0.f == direction.mV[VY]
  579.                                       && 0.f == direction.mV[VZ] );
  580. direction = y_line.getDirection();
  581. ensure("y_line should be parallel to y_axis", 0.f == direction.mV[VX]
  582.   && fabs(direction.mV[VY]) == 1.f
  583.                                       && 0.f == direction.mV[VZ] );
  584. direction = z_line.getDirection();
  585. ensure("z_line should be parallel to z_axis", 0.f == direction.mV[VX]
  586.                                       && 0.f == direction.mV[VY]
  587.   && fabs(direction.mV[VZ]) == 1.f );
  588. // next some random tests
  589. F32 allowable_relative_error = 0.0001f;
  590. S32 number_of_tests = 20;
  591. for (S32 test = 0; test < number_of_tests; ++test)
  592. {
  593. // generate the known line
  594. LLVector3 some_point( ll_frand(2.f) - 1.f, 
  595.       ll_frand(2.f) - 1.f, 
  596.       ll_frand(2.f) - 1.f);
  597. some_point.normalize();
  598. some_point *= ll_frand(LARGE_RADIUS);
  599. LLVector3 another_point( ll_frand(2.f) - 1.f, 
  600.      ll_frand(2.f) - 1.f, 
  601.      ll_frand(2.f) - 1.f);
  602. another_point.normalize();
  603. another_point *= ll_frand(LARGE_RADIUS);
  604. LLLine known_intersection(some_point, another_point);
  605. // compute a plane that intersect the line
  606. LLVector3 point_on_plane( ll_frand(2.f) - 1.f, 
  607.       ll_frand(2.f) - 1.f, 
  608.       ll_frand(2.f) - 1.f);
  609. point_on_plane.normalize();
  610. point_on_plane *= ll_frand(LARGE_RADIUS);
  611. LLVector3 plane_normal = (point_on_plane - some_point) % known_intersection.getDirection();
  612. plane_normal.normalize();
  613. LLLine first_plane(point_on_plane, point_on_plane + plane_normal);
  614. // compute a different plane that intersect the line
  615. LLVector3 point_on_different_plane( ll_frand(2.f) - 1.f, 
  616.     ll_frand(2.f) - 1.f, 
  617.     ll_frand(2.f) - 1.f);
  618. point_on_different_plane.normalize();
  619. point_on_different_plane *= ll_frand(LARGE_RADIUS);
  620. LLVector3 different_plane_normal = (point_on_different_plane - another_point) % known_intersection.getDirection();
  621. different_plane_normal.normalize();
  622. LLLine second_plane(point_on_different_plane, point_on_different_plane + different_plane_normal);
  623. if (fabs(plane_normal * different_plane_normal) > ALMOST_PARALLEL)
  624. {
  625. // the two planes are approximately parallel, so we won't test this case
  626. continue;
  627. }
  628. LLLine measured_intersection;
  629. bool success = LLLine::getIntersectionBetweenTwoPlanes(
  630. measured_intersection,
  631. first_plane,
  632. second_plane);
  633. ensure("plane intersection should succeed", success);
  634. F32 dot = fabs(known_intersection.getDirection() * measured_intersection.getDirection());
  635. ensure("measured intersection should be parallel to known intersection",
  636. dot > ALMOST_PARALLEL);
  637. ensure("measured intersection should pass near known point",
  638. measured_intersection.intersects(some_point, LARGE_RADIUS * allowable_relative_error));
  639. }
  640. }
  641. }