IntrEllipse2Ellipse2.h 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249
  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/FIQuery.h>
  10. #include <Mathematics/TIQuery.h>
  11. #include <Mathematics/Hyperellipsoid.h>
  12. #include <Mathematics/RootsBisection.h>
  13. #include <Mathematics/RootsPolynomial.h>
  14. #include <Mathematics/SymmetricEigensolver2x2.h>
  15. #include <Mathematics/Matrix2x2.h>
  16. // The test-intersection and find-intersection queries implemented here are
  17. // discussed in the document
  18. // https://www.geometrictools.com/Documentation/IntersectionOfEllipses.pdf
  19. // The Real type should support exact rational arithmetic in order for the
  20. // polynomial root construction to be robust. The classification of the
  21. // intersections depends on various sign tests of computed values. If these
  22. // values are computed with floating-point arithmetic, the sign tests can
  23. // lead to misclassification.
  24. //
  25. // The area-of-intersection query is discussed in the document
  26. // https://www.geometrictools.com/Documentation/AreaIntersectingEllipses.pdf
  27. namespace WwiseGTE
  28. {
  29. template <typename Real>
  30. class TIQuery<Real, Ellipse2<Real>, Ellipse2<Real>>
  31. {
  32. public:
  33. // The query tests the relationship between the ellipses as solid
  34. // objects.
  35. enum
  36. {
  37. ELLIPSES_SEPARATED,
  38. ELLIPSES_OVERLAP,
  39. ELLIPSE0_OUTSIDE_ELLIPSE1_BUT_TANGENT,
  40. ELLIPSE0_STRICTLY_CONTAINS_ELLIPSE1,
  41. ELLIPSE0_CONTAINS_ELLIPSE1_BUT_TANGENT,
  42. ELLIPSE1_STRICTLY_CONTAINS_ELLIPSE0,
  43. ELLIPSE1_CONTAINS_ELLIPSE0_BUT_TANGENT,
  44. ELLIPSES_EQUAL
  45. };
  46. // The ellipse axes are already normalized, which most likely
  47. // introduced rounding errors.
  48. int operator()(Ellipse2<Real> const& ellipse0, Ellipse2<Real> const& ellipse1)
  49. {
  50. Real const zero = 0, one = 1;
  51. // Get the parameters of ellipe0.
  52. Vector2<Real> K0 = ellipse0.center;
  53. Matrix2x2<Real> R0;
  54. R0.SetCol(0, ellipse0.axis[0]);
  55. R0.SetCol(1, ellipse0.axis[1]);
  56. Matrix2x2<Real> D0{
  57. one / (ellipse0.extent[0] * ellipse0.extent[0]), zero,
  58. zero, one / (ellipse0.extent[1] * ellipse0.extent[1]) };
  59. // Get the parameters of ellipse1.
  60. Vector2<Real> K1 = ellipse1.center;
  61. Matrix2x2<Real> R1;
  62. R1.SetCol(0, ellipse1.axis[0]);
  63. R1.SetCol(1, ellipse1.axis[1]);
  64. Matrix2x2<Real> D1{
  65. one / (ellipse1.extent[0] * ellipse1.extent[0]), zero,
  66. zero, one / (ellipse1.extent[1] * ellipse1.extent[1]) };
  67. // Compute K2.
  68. Matrix2x2<Real> D0NegHalf{
  69. ellipse0.extent[0], zero,
  70. zero, ellipse0.extent[1] };
  71. Matrix2x2<Real> D0Half{
  72. one / ellipse0.extent[0], zero,
  73. zero, one / ellipse0.extent[1] };
  74. Vector2<Real> K2 = D0Half * ((K1 - K0) * R0);
  75. // Compute M2.
  76. Matrix2x2<Real> R1TR0D0NegHalf = MultiplyATB(R1, R0 * D0NegHalf);
  77. Matrix2x2<Real> M2 = MultiplyATB(R1TR0D0NegHalf, D1) * R1TR0D0NegHalf;
  78. // Factor M2 = R*D*R^T.
  79. SymmetricEigensolver2x2<Real> es;
  80. std::array<Real, 2> D;
  81. std::array<std::array<Real, 2>, 2> evec;
  82. es(M2(0, 0), M2(0, 1), M2(1, 1), +1, D, evec);
  83. Matrix2x2<Real> R;
  84. R.SetCol(0, evec[0]);
  85. R.SetCol(1, evec[1]);
  86. // Compute K = R^T*K2.
  87. Vector2<Real> K = K2 * R;
  88. // Transformed ellipse0 is Z^T*Z = 1 and transformed ellipse1 is
  89. // (Z-K)^T*D*(Z-K) = 0.
  90. // The minimum and maximum squared distances from the origin of
  91. // points on transformed ellipse1 are used to determine whether
  92. // the ellipses intersect, are separated or one contains the
  93. // other.
  94. Real minSqrDistance = std::numeric_limits<Real>::max();
  95. Real maxSqrDistance = zero;
  96. if (K == Vector2<Real>::Zero())
  97. {
  98. // The special case of common centers must be handled
  99. // separately. It is not possible for the ellipses to be
  100. // separated.
  101. for (int i = 0; i < 2; ++i)
  102. {
  103. Real invD = one / D[i];
  104. if (invD < minSqrDistance)
  105. {
  106. minSqrDistance = invD;
  107. }
  108. if (invD > maxSqrDistance)
  109. {
  110. maxSqrDistance = invD;
  111. }
  112. }
  113. return Classify(minSqrDistance, maxSqrDistance, zero);
  114. }
  115. // The closest point P0 and farthest point P1 are solutions to
  116. // s0*D*(P0 - K) = P0 and s1*D1*(P1 - K) = P1 for some scalars s0
  117. // and s1 that are roots to the function
  118. // f(s) = d0*k0^2/(d0*s-1)^2 + d1*k1^2/(d1*s-1)^2 - 1
  119. // where D = diagonal(d0,d1) and K = (k0,k1).
  120. Real d0 = D[0], d1 = D[1];
  121. Real c0 = K[0] * K[0], c1 = K[1] * K[1];
  122. // Sort the values so that d0 >= d1. This allows us to bound the
  123. // roots of f(s), of which there are at most 4.
  124. std::vector<std::pair<Real, Real>> param(2);
  125. if (d0 >= d1)
  126. {
  127. param[0] = std::make_pair(d0, c0);
  128. param[1] = std::make_pair(d1, c1);
  129. }
  130. else
  131. {
  132. param[0] = std::make_pair(d1, c1);
  133. param[1] = std::make_pair(d0, c0);
  134. }
  135. std::vector<std::pair<Real, Real>> valid;
  136. valid.reserve(2);
  137. if (param[0].first > param[1].first)
  138. {
  139. // d0 > d1
  140. for (int i = 0; i < 2; ++i)
  141. {
  142. if (param[i].second > zero)
  143. {
  144. valid.push_back(param[i]);
  145. }
  146. }
  147. }
  148. else
  149. {
  150. // d0 = d1
  151. param[0].second += param[1].second;
  152. if (param[0].second > zero)
  153. {
  154. valid.push_back(param[0]);
  155. }
  156. }
  157. size_t numValid = valid.size();
  158. int numRoots = 0;
  159. Real roots[4];
  160. if (numValid == 2)
  161. {
  162. GetRoots(valid[0].first, valid[1].first, valid[0].second,
  163. valid[1].second, numRoots, roots);
  164. }
  165. else if (numValid == 1)
  166. {
  167. GetRoots(valid[0].first, valid[0].second, numRoots, roots);
  168. }
  169. // else: numValid cannot be zero because we already handled case
  170. // K = 0
  171. for (int i = 0; i < numRoots; ++i)
  172. {
  173. Real s = roots[i];
  174. Real p0 = d0 * K[0] * s / (d0 * s - (Real)1);
  175. Real p1 = d1 * K[1] * s / (d1 * s - (Real)1);
  176. Real sqrDistance = p0 * p0 + p1 * p1;
  177. if (sqrDistance < minSqrDistance)
  178. {
  179. minSqrDistance = sqrDistance;
  180. }
  181. if (sqrDistance > maxSqrDistance)
  182. {
  183. maxSqrDistance = sqrDistance;
  184. }
  185. }
  186. return Classify(minSqrDistance, maxSqrDistance, d0 * c0 + d1 * c1);
  187. }
  188. private:
  189. void GetRoots(Real d0, Real c0, int& numRoots, Real* roots)
  190. {
  191. // f(s) = d0*c0/(d0*s-1)^2 - 1
  192. Real const one = (Real)1;
  193. Real temp = std::sqrt(d0 * c0);
  194. Real inv = one / d0;
  195. numRoots = 2;
  196. roots[0] = (one - temp) * inv;
  197. roots[1] = (one + temp) * inv;
  198. }
  199. void GetRoots(Real d0, Real d1, Real c0, Real c1, int& numRoots, Real* roots)
  200. {
  201. // f(s) = d0*c0/(d0*s-1)^2 + d1*c1/(d1*s-1)^2 - 1 with d0 > d1
  202. Real const zero = 0, one = (Real)1;
  203. Real d0c0 = d0 * c0;
  204. Real d1c1 = d1 * c1;
  205. Real sum = d0c0 + d1c1;
  206. Real sqrtsum = std::sqrt(sum);
  207. std::function<Real(Real)> F = [&one, d0, d1, d0c0, d1c1](Real s)
  208. {
  209. Real invN0 = one / (d0 * s - one);
  210. Real invN1 = one / (d1 * s - one);
  211. Real term0 = d0c0 * invN0 * invN0;
  212. Real term1 = d1c1 * invN1 * invN1;
  213. Real f = term0 + term1 - one;
  214. return f;
  215. };
  216. std::function<Real(Real)> DF = [&one, d0, d1, d0c0, d1c1](Real s)
  217. {
  218. Real const two = 2;
  219. Real invN0 = one / (d0 * s - one);
  220. Real invN1 = one / (d1 * s - one);
  221. Real term0 = d0 * d0c0 * invN0 * invN0 * invN0;
  222. Real term1 = d1 * d1c1 * invN1 * invN1 * invN1;
  223. Real df = -two * (term0 + term1);
  224. return df;
  225. };
  226. unsigned int const maxIterations = static_cast<unsigned int>(
  227. 3 + std::numeric_limits<Real>::digits -
  228. std::numeric_limits<Real>::min_exponent);
  229. unsigned int iterations;
  230. numRoots = 0;
  231. Real invD0 = one / d0;
  232. Real invD1 = one / d1;
  233. Real smin, smax, s, fval;
  234. // Compute root in (-infinity,1/d0). Obtain a lower bound for the
  235. // root better than -std::numeric_limits<Real>::max().
  236. smax = invD0;
  237. fval = sum - one;
  238. if (fval > zero)
  239. {
  240. smin = (one - sqrtsum) * invD1; // < 0
  241. fval = F(smin);
  242. LogAssert(fval <= zero, "Unexpected condition.");
  243. }
  244. else
  245. {
  246. smin = zero;
  247. }
  248. iterations = RootsBisection<Real>::Find(F, smin, smax, -one, one,
  249. maxIterations, s);
  250. fval = F(s);
  251. LogAssert(iterations > 0, "Unexpected condition.");
  252. roots[numRoots++] = s;
  253. // Compute roots (if any) in (1/d0,1/d1). It is the case that
  254. // F(1/d0) = +infinity, F'(1/d0) = -infinity
  255. // F(1/d1) = +infinity, F'(1/d1) = +infinity
  256. // F"(s) > 0 for all s in the domain of F
  257. // Compute the unique root r of F'(s) on (1/d0,1/d1). The
  258. // bisector needs only the signs at the endpoints, so we pass -1
  259. // and +1 instead of the infinite values. If F(r) < 0, F(s) has
  260. // two roots in the interval. If F(r) = 0, F(s) has only one root
  261. // in the interval.
  262. Real const oneThird = (Real)1 / (Real)3;
  263. Real rho = std::pow(d0 * d0c0 / (d1 * d1c1), oneThird);
  264. Real smid = (one + rho) / (d0 + rho * d1);
  265. Real fmid = F(smid);
  266. if (fmid <= zero)
  267. {
  268. // Pass in signs rather than infinities, because the bisector cares
  269. // only about the signs.
  270. iterations = RootsBisection<Real>::Find(F, invD0, smid, one, -one,
  271. maxIterations, s);
  272. fval = F(s);
  273. LogAssert(iterations > 0, "Unexpected condition.");
  274. roots[numRoots++] = s;
  275. iterations = RootsBisection<Real>::Find(F, smid, invD1, -one, one,
  276. maxIterations, s);
  277. fval = F(s);
  278. LogAssert(iterations > 0, "Unexpected condition.");
  279. roots[numRoots++] = s;
  280. }
  281. else if (fmid == zero)
  282. {
  283. roots[numRoots++] = smid;
  284. }
  285. // Compute root in (1/d1,+infinity). Obtain an upper bound for
  286. // the root better than std::numeric_limits<Real>::max().
  287. smin = invD1;
  288. smax = (one + sqrtsum) * invD1; // > 1/d1
  289. fval = F(smax);
  290. LogAssert(fval <= zero, "Unexpected condition.");
  291. iterations = RootsBisection<Real>::Find(F, smin, smax, one, -one,
  292. maxIterations, s);
  293. fval = F(s);
  294. LogAssert(iterations > 0, "Unexpected condition.");
  295. roots[numRoots++] = s;
  296. }
  297. int Classify(Real minSqrDistance, Real maxSqrDistance, Real d0c0pd1c1)
  298. {
  299. Real const one = (Real)1;
  300. if (maxSqrDistance < one)
  301. {
  302. return ELLIPSE0_STRICTLY_CONTAINS_ELLIPSE1;
  303. }
  304. else if (maxSqrDistance > one)
  305. {
  306. if (minSqrDistance < one)
  307. {
  308. return ELLIPSES_OVERLAP;
  309. }
  310. else if (minSqrDistance > one)
  311. {
  312. if (d0c0pd1c1 > one)
  313. {
  314. return ELLIPSES_SEPARATED;
  315. }
  316. else
  317. {
  318. return ELLIPSE1_STRICTLY_CONTAINS_ELLIPSE0;
  319. }
  320. }
  321. else // minSqrDistance = 1
  322. {
  323. if (d0c0pd1c1 > one)
  324. {
  325. return ELLIPSE0_OUTSIDE_ELLIPSE1_BUT_TANGENT;
  326. }
  327. else
  328. {
  329. return ELLIPSE1_CONTAINS_ELLIPSE0_BUT_TANGENT;
  330. }
  331. }
  332. }
  333. else // maxSqrDistance = 1
  334. {
  335. if (minSqrDistance < one)
  336. {
  337. return ELLIPSE0_CONTAINS_ELLIPSE1_BUT_TANGENT;
  338. }
  339. else // minSqrDistance = 1
  340. {
  341. return ELLIPSES_EQUAL;
  342. }
  343. }
  344. }
  345. };
  346. template <typename Real>
  347. class FIQuery<Real, Ellipse2<Real>, Ellipse2<Real>>
  348. {
  349. public:
  350. // The queries find the intersections (if any) of the ellipses treated
  351. // as hollow objects. The implementations use the same concepts.
  352. FIQuery()
  353. :
  354. mZero((Real)0),
  355. mOne((Real)1),
  356. mTwo((Real)2),
  357. mPi((Real)GTE_C_PI),
  358. mTwoPi((Real)GTE_C_TWO_PI)
  359. {
  360. }
  361. struct Result
  362. {
  363. // This value is true when the ellipses intersect in at least one
  364. // point.
  365. bool intersect;
  366. // If the ellipses are not the same, numPoints is 0 through 4 and
  367. // that number of elements of 'points' are valid. If the ellipses
  368. // are the same, numPoints is set to maxInt and 'points' is
  369. // invalid.
  370. int numPoints;
  371. std::array<Vector2<Real>, 4> points;
  372. std::array<bool, 4> isTransverse;
  373. };
  374. // The ellipse axes are already normalized, which most likely
  375. // introducedrounding errors.
  376. Result operator()(Ellipse2<Real> const& ellipse0, Ellipse2<Real> const& ellipse1)
  377. {
  378. Vector2<Real> rCenter, rAxis[2], rSqrExtent;
  379. rCenter = { ellipse0.center[0], ellipse0.center[1] };
  380. rAxis[0] = { ellipse0.axis[0][0], ellipse0.axis[0][1] };
  381. rAxis[1] = { ellipse0.axis[1][0], ellipse0.axis[1][1] };
  382. rSqrExtent =
  383. {
  384. ellipse0.extent[0] * ellipse0.extent[0],
  385. ellipse0.extent[1] * ellipse0.extent[1]
  386. };
  387. ToCoefficients(rCenter, rAxis, rSqrExtent, mA);
  388. rCenter = { ellipse1.center[0], ellipse1.center[1] };
  389. rAxis[0] = { ellipse1.axis[0][0], ellipse1.axis[0][1] };
  390. rAxis[1] = { ellipse1.axis[1][0], ellipse1.axis[1][1] };
  391. rSqrExtent =
  392. {
  393. ellipse1.extent[0] * ellipse1.extent[0],
  394. ellipse1.extent[1] * ellipse1.extent[1]
  395. };
  396. ToCoefficients(rCenter, rAxis, rSqrExtent, mB);
  397. Result result;
  398. DoRootFinding(result);
  399. return result;
  400. }
  401. // The axis directions do not have to be unit length. The quadratic
  402. // equations are constructed according to the details of the PDF
  403. // document about the intersection of ellipses.
  404. Result operator()(Vector2<Real> const& center0,
  405. Vector2<Real> const axis0[2], Vector2<Real> const& sqrExtent0,
  406. Vector2<Real> const& center1, Vector2<Real> const axis1[2],
  407. Vector2<Real> const& sqrExtent1)
  408. {
  409. Vector2<Real> rCenter, rAxis[2], rSqrExtent;
  410. rCenter = { center0[0], center0[1] };
  411. rAxis[0] = { axis0[0][0], axis0[0][1] };
  412. rAxis[1] = { axis0[1][0], axis0[1][1] };
  413. rSqrExtent = { sqrExtent0[0], sqrExtent0[1] };
  414. ToCoefficients(rCenter, rAxis, rSqrExtent, mA);
  415. rCenter = { center1[0], center1[1] };
  416. rAxis[0] = { axis1[0][0], axis1[0][1] };
  417. rAxis[1] = { axis1[1][0], axis1[1][1] };
  418. rSqrExtent = { sqrExtent1[0], sqrExtent1[1] };
  419. ToCoefficients(rCenter, rAxis, rSqrExtent, mB);
  420. Result result;
  421. DoRootFinding(result);
  422. return result;
  423. }
  424. // Compute the area of intersection of ellipses.
  425. struct AreaResult
  426. {
  427. // The configuration of the two ellipses.
  428. enum
  429. {
  430. ELLIPSES_ARE_EQUAL,
  431. ELLIPSES_ARE_SEPARATED,
  432. E0_CONTAINS_E1,
  433. E1_CONTAINS_E0,
  434. ONE_CHORD_REGION,
  435. FOUR_CHORD_REGION
  436. };
  437. // One of the enumerates, determined in the call to AreaDispatch.
  438. int configuration;
  439. // Information about the ellipse-ellipse intersection points.
  440. Result findResult;
  441. // The area of intersection of the ellipses.
  442. Real area;
  443. };
  444. // The ellipse axes are already normalized, which most likely
  445. // introduced rounding errors.
  446. AreaResult AreaOfIntersection(Ellipse2<Real> const& ellipse0,
  447. Ellipse2<Real> const& ellipse1)
  448. {
  449. EllipseInfo E0;
  450. E0.center = ellipse0.center;
  451. E0.axis = ellipse0.axis;
  452. E0.extent = ellipse0.extent;
  453. E0.sqrExtent = ellipse0.extent * ellipse0.extent;
  454. FinishEllipseInfo(E0);
  455. EllipseInfo E1;
  456. E1.center = ellipse1.center;
  457. E1.axis = ellipse1.axis;
  458. E1.extent = ellipse1.extent;
  459. E1.sqrExtent = ellipse1.extent * ellipse0.extent;
  460. FinishEllipseInfo(E1);
  461. AreaResult ar;
  462. ar.configuration = 0;
  463. ar.findResult = operator()(ellipse0, ellipse1);
  464. ar.area = mZero;
  465. AreaDispatch(E0, E1, ar);
  466. return ar;
  467. }
  468. // The axis directions do not have to be unit length. The positive
  469. // definite matrices are constructed according to the details of the
  470. // PDF documentabout the intersection of ellipses.
  471. AreaResult AreaOfIntersection(Vector2<Real> const& center0,
  472. Vector2<Real> const axis0[2], Vector2<Real> const& sqrExtent0,
  473. Vector2<Real> const& center1, Vector2<Real> const axis1[2],
  474. Vector2<Real> const& sqrExtent1)
  475. {
  476. EllipseInfo E0;
  477. E0.center = center0;
  478. E0.axis = { axis0[0], axis0[1] };
  479. E0.extent =
  480. {
  481. std::sqrt(sqrExtent0[0]),
  482. std::sqrt(sqrExtent0[1])
  483. };
  484. E0.sqrExtent = sqrExtent0;
  485. FinishEllipseInfo(E0);
  486. EllipseInfo E1;
  487. E1.center = center1;
  488. E1.axis = { axis1[0], axis1[1] };
  489. E1.extent =
  490. {
  491. std::sqrt(sqrExtent1[0]),
  492. std::sqrt(sqrExtent1[1])
  493. };
  494. E1.sqrExtent = sqrExtent1;
  495. FinishEllipseInfo(E1);
  496. AreaResult ar;
  497. ar.configuration = 0;
  498. ar.findResult = operator()(center0, axis0, sqrExtent0, center1, axis1, sqrExtent1);
  499. ar.area = mZero;
  500. AreaDispatch(E0, E1, ar);
  501. return ar;
  502. }
  503. private:
  504. // Compute the coefficients of the quadratic equation but with the
  505. // y^2-coefficient of 1.
  506. void ToCoefficients(Vector2<Real> const& center, Vector2<Real> const axis[2],
  507. Vector2<Real> const& sqrExtent, std::array<Real, 5>& coeff)
  508. {
  509. Real denom0 = Dot(axis[0], axis[0]) * sqrExtent[0];
  510. Real denom1 = Dot(axis[1], axis[1]) * sqrExtent[1];
  511. Matrix2x2<Real> outer0 = OuterProduct(axis[0], axis[0]);
  512. Matrix2x2<Real> outer1 = OuterProduct(axis[1], axis[1]);
  513. Matrix2x2<Real> A = outer0 / denom0 + outer1 / denom1;
  514. Vector2<Real> product = A * center;
  515. Vector2<Real> B = -mTwo * product;
  516. Real const& denom = A(1, 1);
  517. coeff[0] = (Dot(center, product) - mOne) / denom;
  518. coeff[1] = B[0] / denom;
  519. coeff[2] = B[1] / denom;
  520. coeff[3] = A(0, 0) / denom;
  521. coeff[4] = mTwo * A(0, 1) / denom;
  522. // coeff[5] = A(1, 1) / denom = 1;
  523. }
  524. void DoRootFinding(Result& result)
  525. {
  526. bool allZero = true;
  527. for (int i = 0; i < 5; ++i)
  528. {
  529. mD[i] = mA[i] - mB[i];
  530. if (mD[i] != mZero)
  531. {
  532. allZero = false;
  533. }
  534. }
  535. if (allZero)
  536. {
  537. result.intersect = false;
  538. result.numPoints = std::numeric_limits<int>::max();
  539. return;
  540. }
  541. result.numPoints = 0;
  542. mA2Div2 = mA[2] / mTwo;
  543. mA4Div2 = mA[4] / mTwo;
  544. mC[0] = mA[0] - mA2Div2 * mA2Div2;
  545. mC[1] = mA[1] - mA2Div2 * mA[4];
  546. mC[2] = mA[3] - mA4Div2 * mA4Div2; // c[2] > 0
  547. mE[0] = mD[0] - mA2Div2 * mD[2];
  548. mE[1] = mD[1] - mA2Div2 * mD[4] - mA4Div2 * mD[2];
  549. mE[2] = mD[3] - mA4Div2 * mD[4];
  550. if (mD[4] != mZero)
  551. {
  552. Real xbar = -mD[2] / mD[4];
  553. Real ebar = mE[0] + xbar * (mE[1] + xbar * mE[2]);
  554. if (ebar != mZero)
  555. {
  556. D4NotZeroEBarNotZero(result);
  557. }
  558. else
  559. {
  560. D4NotZeroEBarZero(xbar, result);
  561. }
  562. }
  563. else if (mD[2] != mZero) // d[4] = 0
  564. {
  565. if (mE[2] != mZero)
  566. {
  567. D4ZeroD2NotZeroE2NotZero(result);
  568. }
  569. else
  570. {
  571. D4ZeroD2NotZeroE2Zero(result);
  572. }
  573. }
  574. else // d[2] = d[4] = 0
  575. {
  576. D4ZeroD2Zero(result);
  577. }
  578. result.intersect = (result.numPoints > 0);
  579. }
  580. void D4NotZeroEBarNotZero(Result& result)
  581. {
  582. // The graph of w = -e(x)/d(x) is a hyperbola.
  583. Real d2d2 = mD[2] * mD[2], d2d4 = mD[2] * mD[4], d4d4 = mD[4] * mD[4];
  584. Real e0e0 = mE[0] * mE[0], e0e1 = mE[0] * mE[1], e0e2 = mE[0] * mE[2];
  585. Real e1e1 = mE[1] * mE[1], e1e2 = mE[1] * mE[2], e2e2 = mE[2] * mE[2];
  586. std::array<Real, 5> f =
  587. {
  588. mC[0] * d2d2 + e0e0,
  589. mC[1] * d2d2 + mTwo * (mC[0] * d2d4 + e0e1),
  590. mC[2] * d2d2 + mC[0] * d4d4 + e1e1 + mTwo * (mC[1] * d2d4 + e0e2),
  591. mC[1] * d4d4 + mTwo * (mC[2] * d2d4 + e1e2),
  592. mC[2] * d4d4 + e2e2 // > 0
  593. };
  594. std::map<Real, int> rmMap;
  595. RootsPolynomial<Real>::template SolveQuartic<Real>(f[0], f[1], f[2],
  596. f[3], f[4], rmMap);
  597. // xbar cannot be a root of f(x), so d(x) != 0 and we can solve
  598. // directly for w = -e(x)/d(x).
  599. for (auto const& rm : rmMap)
  600. {
  601. Real const& x = rm.first;
  602. Real w = -(mE[0] + x * (mE[1] + x * mE[2])) / (mD[2] + mD[4] * x);
  603. Real y = w - (mA2Div2 + x * mA4Div2);
  604. result.points[result.numPoints] = { x, y };
  605. result.isTransverse[result.numPoints++] = (rm.second == 1);
  606. }
  607. }
  608. void D4NotZeroEBarZero(Real const& xbar, Result& result)
  609. {
  610. // Factor e(x) = (d2 + d4*x)*(h0 + h1*x). The w-equation has
  611. // two solution components, x = xbar and w = -(h0 + h1*x).
  612. Real translate, w, y;
  613. // Compute intersection of x = xbar with ellipse.
  614. Real ncbar = -(mC[0] + xbar * (mC[1] + xbar * mC[2]));
  615. if (ncbar >= mZero)
  616. {
  617. translate = mA2Div2 + xbar * mA4Div2;
  618. w = std::sqrt(ncbar);
  619. y = w - translate;
  620. result.points[result.numPoints] = { xbar, y };
  621. if (w > mZero)
  622. {
  623. result.isTransverse[result.numPoints++] = true;
  624. w = -w;
  625. y = w - translate;
  626. result.points[result.numPoints] = { xbar, y };
  627. result.isTransverse[result.numPoints++] = true;
  628. }
  629. else
  630. {
  631. result.isTransverse[result.numPoints++] = false;
  632. }
  633. }
  634. // Compute intersections of w = -(h0 + h1*x) with ellipse.
  635. std::array<Real, 2> h;
  636. h[1] = mE[2] / mD[4];
  637. h[0] = (mE[1] - mD[2] * h[1]) / mD[4];
  638. std::array<Real, 3> f =
  639. {
  640. mC[0] + h[0] * h[0],
  641. mC[1] + mTwo * h[0] * h[1],
  642. mC[2] + h[1] * h[1] // > 0
  643. };
  644. std::map<Real, int> rmMap;
  645. RootsPolynomial<Real>::template SolveQuadratic<Real>(f[0], f[1], f[2], rmMap);
  646. for (auto const& rm : rmMap)
  647. {
  648. Real const& x = rm.first;
  649. translate = mA2Div2 + x * mA4Div2;
  650. w = -(h[0] + x * h[1]);
  651. y = w - translate;
  652. result.points[result.numPoints] = { x, y };
  653. result.isTransverse[result.numPoints++] = (rm.second == 1);
  654. }
  655. }
  656. void D4ZeroD2NotZeroE2NotZero(Result& result)
  657. {
  658. Real d2d2 = mD[2] * mD[2];
  659. std::array<Real, 5> f =
  660. {
  661. mC[0] * d2d2 + mE[0] * mE[0],
  662. mC[1] * d2d2 + mTwo * mE[0] * mE[1],
  663. mC[2] * d2d2 + mE[1] * mE[1] + mTwo * mE[0] * mE[2],
  664. mTwo * mE[1] * mE[2],
  665. mE[2] * mE[2] // > 0
  666. };
  667. std::map<Real, int> rmMap;
  668. RootsPolynomial<Real>::template SolveQuartic<Real>(f[0], f[1], f[2], f[3],
  669. f[4], rmMap);
  670. for (auto const& rm : rmMap)
  671. {
  672. Real const& x = rm.first;
  673. Real translate = mA2Div2 + x * mA4Div2;
  674. Real w = -(mE[0] + x * (mE[1] + x * mE[2])) / mD[2];
  675. Real y = w - translate;
  676. result.points[result.numPoints] = { x, y };
  677. result.isTransverse[result.numPoints++] = (rm.second == 1);
  678. }
  679. }
  680. void D4ZeroD2NotZeroE2Zero(Result& result)
  681. {
  682. Real d2d2 = mD[2] * mD[2];
  683. std::array<Real, 3> f =
  684. {
  685. mC[0] * d2d2 + mE[0] * mE[0],
  686. mC[1] * d2d2 + mTwo * mE[0] * mE[1],
  687. mC[2] * d2d2 + mE[1] * mE[1]
  688. };
  689. std::map<Real, int> rmMap;
  690. RootsPolynomial<Real>::template SolveQuadratic<Real>(f[0], f[1], f[2], rmMap);
  691. for (auto const& rm : rmMap)
  692. {
  693. Real const& x = rm.first;
  694. Real translate = mA2Div2 + x * mA4Div2;
  695. Real w = -(mE[0] + x * mE[1]) / mD[2];
  696. Real y = w - translate;
  697. result.points[result.numPoints] = { x, y };
  698. result.isTransverse[result.numPoints++] = (rm.second == 1);
  699. }
  700. }
  701. void D4ZeroD2Zero(Result& result)
  702. {
  703. // e(x) cannot be identically zero, because if it were, then all
  704. // d[i] = 0. But we tested that case previously and exited.
  705. if (mE[2] != mZero)
  706. {
  707. // Make e(x) monic, f(x) = e(x)/e2 = x^2 + (e1/e2)*x + (e0/e2)
  708. // = x^2 + f1*x + f0.
  709. std::array<Real, 2> f = { mE[0] / mE[2], mE[1] / mE[2] };
  710. Real mid = -f[1] / mTwo;
  711. Real discr = mid * mid - f[0];
  712. if (discr > mZero)
  713. {
  714. // The theoretical roots of e(x) are
  715. // x = -f1/2 + s*sqrt(discr) where s in {-1,+1}. For each
  716. // root, determine exactly the sign of c(x). We need
  717. // c(x) <= 0 in order to solve for w^2 = -c(x). At the
  718. // root,
  719. // c(x) = c0 + c1*x + c2*x^2 = c0 + c1*x - c2*(f0 + f1*x)
  720. // = (c0 - c2*f0) + (c1 - c2*f1)*x
  721. // = g0 + g1*x
  722. // We need g0 + g1*x <= 0.
  723. Real sqrtDiscr = std::sqrt(discr);
  724. std::array<Real, 2> g =
  725. {
  726. mC[0] - mC[2] * f[0],
  727. mC[1] - mC[2] * f[1]
  728. };
  729. if (g[1] > mZero)
  730. {
  731. // We need s*sqrt(discr) <= -g[0]/g[1] + f1/2.
  732. Real r = -g[0] / g[1] - mid;
  733. // s = +1:
  734. if (r >= mZero)
  735. {
  736. Real rsqr = r * r;
  737. if (discr < rsqr)
  738. {
  739. SpecialIntersection(mid + sqrtDiscr, true, result);
  740. }
  741. else if (discr == rsqr)
  742. {
  743. SpecialIntersection(mid + sqrtDiscr, false, result);
  744. }
  745. }
  746. // s = -1:
  747. if (r > mZero)
  748. {
  749. SpecialIntersection(mid - sqrtDiscr, true, result);
  750. }
  751. else
  752. {
  753. Real rsqr = r * r;
  754. if (discr > rsqr)
  755. {
  756. SpecialIntersection(mid - sqrtDiscr, true, result);
  757. }
  758. else if (discr == rsqr)
  759. {
  760. SpecialIntersection(mid - sqrtDiscr, false, result);
  761. }
  762. }
  763. }
  764. else if (g[1] < mZero)
  765. {
  766. // We need s*sqrt(discr) >= -g[0]/g[1] + f1/2.
  767. Real r = -g[0] / g[1] - mid;
  768. // s = -1:
  769. if (r <= mZero)
  770. {
  771. Real rsqr = r * r;
  772. if (discr < rsqr)
  773. {
  774. SpecialIntersection(mid - sqrtDiscr, true, result);
  775. }
  776. else
  777. {
  778. SpecialIntersection(mid - sqrtDiscr, false, result);
  779. }
  780. }
  781. // s = +1:
  782. if (r < mZero)
  783. {
  784. SpecialIntersection(mid + sqrtDiscr, true, result);
  785. }
  786. else
  787. {
  788. Real rsqr = r * r;
  789. if (discr > rsqr)
  790. {
  791. SpecialIntersection(mid + sqrtDiscr, true, result);
  792. }
  793. else if (discr == rsqr)
  794. {
  795. SpecialIntersection(mid + sqrtDiscr, false, result);
  796. }
  797. }
  798. }
  799. else // g[1] = 0
  800. {
  801. // The graphs of c(x) and f(x) are parabolas of the
  802. // same shape. One is a vertical translation of the
  803. // other.
  804. if (g[0] < mZero)
  805. {
  806. // The graph of f(x) is above that of c(x).
  807. SpecialIntersection(mid - sqrtDiscr, true, result);
  808. SpecialIntersection(mid + sqrtDiscr, true, result);
  809. }
  810. else if (g[0] == mZero)
  811. {
  812. // The graphs of c(x) and f(x) are the same parabola.
  813. SpecialIntersection(mid - sqrtDiscr, false, result);
  814. SpecialIntersection(mid + sqrtDiscr, false, result);
  815. }
  816. }
  817. }
  818. else if (discr == mZero)
  819. {
  820. // The theoretical root of f(x) is x = -f1/2.
  821. Real nchat = -(mC[0] + mid * (mC[1] + mid * mC[2]));
  822. if (nchat > mZero)
  823. {
  824. SpecialIntersection(mid, true, result);
  825. }
  826. else if (nchat == mZero)
  827. {
  828. SpecialIntersection(mid, false, result);
  829. }
  830. }
  831. }
  832. else if (mE[1] != mZero)
  833. {
  834. Real xhat = -mE[0] / mE[1];
  835. Real nchat = -(mC[0] + xhat * (mC[1] + xhat * mC[2]));
  836. if (nchat > mZero)
  837. {
  838. SpecialIntersection(xhat, true, result);
  839. }
  840. else if (nchat == mZero)
  841. {
  842. SpecialIntersection(xhat, false, result);
  843. }
  844. }
  845. }
  846. // Helper function for D4ZeroD2Zero.
  847. void SpecialIntersection(Real const& x, bool transverse, Result& result)
  848. {
  849. if (transverse)
  850. {
  851. Real translate = mA2Div2 + x * mA4Div2;
  852. Real nc = -(mC[0] + x * (mC[1] + x * mC[2]));
  853. if (nc < mZero)
  854. {
  855. // Clamp to eliminate the rounding error, but duplicate
  856. // the point because we know that it is a transverse
  857. // intersection.
  858. nc = mZero;
  859. }
  860. Real w = std::sqrt(nc);
  861. Real y = w - translate;
  862. result.points[result.numPoints] = { x, y };
  863. result.isTransverse[result.numPoints++] = true;
  864. w = -w;
  865. y = w - translate;
  866. result.points[result.numPoints] = { x, y };
  867. result.isTransverse[result.numPoints++] = true;
  868. }
  869. else
  870. {
  871. // The vertical line at the root is tangent to the ellipse.
  872. Real y = -(mA2Div2 + x * mA4Div2); // w = 0
  873. result.points[result.numPoints] = { x, y };
  874. result.isTransverse[result.numPoints++] = false;
  875. }
  876. }
  877. // Helper functions for AreaOfIntersection.
  878. struct EllipseInfo
  879. {
  880. Vector2<Real> center;
  881. std::array<Vector2<Real>, 2> axis;
  882. Vector2<Real> extent, sqrExtent;
  883. Matrix2x2<Real> M;
  884. Real AB; // extent[0] * extent[1]
  885. Real halfAB; // extent[0] * extent[1] / 2
  886. Real BpA; // extent[1] + extent[0]
  887. Real BmA; // extent[1] - extent[0]
  888. };
  889. // The axis, extent and sqrExtent members of E must be set before
  890. // this function is called.
  891. void FinishEllipseInfo(EllipseInfo& E)
  892. {
  893. E.M = OuterProduct(E.axis[0], E.axis[0]) /
  894. (E.sqrExtent[0] * Dot(E.axis[0], E.axis[0]));
  895. E.M += OuterProduct(E.axis[1], E.axis[1]) /
  896. (E.sqrExtent[1] * Dot(E.axis[1], E.axis[1]));
  897. E.AB = E.extent[0] * E.extent[1];
  898. E.halfAB = E.AB / mTwo;
  899. E.BpA = E.extent[1] + E.extent[0];
  900. E.BmA = E.extent[1] - E.extent[0];
  901. }
  902. void AreaDispatch(EllipseInfo const& E0, EllipseInfo const& E1, AreaResult& ar)
  903. {
  904. if (ar.findResult.intersect)
  905. {
  906. if (ar.findResult.numPoints == 1)
  907. {
  908. // Containment or separation.
  909. AreaCS(E0, E1, ar);
  910. }
  911. else if (ar.findResult.numPoints == 2)
  912. {
  913. if (ar.findResult.isTransverse[0])
  914. {
  915. // Both intersection points are transverse.
  916. Area2(E0, E1, 0, 1, ar);
  917. }
  918. else
  919. {
  920. // Both intersection points are tangential, so one
  921. // ellipse is contained in the other.
  922. AreaCS(E0, E1, ar);
  923. }
  924. }
  925. else if (ar.findResult.numPoints == 3)
  926. {
  927. // The tangential intersection is irrelevant in the area
  928. // computation.
  929. if (!ar.findResult.isTransverse[0])
  930. {
  931. Area2(E0, E1, 1, 2, ar);
  932. }
  933. else if (!ar.findResult.isTransverse[1])
  934. {
  935. Area2(E0, E1, 2, 0, ar);
  936. }
  937. else // ar.findResult.isTransverse[2] == false
  938. {
  939. Area2(E0, E1, 0, 1, ar);
  940. }
  941. }
  942. else // ar.findResult.numPoints == 4
  943. {
  944. Area4(E0, E1, ar);
  945. }
  946. }
  947. else
  948. {
  949. // Containment, separation, or same ellipse.
  950. AreaCS(E0, E1, ar);
  951. }
  952. }
  953. void AreaCS(EllipseInfo const& E0, EllipseInfo const& E1, AreaResult& ar)
  954. {
  955. if (ar.findResult.numPoints <= 1)
  956. {
  957. Vector2<Real> diff = E0.center - E1.center;
  958. Real qform0 = Dot(diff, E0.M * diff);
  959. Real qform1 = Dot(diff, E1.M * diff);
  960. if (qform0 > mOne && qform1 > mOne)
  961. {
  962. // Each ellipse center is outside the other ellipse, so
  963. // the ellipses are separated (numPoints == 0) or outside
  964. // each other and just touching (numPoints == 1).
  965. ar.configuration = AreaResult::ELLIPSES_ARE_SEPARATED;
  966. ar.area = mZero;
  967. }
  968. else
  969. {
  970. // One ellipse is inside the other. Determine this
  971. // indirectly by comparing areas.
  972. if (E0.AB < E1.AB)
  973. {
  974. ar.configuration = AreaResult::E1_CONTAINS_E0;
  975. ar.area = mPi * E0.AB;
  976. }
  977. else
  978. {
  979. ar.configuration = AreaResult::E0_CONTAINS_E1;
  980. ar.area = mPi * E1.AB;
  981. }
  982. }
  983. }
  984. else
  985. {
  986. ar.configuration = AreaResult::ELLIPSES_ARE_EQUAL;
  987. ar.area = mPi * E0.AB;
  988. }
  989. }
  990. void Area2(EllipseInfo const& E0, EllipseInfo const& E1, int i0, int i1, AreaResult& ar)
  991. {
  992. ar.configuration = AreaResult::ONE_CHORD_REGION;
  993. // The endpoints of the chord.
  994. Vector2<Real> const& P0 = ar.findResult.points[i0];
  995. Vector2<Real> const& P1 = ar.findResult.points[i1];
  996. // Compute locations relative to the ellipses.
  997. Vector2<Real> P0mC0 = P0 - E0.center, P0mC1 = P0 - E1.center;
  998. Vector2<Real> P1mC0 = P1 - E0.center, P1mC1 = P1 - E1.center;
  999. // Compute the ellipse normal vectors at endpoint P0. This is
  1000. // sufficient information to determine chord endpoint order.
  1001. Vector2<Real> N0 = E0.M * P0mC0, N1 = E1.M * P0mC1;
  1002. Real dotperp = DotPerp(N1, N0);
  1003. // Choose the endpoint order for the chord region associated
  1004. // with E0.
  1005. if (dotperp > mZero)
  1006. {
  1007. // The chord order for E0 is <P0,P1> and for E1 is <P1,P0>.
  1008. ar.area =
  1009. ComputeAreaChordRegion(E0, P0mC0, P1mC0) +
  1010. ComputeAreaChordRegion(E1, P1mC1, P0mC1);
  1011. }
  1012. else
  1013. {
  1014. // The chord order for E0 is <P1,P0> and for E1 is <P0,P1>.
  1015. ar.area =
  1016. ComputeAreaChordRegion(E0, P1mC0, P0mC0) +
  1017. ComputeAreaChordRegion(E1, P0mC1, P1mC1);
  1018. }
  1019. }
  1020. void Area4(EllipseInfo const& E0, EllipseInfo const& E1, AreaResult& ar)
  1021. {
  1022. ar.configuration = AreaResult::FOUR_CHORD_REGION;
  1023. // Select a counterclockwise ordering of the points of
  1024. // intersection. Use the polar coordinates for E0 to do this.
  1025. // The multimap is used in the event that computing the
  1026. // intersections involved numerical rounding errors that lead to
  1027. // a duplicate intersection, even though the intersections are all
  1028. // labeled as transverse. [See the comment in the function
  1029. // SpecialIntersection.]
  1030. std::multimap<Real, int> ordering;
  1031. int i;
  1032. for (i = 0; i < 4; ++i)
  1033. {
  1034. Vector2<Real> PmC = ar.findResult.points[i] - E0.center;
  1035. Real x = Dot(E0.axis[0], PmC);
  1036. Real y = Dot(E0.axis[1], PmC);
  1037. Real theta = std::atan2(y, x);
  1038. ordering.insert(std::make_pair(theta, i));
  1039. }
  1040. std::array<int, 4> permute;
  1041. i = 0;
  1042. for (auto const& element : ordering)
  1043. {
  1044. permute[i++] = element.second;
  1045. }
  1046. // Start with the area of the convex quadrilateral.
  1047. Vector2<Real> diag20 =
  1048. ar.findResult.points[permute[2]] - ar.findResult.points[permute[0]];
  1049. Vector2<Real> diag31 =
  1050. ar.findResult.points[permute[3]] - ar.findResult.points[permute[1]];
  1051. ar.area = std::fabs(DotPerp(diag20, diag31)) / mTwo;
  1052. // Visit each pair of consecutive points. The selection of
  1053. // ellipse for the chord-region area calculation uses the "most
  1054. // counterclockwise" tangent vector.
  1055. for (int i0 = 3, i1 = 0; i1 < 4; i0 = i1++)
  1056. {
  1057. // Get a pair of consecutive points.
  1058. Vector2<Real> const& P0 = ar.findResult.points[permute[i0]];
  1059. Vector2<Real> const& P1 = ar.findResult.points[permute[i1]];
  1060. // Compute locations relative to the ellipses.
  1061. Vector2<Real> P0mC0 = P0 - E0.center, P0mC1 = P0 - E1.center;
  1062. Vector2<Real> P1mC0 = P1 - E0.center, P1mC1 = P1 - E1.center;
  1063. // Compute the ellipse normal vectors at endpoint P0.
  1064. Vector2<Real> N0 = E0.M * P0mC0, N1 = E1.M * P0mC1;
  1065. Real dotperp = DotPerp(N1, N0);
  1066. if (dotperp > mZero)
  1067. {
  1068. // The chord goes with ellipse E0.
  1069. ar.area += ComputeAreaChordRegion(E0, P0mC0, P1mC0);
  1070. }
  1071. else
  1072. {
  1073. // The chord goes with ellipse E1.
  1074. ar.area += ComputeAreaChordRegion(E1, P0mC1, P1mC1);
  1075. }
  1076. }
  1077. }
  1078. Real ComputeAreaChordRegion(EllipseInfo const& E, Vector2<Real> const& P0mC, Vector2<Real> const& P1mC)
  1079. {
  1080. // Compute polar coordinates for P0 and P1 on the ellipse.
  1081. Real x0 = Dot(E.axis[0], P0mC);
  1082. Real y0 = Dot(E.axis[1], P0mC);
  1083. Real theta0 = std::atan2(y0, x0);
  1084. Real x1 = Dot(E.axis[0], P1mC);
  1085. Real y1 = Dot(E.axis[1], P1mC);
  1086. Real theta1 = std::atan2(y1, x1);
  1087. // The arc straddles the atan2 discontinuity on the negative
  1088. // x-axis. Wrap the second angle to be larger than the first
  1089. // angle.
  1090. if (theta1 < theta0)
  1091. {
  1092. theta1 += mTwoPi;
  1093. }
  1094. // Compute the area portion of the sector due to the triangle.
  1095. Real triArea = std::fabs(DotPerp(P0mC, P1mC)) / mTwo;
  1096. // Compute the chord region area.
  1097. Real dtheta = theta1 - theta0;
  1098. Real F0, F1, sectorArea;
  1099. if (dtheta <= mPi)
  1100. {
  1101. // Use the area formula directly.
  1102. // area(theta0,theta1) = F(theta1)-F(theta0)-area(triangle)
  1103. F0 = ComputeIntegral(E, theta0);
  1104. F1 = ComputeIntegral(E, theta1);
  1105. sectorArea = F1 - F0;
  1106. return sectorArea - triArea;
  1107. }
  1108. else
  1109. {
  1110. // The angle of the elliptical sector is larger than pi
  1111. // radians. Use the area formula
  1112. // area(theta0,theta1) = pi*a*b - area(theta1,theta0)
  1113. theta0 += mTwoPi; // ensure theta0 > theta1
  1114. F0 = ComputeIntegral(E, theta0);
  1115. F1 = ComputeIntegral(E, theta1);
  1116. sectorArea = F0 - F1;
  1117. return mPi * E.AB - (sectorArea - triArea);
  1118. }
  1119. }
  1120. Real ComputeIntegral(EllipseInfo const& E, Real const& theta)
  1121. {
  1122. Real twoTheta = mTwo * theta;
  1123. Real sn = std::sin(twoTheta);
  1124. Real cs = std::cos(twoTheta);
  1125. Real arg = E.BmA * sn / (E.BpA + E.BmA * cs);
  1126. return E.halfAB * (theta - std::atan(arg));
  1127. }
  1128. // Constants that are set up once (optimization for rational
  1129. // arithmetic).
  1130. Real mZero, mOne, mTwo, mPi, mTwoPi;
  1131. // Various polynomial coefficients. The short names are meant to
  1132. // match the variable names used in the PDF documentation.
  1133. std::array<Real, 5> mA, mB, mD, mF;
  1134. std::array<Real, 3> mC, mE;
  1135. Real mA2Div2, mA4Div2;
  1136. };
  1137. // Template aliases for convenience.
  1138. template <typename Real>
  1139. using TIEllipses2 = TIQuery<Real, Ellipse2<Real>, Ellipse2<Real>>;
  1140. template <typename Real>
  1141. using FIEllipses2 = FIQuery<Real, Ellipse2<Real>, Ellipse2<Real>>;
  1142. }