IntrEllipsoid3Ellipsoid3.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. // David Eberly, Geometric Tools, Redmond WA 98052
  2. // Copyright (c) 1998-2020
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // https://www.boost.org/LICENSE_1_0.txt
  5. // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
  6. // Version: 4.0.2019.08.13
  7. #pragma once
  8. #include <Mathematics/Logger.h>
  9. #include <Mathematics/TIQuery.h>
  10. #include <Mathematics/Hyperellipsoid.h>
  11. #include <Mathematics/Matrix3x3.h>
  12. #include <Mathematics/RootsBisection.h>
  13. #include <Mathematics/RootsPolynomial.h>
  14. #include <Mathematics/SymmetricEigensolver3x3.h>
  15. namespace WwiseGTE
  16. {
  17. template <typename Real>
  18. class TIQuery<Real, Ellipsoid3<Real>, Ellipsoid3<Real>>
  19. {
  20. public:
  21. enum
  22. {
  23. ELLIPSOIDS_SEPARATED,
  24. ELLIPSOIDS_INTERSECTING,
  25. ELLIPSOID0_CONTAINS_ELLIPSOID1,
  26. ELLIPSOID1_CONTAINS_ELLIPSOID0
  27. };
  28. struct Result
  29. {
  30. // As solids, the ellipsoids intersect as long as they are not
  31. // separated.
  32. bool intersect;
  33. // This is one of the four enumerations listed above.
  34. int relationship;
  35. };
  36. Result operator()(Ellipsoid3<Real> const& ellipsoid0, Ellipsoid3<Real> const& ellipsoid1)
  37. {
  38. Result result;
  39. Real const zero = (Real)0;
  40. Real const one = (Real)1;
  41. // Get the parameters of ellipsoid0.
  42. Vector3<Real> K0 = ellipsoid0.center;
  43. Matrix3x3<Real> R0;
  44. R0.SetCol(0, ellipsoid0.axis[0]);
  45. R0.SetCol(1, ellipsoid0.axis[1]);
  46. R0.SetCol(2, ellipsoid0.axis[2]);
  47. Matrix3x3<Real> D0{
  48. one / (ellipsoid0.extent[0] * ellipsoid0.extent[0]), zero, zero,
  49. zero, one / (ellipsoid0.extent[1] * ellipsoid0.extent[1]), zero,
  50. zero, zero, one / (ellipsoid0.extent[2] * ellipsoid0.extent[2]) };
  51. // Get the parameters of ellipsoid1.
  52. Vector3<Real> K1 = ellipsoid1.center;
  53. Matrix3x3<Real> R1;
  54. R1.SetCol(0, ellipsoid1.axis[0]);
  55. R1.SetCol(1, ellipsoid1.axis[1]);
  56. R1.SetCol(2, ellipsoid1.axis[2]);
  57. Matrix3x3<Real> D1{
  58. one / (ellipsoid1.extent[0] * ellipsoid1.extent[0]), zero, zero,
  59. zero, one / (ellipsoid1.extent[1] * ellipsoid1.extent[1]), zero,
  60. zero, zero, one / (ellipsoid1.extent[2] * ellipsoid1.extent[2]) };
  61. // Compute K2.
  62. Matrix3x3<Real> D0NegHalf{
  63. ellipsoid0.extent[0], zero, zero,
  64. zero, ellipsoid0.extent[1], zero,
  65. zero, zero, ellipsoid0.extent[2] };
  66. Matrix3x3<Real> D0Half{
  67. one / ellipsoid0.extent[0], zero, zero,
  68. zero, one / ellipsoid0.extent[1], zero,
  69. zero, zero, one / ellipsoid0.extent[2] };
  70. Vector3<Real> K2 = D0Half * ((K1 - K0) * R0);
  71. // Compute M2.
  72. Matrix3x3<Real> R1TR0D0NegHalf = MultiplyATB(R1, R0 * D0NegHalf);
  73. Matrix3x3<Real> M2 = MultiplyATB(R1TR0D0NegHalf, D1) * R1TR0D0NegHalf;
  74. // Factor M2 = R*D*R^T.
  75. SymmetricEigensolver3x3<Real> es;
  76. std::array<Real, 3> D;
  77. std::array<std::array<Real, 3>, 3> evec;
  78. es(M2(0, 0), M2(0, 1), M2(0, 2), M2(1, 1), M2(1, 2), M2(2, 2), false, +1, D, evec);
  79. Matrix3x3<Real> R;
  80. R.SetCol(0, evec[0]);
  81. R.SetCol(1, evec[1]);
  82. R.SetCol(2, evec[2]);
  83. // Compute K = R^T*K2.
  84. Vector3<Real> K = K2 * R;
  85. // Transformed ellipsoid0 is Z^T*Z = 1 and transformed ellipsoid1
  86. // is (Z-K)^T*D*(Z-K) = 0.
  87. // The minimum and maximum squared distances from the origin of
  88. // points on transformed ellipsoid1 are used to determine whether
  89. // the ellipsoids intersect, are separated, or one contains the
  90. // other.
  91. Real minSqrDistance = std::numeric_limits<Real>::max();
  92. Real maxSqrDistance = zero;
  93. int i;
  94. if (K == Vector3<Real>::Zero())
  95. {
  96. // The special case of common centers must be handled
  97. // separately. It is not possible for the ellipsoids to be
  98. // separated.
  99. for (i = 0; i < 3; ++i)
  100. {
  101. Real invD = one / D[i];
  102. if (invD < minSqrDistance)
  103. {
  104. minSqrDistance = invD;
  105. }
  106. if (invD > maxSqrDistance)
  107. {
  108. maxSqrDistance = invD;
  109. }
  110. }
  111. if (maxSqrDistance < one)
  112. {
  113. result.relationship = ELLIPSOID0_CONTAINS_ELLIPSOID1;
  114. }
  115. else if (minSqrDistance > (Real)1)
  116. {
  117. result.relationship = ELLIPSOID1_CONTAINS_ELLIPSOID0;
  118. }
  119. else
  120. {
  121. result.relationship = ELLIPSOIDS_INTERSECTING;
  122. }
  123. result.intersect = true;
  124. return result;
  125. }
  126. // The closest point P0 and farthest point P1 are solutions to
  127. // s0*D*(P0 - K) = P0 and s1*D*(P1 - K) = P1 for some scalars s0
  128. // and s1 that are roots to the function
  129. // f(s) = d0*k0^2/(d0*s-1)^2 + d1*k1^2/(d1*s-1)^2
  130. // + d2*k2^2/(d2*s-1)^2 - 1
  131. // where D = diagonal(d0,d1,d2) and K = (k0,k1,k2).
  132. Real d0 = D[0], d1 = D[1], d2 = D[2];
  133. Real c0 = K[0] * K[0], c1 = K[1] * K[1], c2 = K[2] * K[2];
  134. // Sort the values so that d0 >= d1 >= d2. This allows us to
  135. // bound the roots of f(s), of which there are at most 6.
  136. std::vector<std::pair<Real, Real>> param(3);
  137. param[0] = std::make_pair(d0, c0);
  138. param[1] = std::make_pair(d1, c1);
  139. param[2] = std::make_pair(d2, c2);
  140. std::sort(param.begin(), param.end(), std::greater<std::pair<Real, Real>>());
  141. std::vector<std::pair<Real, Real>> valid;
  142. valid.reserve(3);
  143. if (param[0].first > param[1].first)
  144. {
  145. if (param[1].first > param[2].first)
  146. {
  147. // d0 > d1 > d2
  148. for (i = 0; i < 3; ++i)
  149. {
  150. if (param[i].second > (Real)0)
  151. {
  152. valid.push_back(param[i]);
  153. }
  154. }
  155. }
  156. else
  157. {
  158. // d0 > d1 = d2
  159. if (param[0].second > (Real)0)
  160. {
  161. valid.push_back(param[0]);
  162. }
  163. param[1].second += param[0].second;
  164. if (param[1].second > (Real)0)
  165. {
  166. valid.push_back(param[1]);
  167. }
  168. }
  169. }
  170. else
  171. {
  172. if (param[1].first > param[2].first)
  173. {
  174. // d0 = d1 > d2
  175. param[0].second += param[1].second;
  176. if (param[0].second > (Real)0)
  177. {
  178. valid.push_back(param[0]);
  179. }
  180. if (param[2].second > (Real)0)
  181. {
  182. valid.push_back(param[2]);
  183. }
  184. }
  185. else
  186. {
  187. // d0 = d1 = d2
  188. param[0].second += param[1].second + param[2].second;
  189. if (param[0].second > (Real)0)
  190. {
  191. valid.push_back(param[0]);
  192. }
  193. }
  194. }
  195. size_t numValid = valid.size();
  196. int numRoots;
  197. Real roots[6];
  198. if (numValid == 3)
  199. {
  200. GetRoots(valid[0].first, valid[1].first, valid[2].first,
  201. valid[0].second, valid[1].second, valid[2].second, numRoots, roots);
  202. }
  203. else if (numValid == 2)
  204. {
  205. GetRoots(valid[0].first, valid[1].first, valid[0].second,
  206. valid[1].second, numRoots, roots);
  207. }
  208. else if (numValid == 1)
  209. {
  210. GetRoots(valid[0].first, valid[0].second, numRoots, roots);
  211. }
  212. else
  213. {
  214. // numValid cannot be zero because we already handled case K = 0
  215. LogError("Unexpected condition.");
  216. }
  217. for (i = 0; i < numRoots; ++i)
  218. {
  219. Real s = roots[i];
  220. Real p0 = d0 * K[0] * s / (d0 * s - (Real)1);
  221. Real p1 = d1 * K[1] * s / (d1 * s - (Real)1);
  222. Real p2 = d2 * K[2] * s / (d2 * s - (Real)1);
  223. Real sqrDistance = p0 * p0 + p1 * p1 + p2 * p2;
  224. if (sqrDistance < minSqrDistance)
  225. {
  226. minSqrDistance = sqrDistance;
  227. }
  228. if (sqrDistance > maxSqrDistance)
  229. {
  230. maxSqrDistance = sqrDistance;
  231. }
  232. }
  233. if (maxSqrDistance < one)
  234. {
  235. result.intersect = true;
  236. result.relationship = ELLIPSOID0_CONTAINS_ELLIPSOID1;
  237. }
  238. else if (minSqrDistance > (Real)1)
  239. {
  240. if (d0 * c0 + d1 * c1 + d2 * c2 > one)
  241. {
  242. result.intersect = false;
  243. result.relationship = ELLIPSOIDS_SEPARATED;
  244. }
  245. else
  246. {
  247. result.intersect = true;
  248. result.relationship = ELLIPSOID1_CONTAINS_ELLIPSOID0;
  249. }
  250. }
  251. else
  252. {
  253. result.intersect = true;
  254. result.relationship = ELLIPSOIDS_INTERSECTING;
  255. }
  256. return result;
  257. }
  258. private:
  259. void GetRoots(Real d0, Real c0, int& numRoots, Real* roots)
  260. {
  261. // f(s) = d0*c0/(d0*s-1)^2 - 1
  262. Real const one = (Real)1;
  263. Real temp = std::sqrt(d0 * c0);
  264. Real inv = one / d0;
  265. numRoots = 2;
  266. roots[0] = (one - temp) * inv;
  267. roots[1] = (one + temp) * inv;
  268. }
  269. void GetRoots(Real d0, Real d1, Real c0, Real c1, int& numRoots, Real* roots)
  270. {
  271. // f(s) = d0*c0/(d0*s-1)^2 + d1*c1/(d1*s-1)^2 - 1
  272. // with d0 > d1
  273. Real const zero = (Real)0;
  274. Real const one = (Real)1;
  275. Real const two = (Real)2;
  276. Real d0c0 = d0 * c0;
  277. Real d1c1 = d1 * c1;
  278. std::function<Real(Real)> F = [&one, d0, d1, d0c0, d1c1](Real s)
  279. {
  280. Real invN0 = one / (d0 * s - one);
  281. Real invN1 = one / (d1 * s - one);
  282. Real term0 = d0c0 * invN0 * invN0;
  283. Real term1 = d1c1 * invN1 * invN1;
  284. Real f = term0 + term1 - one;
  285. return f;
  286. };
  287. std::function<Real(Real)> DF = [&one, &two, d0, d1, d0c0, d1c1](Real s)
  288. {
  289. Real invN0 = one / (d0 * s - one);
  290. Real invN1 = one / (d1 * s - one);
  291. Real term0 = d0 * d0c0 * invN0 * invN0 * invN0;
  292. Real term1 = d1 * d1c1 * invN1 * invN1 * invN1;
  293. Real df = -two * (term0 + term1);
  294. return df;
  295. };
  296. unsigned int const maxIterations = 1024;
  297. unsigned int iterations;
  298. numRoots = 0;
  299. // TODO: What role does epsilon play?
  300. Real const epsilon = (Real)0.001;
  301. Real multiplier0 = std::sqrt(two / (one - epsilon));
  302. Real multiplier1 = std::sqrt(one / (one + epsilon));
  303. Real sqrtd0c0 = std::sqrt(d0c0);
  304. Real sqrtd1c1 = std::sqrt(d1c1);
  305. Real invD0 = one / d0;
  306. Real invD1 = one / d1;
  307. Real temp0, temp1, smin, smax, s;
  308. // Compute root in (-infinity,1/d0).
  309. temp0 = (one - multiplier0 * sqrtd0c0) * invD0;
  310. temp1 = (one - multiplier0 * sqrtd1c1) * invD1;
  311. smin = std::min(temp0, temp1);
  312. LogAssert(F(smin) < zero, "Unexpected condition.");
  313. smax = (one - multiplier1 * sqrtd0c0) * invD0;
  314. LogAssert(F(smax) > zero, "Unexpected condition.");
  315. iterations = RootsBisection<Real>::Find(F, smin, smax, maxIterations, s);
  316. LogAssert(iterations > 0, "Unexpected condition.");
  317. roots[numRoots++] = s;
  318. // Compute roots (if any) in (1/d0,1/d1). It is the case that
  319. // F(1/d0) = +infinity, F'(1/d0) = -infinity
  320. // F(1/d1) = +infinity, F'(1/d1) = +infinity
  321. // F"(s) > 0 for all s in the domain of F
  322. // Compute the unique root r of F'(s) on (1/d0,1/d1). The
  323. // bisector needs only the signs at the endpoints, so we pass -1
  324. // and +1 instead of the infinite values. If F(r) < 0, F(s) has
  325. // two roots in the interval. If F(r) = 0, F(s) has only one root
  326. // in the interval.
  327. Real smid;
  328. iterations = RootsBisection<Real>::Find(DF, invD0, invD1, -one, one,
  329. maxIterations, smid);
  330. LogAssert(iterations > 0, "Unexpected condition.");
  331. if (F(smid) < zero)
  332. {
  333. // Pass in signs rather than infinities, because the bisector
  334. // cares only about the signs.
  335. iterations = RootsBisection<Real>::Find(F, invD0, smid, one, -one,
  336. maxIterations, s);
  337. LogAssert(iterations > 0, "Unexpected condition.");
  338. roots[numRoots++] = s;
  339. iterations = RootsBisection<Real>::Find(F, smid, invD1, -one, one,
  340. maxIterations, s);
  341. LogAssert(iterations > 0, "Unexpected condition.");
  342. roots[numRoots++] = s;
  343. }
  344. // Compute root in (1/d1,+infinity).
  345. temp0 = (one + multiplier0 * sqrtd0c0) * invD0;
  346. temp1 = (one + multiplier0 * sqrtd1c1) * invD1;
  347. smax = std::max(temp0, temp1);
  348. LogAssert(F(smax) < zero, "Unexpected condition.");
  349. smin = (one + multiplier1 * sqrtd1c1) * invD1;
  350. LogAssert(F(smin) > zero, "Unexpected condition.");
  351. iterations = RootsBisection<Real>::Find(F, smin, smax, maxIterations, s);
  352. LogAssert(iterations > 0, "Unexpected condition.");
  353. roots[numRoots++] = s;
  354. }
  355. void GetRoots(Real d0, Real d1, Real d2, Real c0, Real c1, Real c2,
  356. int& numRoots, Real* roots)
  357. {
  358. // f(s) = d0*c0/(d0*s-1)^2 + d1*c1/(d1*s-1)^2
  359. // + d2*c2/(d2*s-1)^2 - 1 with d0 > d1 > d2
  360. Real const zero = (Real)0;
  361. Real const one = (Real)1;
  362. Real const three = (Real)3;
  363. Real d0c0 = d0 * c0;
  364. Real d1c1 = d1 * c1;
  365. Real d2c2 = d2 * c2;
  366. std::function<Real(Real)> F = [&one, d0, d1, d2, d0c0, d1c1, d2c2](Real s)
  367. {
  368. Real invN0 = one / (d0 * s - one);
  369. Real invN1 = one / (d1 * s - one);
  370. Real invN2 = one / (d2 * s - one);
  371. Real term0 = d0c0 * invN0 * invN0;
  372. Real term1 = d1c1 * invN1 * invN1;
  373. Real term2 = d2c2 * invN2 * invN2;
  374. Real f = term0 + term1 + term2 - one;
  375. return f;
  376. };
  377. std::function<Real(Real)> DF = [&one, d0, d1, d2, d0c0, d1c1, d2c2](Real s)
  378. {
  379. Real const two = (Real)2;
  380. Real invN0 = one / (d0 * s - one);
  381. Real invN1 = one / (d1 * s - one);
  382. Real invN2 = one / (d2 * s - one);
  383. Real term0 = d0 * d0c0 * invN0 * invN0 * invN0;
  384. Real term1 = d1 * d1c1 * invN1 * invN1 * invN1;
  385. Real term2 = d2 * d2c2 * invN2 * invN2 * invN2;
  386. Real df = -two * (term0 + term1 + term2);
  387. return df;
  388. };
  389. unsigned int const maxIterations = 1024;
  390. unsigned int iterations;
  391. numRoots = 0;
  392. // TODO: What role does epsilon play?
  393. Real epsilon = (Real)0.001;
  394. Real multiplier0 = std::sqrt(three / (one - epsilon));
  395. Real multiplier1 = std::sqrt(one / (one + epsilon));
  396. Real sqrtd0c0 = std::sqrt(d0c0);
  397. Real sqrtd1c1 = std::sqrt(d1c1);
  398. Real sqrtd2c2 = std::sqrt(d2c2);
  399. Real invD0 = one / d0;
  400. Real invD1 = one / d1;
  401. Real invD2 = one / d2;
  402. Real temp0, temp1, temp2, smin, smax, s;
  403. // Compute root in (-infinity,1/d0).
  404. temp0 = (one - multiplier0 * sqrtd0c0) * invD0;
  405. temp1 = (one - multiplier0 * sqrtd1c1) * invD1;
  406. temp2 = (one - multiplier0 * sqrtd2c2) * invD2;
  407. smin = std::min(std::min(temp0, temp1), temp2);
  408. LogAssert(F(smin) < zero, "Unexpected condition.");
  409. smax = (one - multiplier1 * sqrtd0c0) * invD0;
  410. LogAssert(F(smax) > zero, "Unexpected condition.");
  411. iterations = RootsBisection<Real>::Find(F, smin, smax, maxIterations, s);
  412. LogAssert(iterations > 0, "Unexpected condition.");
  413. roots[numRoots++] = s;
  414. // Compute roots (if any) in (1/d0,1/d1). It is the case that
  415. // F(1/d0) = +infinity, F'(1/d0) = -infinity
  416. // F(1/d1) = +infinity, F'(1/d1) = +infinity
  417. // F"(s) > 0 for all s in the domain of F
  418. // Compute the unique root r of F'(s) on (1/d0,1/d1). The
  419. // bisector needs only the signs at the endpoints, so we pass -1
  420. // and +1 instead of the infinite values. If F(r) < 0, F(s) has
  421. // two roots in the interval. If F(r) = 0, F(s) has only one root
  422. // in the interval.
  423. Real smid;
  424. iterations = RootsBisection<Real>::Find(DF, invD0, invD1, -one, one,
  425. maxIterations, smid);
  426. LogAssert(iterations > 0, "Unexpected condition.");
  427. if (F(smid) < zero)
  428. {
  429. // Pass in signs rather than infinities, because the bisector cares
  430. // only about the signs.
  431. iterations = RootsBisection<Real>::Find(F, invD0, smid, one, -one,
  432. maxIterations, s);
  433. LogAssert(iterations > 0, "Unexpected condition.");
  434. roots[numRoots++] = s;
  435. iterations = RootsBisection<Real>::Find(F, smid, invD1, -one, one,
  436. maxIterations, s);
  437. LogAssert(iterations > 0, "Unexpected condition.");
  438. roots[numRoots++] = s;
  439. }
  440. // Compute roots (if any) in (1/d1,1/d2). It is the case that
  441. // F(1/d1) = +infinity, F'(1/d1) = -infinity
  442. // F(1/d2) = +infinity, F'(1/d2) = +infinity
  443. // F"(s) > 0 for all s in the domain of F
  444. // Compute the unique root r of F'(s) on (1/d1,1/d2). The
  445. // bisector needs only the signs at the endpoints, so we pass -1
  446. // and +1 instead of the infinite values. If F(r) < 0, F(s) has
  447. // two roots in the interval. If F(r) = 0, F(s) has only one root
  448. // in the interval.
  449. iterations = RootsBisection<Real>::Find(DF, invD1, invD2, -one, one,
  450. maxIterations, smid);
  451. LogAssert(iterations > 0, "Unexpected condition.");
  452. if (F(smid) < zero)
  453. {
  454. // Pass in signs rather than infinities, because the bisector
  455. // cares only about the signs.
  456. iterations = RootsBisection<Real>::Find(F, invD1, smid, one, -one,
  457. maxIterations, s);
  458. LogAssert(iterations > 0, "Unexpected condition.");
  459. roots[numRoots++] = s;
  460. iterations = RootsBisection<Real>::Find(F, smid, invD2, -one, one,
  461. maxIterations, s);
  462. LogAssert(iterations > 0, "Unexpected condition.");
  463. roots[numRoots++] = s;
  464. }
  465. // Compute root in (1/d2,+infinity).
  466. temp0 = (one + multiplier0 * sqrtd0c0) * invD0;
  467. temp1 = (one + multiplier0 * sqrtd1c1) * invD1;
  468. temp2 = (one + multiplier0 * sqrtd2c2) * invD2;
  469. smax = std::max(std::max(temp0, temp1), temp2);
  470. LogAssert(F(smax) < zero, "Unexpected condition.");
  471. smin = (one + multiplier1 * sqrtd2c2) * invD2;
  472. LogAssert(F(smin) > zero, "Unexpected condition.");
  473. iterations = RootsBisection<Real>::Find(F, smin, smax, maxIterations, s);
  474. LogAssert(iterations > 0, "Unexpected condition.");
  475. roots[numRoots++] = s;
  476. }
  477. };
  478. }