123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- #pragma once
- #include <Mathematics/Matrix3x3.h>
- #include <random>
- namespace WwiseGTE
- {
- template <typename Real>
- class ContEllipsoid3MinCR
- {
- public:
- void operator()(int numPoints, Vector3<Real> const* points,
- Vector3<Real> const& C, Matrix3x3<Real> const& R, Real D[3]) const
- {
-
-
- std::vector<Vector3<Real>> A(numPoints);
- for (int i = 0; i < numPoints; ++i)
- {
- Vector3<Real> diff = points[i] - C;
- Vector3<Real> prod = diff * R;
- A[i] = prod * prod;
- }
-
-
-
- MaxProduct(A, D);
- }
- private:
- void FindEdgeMax(std::vector<Vector3<Real>>& A, int& plane0, int& plane1, Real D[3]) const
- {
-
-
- Real xDir = A[plane0][1] * A[plane1][2] - A[plane1][1] * A[plane0][2];
- Real yDir = A[plane0][2] * A[plane1][0] - A[plane1][2] * A[plane0][0];
- Real zDir = A[plane0][0] * A[plane1][1] - A[plane1][0] * A[plane0][1];
-
- Real a0 = D[0] * D[1] * zDir + D[0] * D[2] * yDir + D[1] * D[2] * xDir;
- Real a1 = (Real)2 * (D[2] * xDir * yDir + D[1] * xDir * zDir + D[0] * yDir * zDir);
- Real a2 = (Real)3 * (xDir * yDir * zDir);
-
- Real tFinal;
- if (a2 != (Real)0)
- {
- Real invA2 = (Real)1 / a2;
- Real discr = a1 * a1 - (Real)4 * a0 * a2;
- discr = std::sqrt(std::max(discr, (Real)0));
- tFinal = (Real)-0.5 * (a1 + discr) * invA2;
- if (a1 + (Real)2 * a2 * tFinal > (Real)0)
- {
- tFinal = (Real)0.5 * (-a1 + discr) * invA2;
- }
- }
- else if (a1 != (Real)0)
- {
- tFinal = -a0 / a1;
- }
- else if (a0 != (Real)0)
- {
- Real fmax = std::numeric_limits<Real>::max();
- tFinal = (a0 >= (Real)0 ? fmax : -fmax);
- }
- else
- {
- return;
- }
- if (tFinal < (Real)0)
- {
-
- tFinal = -tFinal;
- xDir = -xDir;
- yDir = -yDir;
- zDir = -zDir;
- }
-
-
- Real tMax = tFinal;
- int plane2 = -1;
- int numPoints = static_cast<int>(A.size());
- for (int i = 0; i < numPoints; ++i)
- {
- if (i == plane0 || i == plane1)
- {
- continue;
- }
- Real norDotDir = A[i][0] * xDir + A[i][1] * yDir + A[i][2] * zDir;
- if (norDotDir <= (Real)0)
- {
- continue;
- }
-
-
-
-
-
- Real numer = (Real)1 - A[i][0] * D[0] - A[i][1] * D[1] - A[i][2] * D[2];
- LogAssert(numer >= (Real)0, "Unexpected condition.");
- Real t = numer / norDotDir;
- if (0 <= t && t < tMax)
- {
- plane2 = i;
- tMax = t;
- }
- }
- D[0] += tMax * xDir;
- D[1] += tMax * yDir;
- D[2] += tMax * zDir;
- if (tMax == tFinal)
- {
- return;
- }
- if (tMax > (Real)0)
- {
- plane0 = plane2;
- FindFacetMax(A, plane0, D);
- return;
- }
-
- }
- void FindFacetMax(std::vector<Vector3<Real>>& A, int& plane0, Real D[3]) const
- {
- Real tFinal, xDir, yDir, zDir;
- if (A[plane0][0] > (Real)0
- && A[plane0][1] > (Real)0
- && A[plane0][2] > (Real)0)
- {
-
- Real oneThird = (Real)1 / (Real)3;
- Real xMax = oneThird / A[plane0][0];
- Real yMax = oneThird / A[plane0][1];
- Real zMax = oneThird / A[plane0][2];
-
- tFinal = (Real)1;
- xDir = xMax - D[0];
- yDir = yMax - D[1];
- zDir = zMax - D[2];
- }
- else
- {
- tFinal = std::numeric_limits<Real>::max();
- if (A[plane0][0] > (Real)0)
- {
- xDir = (Real)0;
- }
- else
- {
- xDir = (Real)1;
- }
- if (A[plane0][1] > (Real)0)
- {
- yDir = (Real)0;
- }
- else
- {
- yDir = (Real)1;
- }
- if (A[plane0][2] > (Real)0)
- {
- zDir = (Real)0;
- }
- else
- {
- zDir = (Real)1;
- }
- }
-
- Real tMax = tFinal;
- int plane1 = -1;
- int numPoints = static_cast<int>(A.size());
- for (int i = 0; i < numPoints; ++i)
- {
- if (i == plane0)
- {
- continue;
- }
- Real norDotDir = A[i][0] * xDir + A[i][1] * yDir + A[i][2] * zDir;
- if (norDotDir <= (Real)0)
- {
- continue;
- }
-
-
-
-
-
- Real numer = (Real)1 - A[i][0] * D[0] - A[i][1] * D[1] - A[i][2] * D[2];
- LogAssert(numer >= (Real)0, "Unexpected condition.");
- Real t = numer / norDotDir;
- if (0 <= t && t < tMax)
- {
- plane1 = i;
- tMax = t;
- }
- }
- D[0] += tMax * xDir;
- D[1] += tMax * yDir;
- D[2] += tMax * zDir;
- if (tMax == (Real)1)
- {
- return;
- }
- if (tMax > (Real)0)
- {
- plane0 = plane1;
- FindFacetMax(A, plane0, D);
- return;
- }
- FindEdgeMax(A, plane0, plane1, D);
- }
- void MaxProduct(std::vector<Vector3<Real>>& A, Real D[3]) const
- {
-
-
-
-
-
-
- std::mt19937 mte;
- std::uniform_real_distribution<Real> rnd((Real)0, (Real)1);
- Real maxJitter = (Real)1e-12;
- int numPoints = static_cast<int>(A.size());
- int i;
- for (i = 0; i < numPoints; ++i)
- {
- A[i][0] += maxJitter * rnd(mte);
- A[i][1] += maxJitter * rnd(mte);
- A[i][2] += maxJitter * rnd(mte);
- }
-
- int plane = -1;
- Real zmax = (Real)0;
- for (i = 0; i < numPoints; ++i)
- {
- if (A[i][2] > zmax)
- {
- zmax = A[i][2];
- plane = i;
- }
- }
- LogAssert(plane != -1, "Unexpected condition.");
-
- D[0] = (Real)0;
- D[1] = (Real)0;
- D[2] = (Real)1 / zmax;
- FindFacetMax(A, plane, D);
- }
- };
- }
|