1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249 |
- #pragma once
- #include <Mathematics/Logger.h>
- #include <Mathematics/FIQuery.h>
- #include <Mathematics/TIQuery.h>
- #include <Mathematics/Hyperellipsoid.h>
- #include <Mathematics/RootsBisection.h>
- #include <Mathematics/RootsPolynomial.h>
- #include <Mathematics/SymmetricEigensolver2x2.h>
- #include <Mathematics/Matrix2x2.h>
- namespace WwiseGTE
- {
- template <typename Real>
- class TIQuery<Real, Ellipse2<Real>, Ellipse2<Real>>
- {
- public:
-
-
- enum
- {
- ELLIPSES_SEPARATED,
- ELLIPSES_OVERLAP,
- ELLIPSE0_OUTSIDE_ELLIPSE1_BUT_TANGENT,
- ELLIPSE0_STRICTLY_CONTAINS_ELLIPSE1,
- ELLIPSE0_CONTAINS_ELLIPSE1_BUT_TANGENT,
- ELLIPSE1_STRICTLY_CONTAINS_ELLIPSE0,
- ELLIPSE1_CONTAINS_ELLIPSE0_BUT_TANGENT,
- ELLIPSES_EQUAL
- };
-
-
- int operator()(Ellipse2<Real> const& ellipse0, Ellipse2<Real> const& ellipse1)
- {
- Real const zero = 0, one = 1;
-
- Vector2<Real> K0 = ellipse0.center;
- Matrix2x2<Real> R0;
- R0.SetCol(0, ellipse0.axis[0]);
- R0.SetCol(1, ellipse0.axis[1]);
- Matrix2x2<Real> D0{
- one / (ellipse0.extent[0] * ellipse0.extent[0]), zero,
- zero, one / (ellipse0.extent[1] * ellipse0.extent[1]) };
-
- Vector2<Real> K1 = ellipse1.center;
- Matrix2x2<Real> R1;
- R1.SetCol(0, ellipse1.axis[0]);
- R1.SetCol(1, ellipse1.axis[1]);
- Matrix2x2<Real> D1{
- one / (ellipse1.extent[0] * ellipse1.extent[0]), zero,
- zero, one / (ellipse1.extent[1] * ellipse1.extent[1]) };
-
- Matrix2x2<Real> D0NegHalf{
- ellipse0.extent[0], zero,
- zero, ellipse0.extent[1] };
- Matrix2x2<Real> D0Half{
- one / ellipse0.extent[0], zero,
- zero, one / ellipse0.extent[1] };
- Vector2<Real> K2 = D0Half * ((K1 - K0) * R0);
-
- Matrix2x2<Real> R1TR0D0NegHalf = MultiplyATB(R1, R0 * D0NegHalf);
- Matrix2x2<Real> M2 = MultiplyATB(R1TR0D0NegHalf, D1) * R1TR0D0NegHalf;
-
- SymmetricEigensolver2x2<Real> es;
- std::array<Real, 2> D;
- std::array<std::array<Real, 2>, 2> evec;
- es(M2(0, 0), M2(0, 1), M2(1, 1), +1, D, evec);
- Matrix2x2<Real> R;
- R.SetCol(0, evec[0]);
- R.SetCol(1, evec[1]);
-
- Vector2<Real> K = K2 * R;
-
-
-
-
-
-
- Real minSqrDistance = std::numeric_limits<Real>::max();
- Real maxSqrDistance = zero;
- if (K == Vector2<Real>::Zero())
- {
-
-
-
- for (int i = 0; i < 2; ++i)
- {
- Real invD = one / D[i];
- if (invD < minSqrDistance)
- {
- minSqrDistance = invD;
- }
- if (invD > maxSqrDistance)
- {
- maxSqrDistance = invD;
- }
- }
- return Classify(minSqrDistance, maxSqrDistance, zero);
- }
-
-
-
-
-
- Real d0 = D[0], d1 = D[1];
- Real c0 = K[0] * K[0], c1 = K[1] * K[1];
-
-
- std::vector<std::pair<Real, Real>> param(2);
- if (d0 >= d1)
- {
- param[0] = std::make_pair(d0, c0);
- param[1] = std::make_pair(d1, c1);
- }
- else
- {
- param[0] = std::make_pair(d1, c1);
- param[1] = std::make_pair(d0, c0);
- }
- std::vector<std::pair<Real, Real>> valid;
- valid.reserve(2);
- if (param[0].first > param[1].first)
- {
-
- for (int i = 0; i < 2; ++i)
- {
- if (param[i].second > zero)
- {
- valid.push_back(param[i]);
- }
- }
- }
- else
- {
-
- param[0].second += param[1].second;
- if (param[0].second > zero)
- {
- valid.push_back(param[0]);
- }
- }
- size_t numValid = valid.size();
- int numRoots = 0;
- Real roots[4];
- if (numValid == 2)
- {
- GetRoots(valid[0].first, valid[1].first, valid[0].second,
- valid[1].second, numRoots, roots);
- }
- else if (numValid == 1)
- {
- GetRoots(valid[0].first, valid[0].second, numRoots, roots);
- }
-
-
- for (int i = 0; i < numRoots; ++i)
- {
- Real s = roots[i];
- Real p0 = d0 * K[0] * s / (d0 * s - (Real)1);
- Real p1 = d1 * K[1] * s / (d1 * s - (Real)1);
- Real sqrDistance = p0 * p0 + p1 * p1;
- if (sqrDistance < minSqrDistance)
- {
- minSqrDistance = sqrDistance;
- }
- if (sqrDistance > maxSqrDistance)
- {
- maxSqrDistance = sqrDistance;
- }
- }
- return Classify(minSqrDistance, maxSqrDistance, d0 * c0 + d1 * c1);
- }
- private:
- void GetRoots(Real d0, Real c0, int& numRoots, Real* roots)
- {
-
- Real const one = (Real)1;
- Real temp = std::sqrt(d0 * c0);
- Real inv = one / d0;
- numRoots = 2;
- roots[0] = (one - temp) * inv;
- roots[1] = (one + temp) * inv;
- }
- void GetRoots(Real d0, Real d1, Real c0, Real c1, int& numRoots, Real* roots)
- {
-
- Real const zero = 0, one = (Real)1;
- Real d0c0 = d0 * c0;
- Real d1c1 = d1 * c1;
- Real sum = d0c0 + d1c1;
- Real sqrtsum = std::sqrt(sum);
- std::function<Real(Real)> F = [&one, d0, d1, d0c0, d1c1](Real s)
- {
- Real invN0 = one / (d0 * s - one);
- Real invN1 = one / (d1 * s - one);
- Real term0 = d0c0 * invN0 * invN0;
- Real term1 = d1c1 * invN1 * invN1;
- Real f = term0 + term1 - one;
- return f;
- };
- std::function<Real(Real)> DF = [&one, d0, d1, d0c0, d1c1](Real s)
- {
- Real const two = 2;
- Real invN0 = one / (d0 * s - one);
- Real invN1 = one / (d1 * s - one);
- Real term0 = d0 * d0c0 * invN0 * invN0 * invN0;
- Real term1 = d1 * d1c1 * invN1 * invN1 * invN1;
- Real df = -two * (term0 + term1);
- return df;
- };
- unsigned int const maxIterations = static_cast<unsigned int>(
- 3 + std::numeric_limits<Real>::digits -
- std::numeric_limits<Real>::min_exponent);
- unsigned int iterations;
- numRoots = 0;
- Real invD0 = one / d0;
- Real invD1 = one / d1;
- Real smin, smax, s, fval;
-
-
- smax = invD0;
- fval = sum - one;
- if (fval > zero)
- {
- smin = (one - sqrtsum) * invD1;
- fval = F(smin);
- LogAssert(fval <= zero, "Unexpected condition.");
- }
- else
- {
- smin = zero;
- }
- iterations = RootsBisection<Real>::Find(F, smin, smax, -one, one,
- maxIterations, s);
- fval = F(s);
- LogAssert(iterations > 0, "Unexpected condition.");
- roots[numRoots++] = s;
-
-
-
-
-
-
-
-
-
- Real const oneThird = (Real)1 / (Real)3;
- Real rho = std::pow(d0 * d0c0 / (d1 * d1c1), oneThird);
- Real smid = (one + rho) / (d0 + rho * d1);
- Real fmid = F(smid);
- if (fmid <= zero)
- {
-
-
- iterations = RootsBisection<Real>::Find(F, invD0, smid, one, -one,
- maxIterations, s);
- fval = F(s);
- LogAssert(iterations > 0, "Unexpected condition.");
- roots[numRoots++] = s;
- iterations = RootsBisection<Real>::Find(F, smid, invD1, -one, one,
- maxIterations, s);
- fval = F(s);
- LogAssert(iterations > 0, "Unexpected condition.");
- roots[numRoots++] = s;
- }
- else if (fmid == zero)
- {
- roots[numRoots++] = smid;
- }
-
-
- smin = invD1;
- smax = (one + sqrtsum) * invD1;
- fval = F(smax);
- LogAssert(fval <= zero, "Unexpected condition.");
- iterations = RootsBisection<Real>::Find(F, smin, smax, one, -one,
- maxIterations, s);
- fval = F(s);
- LogAssert(iterations > 0, "Unexpected condition.");
- roots[numRoots++] = s;
- }
- int Classify(Real minSqrDistance, Real maxSqrDistance, Real d0c0pd1c1)
- {
- Real const one = (Real)1;
- if (maxSqrDistance < one)
- {
- return ELLIPSE0_STRICTLY_CONTAINS_ELLIPSE1;
- }
- else if (maxSqrDistance > one)
- {
- if (minSqrDistance < one)
- {
- return ELLIPSES_OVERLAP;
- }
- else if (minSqrDistance > one)
- {
- if (d0c0pd1c1 > one)
- {
- return ELLIPSES_SEPARATED;
- }
- else
- {
- return ELLIPSE1_STRICTLY_CONTAINS_ELLIPSE0;
- }
- }
- else
- {
- if (d0c0pd1c1 > one)
- {
- return ELLIPSE0_OUTSIDE_ELLIPSE1_BUT_TANGENT;
- }
- else
- {
- return ELLIPSE1_CONTAINS_ELLIPSE0_BUT_TANGENT;
- }
- }
- }
- else
- {
- if (minSqrDistance < one)
- {
- return ELLIPSE0_CONTAINS_ELLIPSE1_BUT_TANGENT;
- }
- else
- {
- return ELLIPSES_EQUAL;
- }
- }
- }
- };
- template <typename Real>
- class FIQuery<Real, Ellipse2<Real>, Ellipse2<Real>>
- {
- public:
-
-
- FIQuery()
- :
- mZero((Real)0),
- mOne((Real)1),
- mTwo((Real)2),
- mPi((Real)GTE_C_PI),
- mTwoPi((Real)GTE_C_TWO_PI)
- {
- }
- struct Result
- {
-
-
- bool intersect;
-
-
-
-
- int numPoints;
- std::array<Vector2<Real>, 4> points;
- std::array<bool, 4> isTransverse;
- };
-
-
- Result operator()(Ellipse2<Real> const& ellipse0, Ellipse2<Real> const& ellipse1)
- {
- Vector2<Real> rCenter, rAxis[2], rSqrExtent;
- rCenter = { ellipse0.center[0], ellipse0.center[1] };
- rAxis[0] = { ellipse0.axis[0][0], ellipse0.axis[0][1] };
- rAxis[1] = { ellipse0.axis[1][0], ellipse0.axis[1][1] };
- rSqrExtent =
- {
- ellipse0.extent[0] * ellipse0.extent[0],
- ellipse0.extent[1] * ellipse0.extent[1]
- };
- ToCoefficients(rCenter, rAxis, rSqrExtent, mA);
- rCenter = { ellipse1.center[0], ellipse1.center[1] };
- rAxis[0] = { ellipse1.axis[0][0], ellipse1.axis[0][1] };
- rAxis[1] = { ellipse1.axis[1][0], ellipse1.axis[1][1] };
- rSqrExtent =
- {
- ellipse1.extent[0] * ellipse1.extent[0],
- ellipse1.extent[1] * ellipse1.extent[1]
- };
- ToCoefficients(rCenter, rAxis, rSqrExtent, mB);
- Result result;
- DoRootFinding(result);
- return result;
- }
-
-
-
- Result operator()(Vector2<Real> const& center0,
- Vector2<Real> const axis0[2], Vector2<Real> const& sqrExtent0,
- Vector2<Real> const& center1, Vector2<Real> const axis1[2],
- Vector2<Real> const& sqrExtent1)
- {
- Vector2<Real> rCenter, rAxis[2], rSqrExtent;
- rCenter = { center0[0], center0[1] };
- rAxis[0] = { axis0[0][0], axis0[0][1] };
- rAxis[1] = { axis0[1][0], axis0[1][1] };
- rSqrExtent = { sqrExtent0[0], sqrExtent0[1] };
- ToCoefficients(rCenter, rAxis, rSqrExtent, mA);
- rCenter = { center1[0], center1[1] };
- rAxis[0] = { axis1[0][0], axis1[0][1] };
- rAxis[1] = { axis1[1][0], axis1[1][1] };
- rSqrExtent = { sqrExtent1[0], sqrExtent1[1] };
- ToCoefficients(rCenter, rAxis, rSqrExtent, mB);
- Result result;
- DoRootFinding(result);
- return result;
- }
-
- struct AreaResult
- {
-
- enum
- {
- ELLIPSES_ARE_EQUAL,
- ELLIPSES_ARE_SEPARATED,
- E0_CONTAINS_E1,
- E1_CONTAINS_E0,
- ONE_CHORD_REGION,
- FOUR_CHORD_REGION
- };
-
- int configuration;
-
- Result findResult;
-
- Real area;
- };
-
-
- AreaResult AreaOfIntersection(Ellipse2<Real> const& ellipse0,
- Ellipse2<Real> const& ellipse1)
- {
- EllipseInfo E0;
- E0.center = ellipse0.center;
- E0.axis = ellipse0.axis;
- E0.extent = ellipse0.extent;
- E0.sqrExtent = ellipse0.extent * ellipse0.extent;
- FinishEllipseInfo(E0);
- EllipseInfo E1;
- E1.center = ellipse1.center;
- E1.axis = ellipse1.axis;
- E1.extent = ellipse1.extent;
- E1.sqrExtent = ellipse1.extent * ellipse0.extent;
- FinishEllipseInfo(E1);
- AreaResult ar;
- ar.configuration = 0;
- ar.findResult = operator()(ellipse0, ellipse1);
- ar.area = mZero;
- AreaDispatch(E0, E1, ar);
- return ar;
- }
-
-
-
- AreaResult AreaOfIntersection(Vector2<Real> const& center0,
- Vector2<Real> const axis0[2], Vector2<Real> const& sqrExtent0,
- Vector2<Real> const& center1, Vector2<Real> const axis1[2],
- Vector2<Real> const& sqrExtent1)
- {
- EllipseInfo E0;
- E0.center = center0;
- E0.axis = { axis0[0], axis0[1] };
- E0.extent =
- {
- std::sqrt(sqrExtent0[0]),
- std::sqrt(sqrExtent0[1])
- };
- E0.sqrExtent = sqrExtent0;
- FinishEllipseInfo(E0);
- EllipseInfo E1;
- E1.center = center1;
- E1.axis = { axis1[0], axis1[1] };
- E1.extent =
- {
- std::sqrt(sqrExtent1[0]),
- std::sqrt(sqrExtent1[1])
- };
- E1.sqrExtent = sqrExtent1;
- FinishEllipseInfo(E1);
- AreaResult ar;
- ar.configuration = 0;
- ar.findResult = operator()(center0, axis0, sqrExtent0, center1, axis1, sqrExtent1);
- ar.area = mZero;
- AreaDispatch(E0, E1, ar);
- return ar;
- }
- private:
-
-
- void ToCoefficients(Vector2<Real> const& center, Vector2<Real> const axis[2],
- Vector2<Real> const& sqrExtent, std::array<Real, 5>& coeff)
- {
- Real denom0 = Dot(axis[0], axis[0]) * sqrExtent[0];
- Real denom1 = Dot(axis[1], axis[1]) * sqrExtent[1];
- Matrix2x2<Real> outer0 = OuterProduct(axis[0], axis[0]);
- Matrix2x2<Real> outer1 = OuterProduct(axis[1], axis[1]);
- Matrix2x2<Real> A = outer0 / denom0 + outer1 / denom1;
- Vector2<Real> product = A * center;
- Vector2<Real> B = -mTwo * product;
- Real const& denom = A(1, 1);
- coeff[0] = (Dot(center, product) - mOne) / denom;
- coeff[1] = B[0] / denom;
- coeff[2] = B[1] / denom;
- coeff[3] = A(0, 0) / denom;
- coeff[4] = mTwo * A(0, 1) / denom;
-
- }
- void DoRootFinding(Result& result)
- {
- bool allZero = true;
- for (int i = 0; i < 5; ++i)
- {
- mD[i] = mA[i] - mB[i];
- if (mD[i] != mZero)
- {
- allZero = false;
- }
- }
- if (allZero)
- {
- result.intersect = false;
- result.numPoints = std::numeric_limits<int>::max();
- return;
- }
- result.numPoints = 0;
- mA2Div2 = mA[2] / mTwo;
- mA4Div2 = mA[4] / mTwo;
- mC[0] = mA[0] - mA2Div2 * mA2Div2;
- mC[1] = mA[1] - mA2Div2 * mA[4];
- mC[2] = mA[3] - mA4Div2 * mA4Div2;
- mE[0] = mD[0] - mA2Div2 * mD[2];
- mE[1] = mD[1] - mA2Div2 * mD[4] - mA4Div2 * mD[2];
- mE[2] = mD[3] - mA4Div2 * mD[4];
- if (mD[4] != mZero)
- {
- Real xbar = -mD[2] / mD[4];
- Real ebar = mE[0] + xbar * (mE[1] + xbar * mE[2]);
- if (ebar != mZero)
- {
- D4NotZeroEBarNotZero(result);
- }
- else
- {
- D4NotZeroEBarZero(xbar, result);
- }
- }
- else if (mD[2] != mZero)
- {
- if (mE[2] != mZero)
- {
- D4ZeroD2NotZeroE2NotZero(result);
- }
- else
- {
- D4ZeroD2NotZeroE2Zero(result);
- }
- }
- else
- {
- D4ZeroD2Zero(result);
- }
- result.intersect = (result.numPoints > 0);
- }
- void D4NotZeroEBarNotZero(Result& result)
- {
-
- Real d2d2 = mD[2] * mD[2], d2d4 = mD[2] * mD[4], d4d4 = mD[4] * mD[4];
- Real e0e0 = mE[0] * mE[0], e0e1 = mE[0] * mE[1], e0e2 = mE[0] * mE[2];
- Real e1e1 = mE[1] * mE[1], e1e2 = mE[1] * mE[2], e2e2 = mE[2] * mE[2];
- std::array<Real, 5> f =
- {
- mC[0] * d2d2 + e0e0,
- mC[1] * d2d2 + mTwo * (mC[0] * d2d4 + e0e1),
- mC[2] * d2d2 + mC[0] * d4d4 + e1e1 + mTwo * (mC[1] * d2d4 + e0e2),
- mC[1] * d4d4 + mTwo * (mC[2] * d2d4 + e1e2),
- mC[2] * d4d4 + e2e2
- };
- std::map<Real, int> rmMap;
- RootsPolynomial<Real>::template SolveQuartic<Real>(f[0], f[1], f[2],
- f[3], f[4], rmMap);
-
-
- for (auto const& rm : rmMap)
- {
- Real const& x = rm.first;
- Real w = -(mE[0] + x * (mE[1] + x * mE[2])) / (mD[2] + mD[4] * x);
- Real y = w - (mA2Div2 + x * mA4Div2);
- result.points[result.numPoints] = { x, y };
- result.isTransverse[result.numPoints++] = (rm.second == 1);
- }
- }
- void D4NotZeroEBarZero(Real const& xbar, Result& result)
- {
-
-
- Real translate, w, y;
-
- Real ncbar = -(mC[0] + xbar * (mC[1] + xbar * mC[2]));
- if (ncbar >= mZero)
- {
- translate = mA2Div2 + xbar * mA4Div2;
- w = std::sqrt(ncbar);
- y = w - translate;
- result.points[result.numPoints] = { xbar, y };
- if (w > mZero)
- {
- result.isTransverse[result.numPoints++] = true;
- w = -w;
- y = w - translate;
- result.points[result.numPoints] = { xbar, y };
- result.isTransverse[result.numPoints++] = true;
- }
- else
- {
- result.isTransverse[result.numPoints++] = false;
- }
- }
-
- std::array<Real, 2> h;
- h[1] = mE[2] / mD[4];
- h[0] = (mE[1] - mD[2] * h[1]) / mD[4];
- std::array<Real, 3> f =
- {
- mC[0] + h[0] * h[0],
- mC[1] + mTwo * h[0] * h[1],
- mC[2] + h[1] * h[1]
- };
- std::map<Real, int> rmMap;
- RootsPolynomial<Real>::template SolveQuadratic<Real>(f[0], f[1], f[2], rmMap);
- for (auto const& rm : rmMap)
- {
- Real const& x = rm.first;
- translate = mA2Div2 + x * mA4Div2;
- w = -(h[0] + x * h[1]);
- y = w - translate;
- result.points[result.numPoints] = { x, y };
- result.isTransverse[result.numPoints++] = (rm.second == 1);
- }
- }
- void D4ZeroD2NotZeroE2NotZero(Result& result)
- {
- Real d2d2 = mD[2] * mD[2];
- std::array<Real, 5> f =
- {
- mC[0] * d2d2 + mE[0] * mE[0],
- mC[1] * d2d2 + mTwo * mE[0] * mE[1],
- mC[2] * d2d2 + mE[1] * mE[1] + mTwo * mE[0] * mE[2],
- mTwo * mE[1] * mE[2],
- mE[2] * mE[2]
- };
- std::map<Real, int> rmMap;
- RootsPolynomial<Real>::template SolveQuartic<Real>(f[0], f[1], f[2], f[3],
- f[4], rmMap);
- for (auto const& rm : rmMap)
- {
- Real const& x = rm.first;
- Real translate = mA2Div2 + x * mA4Div2;
- Real w = -(mE[0] + x * (mE[1] + x * mE[2])) / mD[2];
- Real y = w - translate;
- result.points[result.numPoints] = { x, y };
- result.isTransverse[result.numPoints++] = (rm.second == 1);
- }
- }
- void D4ZeroD2NotZeroE2Zero(Result& result)
- {
- Real d2d2 = mD[2] * mD[2];
- std::array<Real, 3> f =
- {
- mC[0] * d2d2 + mE[0] * mE[0],
- mC[1] * d2d2 + mTwo * mE[0] * mE[1],
- mC[2] * d2d2 + mE[1] * mE[1]
- };
- std::map<Real, int> rmMap;
- RootsPolynomial<Real>::template SolveQuadratic<Real>(f[0], f[1], f[2], rmMap);
- for (auto const& rm : rmMap)
- {
- Real const& x = rm.first;
- Real translate = mA2Div2 + x * mA4Div2;
- Real w = -(mE[0] + x * mE[1]) / mD[2];
- Real y = w - translate;
- result.points[result.numPoints] = { x, y };
- result.isTransverse[result.numPoints++] = (rm.second == 1);
- }
- }
- void D4ZeroD2Zero(Result& result)
- {
-
-
- if (mE[2] != mZero)
- {
-
-
- std::array<Real, 2> f = { mE[0] / mE[2], mE[1] / mE[2] };
- Real mid = -f[1] / mTwo;
- Real discr = mid * mid - f[0];
- if (discr > mZero)
- {
-
-
-
-
-
-
-
-
-
- Real sqrtDiscr = std::sqrt(discr);
- std::array<Real, 2> g =
- {
- mC[0] - mC[2] * f[0],
- mC[1] - mC[2] * f[1]
- };
- if (g[1] > mZero)
- {
-
- Real r = -g[0] / g[1] - mid;
-
- if (r >= mZero)
- {
- Real rsqr = r * r;
- if (discr < rsqr)
- {
- SpecialIntersection(mid + sqrtDiscr, true, result);
- }
- else if (discr == rsqr)
- {
- SpecialIntersection(mid + sqrtDiscr, false, result);
- }
- }
-
- if (r > mZero)
- {
- SpecialIntersection(mid - sqrtDiscr, true, result);
- }
- else
- {
- Real rsqr = r * r;
- if (discr > rsqr)
- {
- SpecialIntersection(mid - sqrtDiscr, true, result);
- }
- else if (discr == rsqr)
- {
- SpecialIntersection(mid - sqrtDiscr, false, result);
- }
- }
- }
- else if (g[1] < mZero)
- {
-
- Real r = -g[0] / g[1] - mid;
-
- if (r <= mZero)
- {
- Real rsqr = r * r;
- if (discr < rsqr)
- {
- SpecialIntersection(mid - sqrtDiscr, true, result);
- }
- else
- {
- SpecialIntersection(mid - sqrtDiscr, false, result);
- }
- }
-
- if (r < mZero)
- {
- SpecialIntersection(mid + sqrtDiscr, true, result);
- }
- else
- {
- Real rsqr = r * r;
- if (discr > rsqr)
- {
- SpecialIntersection(mid + sqrtDiscr, true, result);
- }
- else if (discr == rsqr)
- {
- SpecialIntersection(mid + sqrtDiscr, false, result);
- }
- }
- }
- else
- {
-
-
-
- if (g[0] < mZero)
- {
-
- SpecialIntersection(mid - sqrtDiscr, true, result);
- SpecialIntersection(mid + sqrtDiscr, true, result);
- }
- else if (g[0] == mZero)
- {
-
- SpecialIntersection(mid - sqrtDiscr, false, result);
- SpecialIntersection(mid + sqrtDiscr, false, result);
- }
- }
- }
- else if (discr == mZero)
- {
-
- Real nchat = -(mC[0] + mid * (mC[1] + mid * mC[2]));
- if (nchat > mZero)
- {
- SpecialIntersection(mid, true, result);
- }
- else if (nchat == mZero)
- {
- SpecialIntersection(mid, false, result);
- }
- }
- }
- else if (mE[1] != mZero)
- {
- Real xhat = -mE[0] / mE[1];
- Real nchat = -(mC[0] + xhat * (mC[1] + xhat * mC[2]));
- if (nchat > mZero)
- {
- SpecialIntersection(xhat, true, result);
- }
- else if (nchat == mZero)
- {
- SpecialIntersection(xhat, false, result);
- }
- }
- }
-
- void SpecialIntersection(Real const& x, bool transverse, Result& result)
- {
- if (transverse)
- {
- Real translate = mA2Div2 + x * mA4Div2;
- Real nc = -(mC[0] + x * (mC[1] + x * mC[2]));
- if (nc < mZero)
- {
-
-
-
- nc = mZero;
- }
- Real w = std::sqrt(nc);
- Real y = w - translate;
- result.points[result.numPoints] = { x, y };
- result.isTransverse[result.numPoints++] = true;
- w = -w;
- y = w - translate;
- result.points[result.numPoints] = { x, y };
- result.isTransverse[result.numPoints++] = true;
- }
- else
- {
-
- Real y = -(mA2Div2 + x * mA4Div2);
- result.points[result.numPoints] = { x, y };
- result.isTransverse[result.numPoints++] = false;
- }
- }
-
- struct EllipseInfo
- {
- Vector2<Real> center;
- std::array<Vector2<Real>, 2> axis;
- Vector2<Real> extent, sqrExtent;
- Matrix2x2<Real> M;
- Real AB;
- Real halfAB;
- Real BpA;
- Real BmA;
- };
-
-
- void FinishEllipseInfo(EllipseInfo& E)
- {
- E.M = OuterProduct(E.axis[0], E.axis[0]) /
- (E.sqrExtent[0] * Dot(E.axis[0], E.axis[0]));
- E.M += OuterProduct(E.axis[1], E.axis[1]) /
- (E.sqrExtent[1] * Dot(E.axis[1], E.axis[1]));
- E.AB = E.extent[0] * E.extent[1];
- E.halfAB = E.AB / mTwo;
- E.BpA = E.extent[1] + E.extent[0];
- E.BmA = E.extent[1] - E.extent[0];
- }
- void AreaDispatch(EllipseInfo const& E0, EllipseInfo const& E1, AreaResult& ar)
- {
- if (ar.findResult.intersect)
- {
- if (ar.findResult.numPoints == 1)
- {
-
- AreaCS(E0, E1, ar);
- }
- else if (ar.findResult.numPoints == 2)
- {
- if (ar.findResult.isTransverse[0])
- {
-
- Area2(E0, E1, 0, 1, ar);
- }
- else
- {
-
-
- AreaCS(E0, E1, ar);
- }
- }
- else if (ar.findResult.numPoints == 3)
- {
-
-
- if (!ar.findResult.isTransverse[0])
- {
- Area2(E0, E1, 1, 2, ar);
- }
- else if (!ar.findResult.isTransverse[1])
- {
- Area2(E0, E1, 2, 0, ar);
- }
- else
- {
- Area2(E0, E1, 0, 1, ar);
- }
- }
- else
- {
- Area4(E0, E1, ar);
- }
- }
- else
- {
-
- AreaCS(E0, E1, ar);
- }
- }
- void AreaCS(EllipseInfo const& E0, EllipseInfo const& E1, AreaResult& ar)
- {
- if (ar.findResult.numPoints <= 1)
- {
- Vector2<Real> diff = E0.center - E1.center;
- Real qform0 = Dot(diff, E0.M * diff);
- Real qform1 = Dot(diff, E1.M * diff);
- if (qform0 > mOne && qform1 > mOne)
- {
-
-
-
- ar.configuration = AreaResult::ELLIPSES_ARE_SEPARATED;
- ar.area = mZero;
- }
- else
- {
-
-
- if (E0.AB < E1.AB)
- {
- ar.configuration = AreaResult::E1_CONTAINS_E0;
- ar.area = mPi * E0.AB;
- }
- else
- {
- ar.configuration = AreaResult::E0_CONTAINS_E1;
- ar.area = mPi * E1.AB;
- }
- }
- }
- else
- {
- ar.configuration = AreaResult::ELLIPSES_ARE_EQUAL;
- ar.area = mPi * E0.AB;
- }
- }
- void Area2(EllipseInfo const& E0, EllipseInfo const& E1, int i0, int i1, AreaResult& ar)
- {
- ar.configuration = AreaResult::ONE_CHORD_REGION;
-
- Vector2<Real> const& P0 = ar.findResult.points[i0];
- Vector2<Real> const& P1 = ar.findResult.points[i1];
-
- Vector2<Real> P0mC0 = P0 - E0.center, P0mC1 = P0 - E1.center;
- Vector2<Real> P1mC0 = P1 - E0.center, P1mC1 = P1 - E1.center;
-
-
- Vector2<Real> N0 = E0.M * P0mC0, N1 = E1.M * P0mC1;
- Real dotperp = DotPerp(N1, N0);
-
-
- if (dotperp > mZero)
- {
-
- ar.area =
- ComputeAreaChordRegion(E0, P0mC0, P1mC0) +
- ComputeAreaChordRegion(E1, P1mC1, P0mC1);
- }
- else
- {
-
- ar.area =
- ComputeAreaChordRegion(E0, P1mC0, P0mC0) +
- ComputeAreaChordRegion(E1, P0mC1, P1mC1);
- }
- }
- void Area4(EllipseInfo const& E0, EllipseInfo const& E1, AreaResult& ar)
- {
- ar.configuration = AreaResult::FOUR_CHORD_REGION;
-
-
-
-
-
-
-
- std::multimap<Real, int> ordering;
- int i;
- for (i = 0; i < 4; ++i)
- {
- Vector2<Real> PmC = ar.findResult.points[i] - E0.center;
- Real x = Dot(E0.axis[0], PmC);
- Real y = Dot(E0.axis[1], PmC);
- Real theta = std::atan2(y, x);
- ordering.insert(std::make_pair(theta, i));
- }
- std::array<int, 4> permute;
- i = 0;
- for (auto const& element : ordering)
- {
- permute[i++] = element.second;
- }
-
- Vector2<Real> diag20 =
- ar.findResult.points[permute[2]] - ar.findResult.points[permute[0]];
- Vector2<Real> diag31 =
- ar.findResult.points[permute[3]] - ar.findResult.points[permute[1]];
- ar.area = std::fabs(DotPerp(diag20, diag31)) / mTwo;
-
-
-
- for (int i0 = 3, i1 = 0; i1 < 4; i0 = i1++)
- {
- // Get a pair of consecutive points.
- Vector2<Real> const& P0 = ar.findResult.points[permute[i0]];
- Vector2<Real> const& P1 = ar.findResult.points[permute[i1]];
-
- Vector2<Real> P0mC0 = P0 - E0.center, P0mC1 = P0 - E1.center;
- Vector2<Real> P1mC0 = P1 - E0.center, P1mC1 = P1 - E1.center;
-
- Vector2<Real> N0 = E0.M * P0mC0, N1 = E1.M * P0mC1;
- Real dotperp = DotPerp(N1, N0);
- if (dotperp > mZero)
- {
-
- ar.area += ComputeAreaChordRegion(E0, P0mC0, P1mC0);
- }
- else
- {
-
- ar.area += ComputeAreaChordRegion(E1, P0mC1, P1mC1);
- }
- }
- }
- Real ComputeAreaChordRegion(EllipseInfo const& E, Vector2<Real> const& P0mC, Vector2<Real> const& P1mC)
- {
-
- Real x0 = Dot(E.axis[0], P0mC);
- Real y0 = Dot(E.axis[1], P0mC);
- Real theta0 = std::atan2(y0, x0);
- Real x1 = Dot(E.axis[0], P1mC);
- Real y1 = Dot(E.axis[1], P1mC);
- Real theta1 = std::atan2(y1, x1);
-
-
-
- if (theta1 < theta0)
- {
- theta1 += mTwoPi;
- }
-
- Real triArea = std::fabs(DotPerp(P0mC, P1mC)) / mTwo;
-
- Real dtheta = theta1 - theta0;
- Real F0, F1, sectorArea;
- if (dtheta <= mPi)
- {
-
-
- F0 = ComputeIntegral(E, theta0);
- F1 = ComputeIntegral(E, theta1);
- sectorArea = F1 - F0;
- return sectorArea - triArea;
- }
- else
- {
-
-
-
- theta0 += mTwoPi;
- F0 = ComputeIntegral(E, theta0);
- F1 = ComputeIntegral(E, theta1);
- sectorArea = F0 - F1;
- return mPi * E.AB - (sectorArea - triArea);
- }
- }
- Real ComputeIntegral(EllipseInfo const& E, Real const& theta)
- {
- Real twoTheta = mTwo * theta;
- Real sn = std::sin(twoTheta);
- Real cs = std::cos(twoTheta);
- Real arg = E.BmA * sn / (E.BpA + E.BmA * cs);
- return E.halfAB * (theta - std::atan(arg));
- }
-
-
- Real mZero, mOne, mTwo, mPi, mTwoPi;
-
-
- std::array<Real, 5> mA, mB, mD, mF;
- std::array<Real, 3> mC, mE;
- Real mA2Div2, mA4Div2;
- };
-
- template <typename Real>
- using TIEllipses2 = TIQuery<Real, Ellipse2<Real>, Ellipse2<Real>>;
- template <typename Real>
- using FIEllipses2 = FIQuery<Real, Ellipse2<Real>, Ellipse2<Real>>;
- }
|