123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443 |
- #pragma once
- #include <Mathematics/Logger.h>
- #include <Mathematics/ContCircle2.h>
- #include <Mathematics/Hypersphere.h>
- #include <Mathematics/LinearSystem.h>
- #include <functional>
- #include <random>
- namespace WwiseGTE
- {
- template <typename InputType, typename ComputeType>
- class MinimumAreaCircle2
- {
- public:
- bool operator()(int numPoints, Vector2<InputType> const* points, Circle2<InputType>& minimal)
- {
- if (numPoints >= 1 && points)
- {
-
- std::function<UpdateResult(int)> update[4];
- update[1] = [this](int i) { return UpdateSupport1(i); };
- update[2] = [this](int i) { return UpdateSupport2(i); };
- update[3] = [this](int i) { return UpdateSupport3(i); };
-
- std::vector<int> permuted(numPoints);
- for (int i = 0; i < numPoints; ++i)
- {
- permuted[i] = i;
- }
- std::sort(permuted.begin(), permuted.end(),
- [points](int i0, int i1) { return points[i0] < points[i1]; });
- auto end = std::unique(permuted.begin(), permuted.end(),
- [points](int i0, int i1) { return points[i0] == points[i1]; });
- permuted.erase(end, permuted.end());
- numPoints = static_cast<int>(permuted.size());
-
- std::shuffle(permuted.begin(), permuted.end(), mDRE);
-
-
- mComputePoints.resize(numPoints);
- for (int i = 0; i < numPoints; ++i)
- {
- for (int j = 0; j < 2; ++j)
- {
- mComputePoints[i][j] = points[permuted[i]][j];
- }
- }
-
- Circle2<ComputeType> ctMinimal = ExactCircle1(0);
- mNumSupport = 1;
- mSupport[0] = 0;
-
-
-
-
-
-
-
-
-
-
- for (int i = 1 % numPoints, n = 0; i != n; i = (i + 1) % numPoints)
- {
- if (!SupportContains(i))
- {
- if (!Contains(i, ctMinimal))
- {
- auto result = update[mNumSupport](i);
- if (result.second == true)
- {
- if (result.first.radius > ctMinimal.radius)
- {
- ctMinimal = result.first;
- n = i;
- }
- }
- else
- {
-
-
-
-
-
-
- GetContainer(numPoints, points, minimal);
- mNumSupport = 0;
- mSupport.fill(0);
- return false;
- }
- }
- }
- }
- for (int j = 0; j < 2; ++j)
- {
- minimal.center[j] = static_cast<InputType>(ctMinimal.center[j]);
- }
- minimal.radius = static_cast<InputType>(ctMinimal.radius);
- minimal.radius = std::sqrt(minimal.radius);
- for (int i = 0; i < mNumSupport; ++i)
- {
- mSupport[i] = permuted[mSupport[i]];
- }
- return true;
- }
- else
- {
- LogError("Input must contain points.");
- }
- }
-
- inline int GetNumSupport() const
- {
- return mNumSupport;
- }
- inline std::array<int, 3> const& GetSupport() const
- {
- return mSupport;
- }
- private:
-
-
- bool Contains(int i, Circle2<ComputeType> const& circle) const
- {
-
-
-
- Vector2<ComputeType> diff = mComputePoints[i] - circle.center;
- return Dot(diff, diff) <= circle.radius;
- }
- Circle2<ComputeType> ExactCircle1(int i0) const
- {
- Circle2<ComputeType> minimal;
- minimal.center = mComputePoints[i0];
- minimal.radius = (ComputeType)0;
- return minimal;
- }
- Circle2<ComputeType> ExactCircle2(int i0, int i1) const
- {
- Vector2<ComputeType> const& P0 = mComputePoints[i0];
- Vector2<ComputeType> const& P1 = mComputePoints[i1];
- Vector2<ComputeType> diff = P1 - P0;
- Circle2<ComputeType> minimal;
- minimal.center = ((ComputeType)0.5)*(P0 + P1);
- minimal.radius = ((ComputeType)0.25)*Dot(diff, diff);
- return minimal;
- }
- Circle2<ComputeType> ExactCircle3(int i0, int i1, int i2) const
- {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Vector2<ComputeType> const& P0 = mComputePoints[i0];
- Vector2<ComputeType> const& P1 = mComputePoints[i1];
- Vector2<ComputeType> const& P2 = mComputePoints[i2];
- Vector2<ComputeType> E0 = P0 - P2;
- Vector2<ComputeType> E1 = P1 - P2;
- Matrix2x2<ComputeType> A;
- A(0, 0) = Dot(E0, E0);
- A(0, 1) = Dot(E0, E1);
- A(1, 0) = A(0, 1);
- A(1, 1) = Dot(E1, E1);
- ComputeType const half = (ComputeType)0.5;
- Vector2<ComputeType> B{ half * A(0, 0), half* A(1, 1) };
- Circle2<ComputeType> minimal;
- Vector2<ComputeType> X;
- if (LinearSystem<ComputeType>::Solve(A, B, X))
- {
- ComputeType x2 = (ComputeType)1 - X[0] - X[1];
- minimal.center = X[0] * P0 + X[1] * P1 + x2 * P2;
- Vector2<ComputeType> tmp = X[0] * E0 + X[1] * E1;
- minimal.radius = Dot(tmp, tmp);
- }
- else
- {
- minimal.center = Vector2<ComputeType>::Zero();
- minimal.radius = (ComputeType)std::numeric_limits<InputType>::max();
- }
- return minimal;
- }
- typedef std::pair<Circle2<ComputeType>, bool> UpdateResult;
- UpdateResult UpdateSupport1(int i)
- {
- Circle2<ComputeType> minimal = ExactCircle2(mSupport[0], i);
- mNumSupport = 2;
- mSupport[1] = i;
- return std::make_pair(minimal, true);
- }
- UpdateResult UpdateSupport2(int i)
- {
-
- int const numType2 = 2;
- int const type2[numType2][2] =
- {
- { 0, 1 },
- { 1, 0 }
- };
-
- int const numType3 = 1;
- Circle2<ComputeType> circle[numType2 + numType3];
- ComputeType minRSqr = (ComputeType)std::numeric_limits<InputType>::max();
- int iCircle = 0, iMinRSqr = -1;
- int k0, k1;
-
- for (int j = 0; j < numType2; ++j, ++iCircle)
- {
- k0 = mSupport[type2[j][0]];
- circle[iCircle] = ExactCircle2(k0, i);
- if (circle[iCircle].radius < minRSqr)
- {
- k1 = mSupport[type2[j][1]];
- if (Contains(k1, circle[iCircle]))
- {
- minRSqr = circle[iCircle].radius;
- iMinRSqr = iCircle;
- }
- }
- }
-
- k0 = mSupport[0];
- k1 = mSupport[1];
- circle[iCircle] = ExactCircle3(k0, k1, i);
- if (circle[iCircle].radius < minRSqr)
- {
- minRSqr = circle[iCircle].radius;
- iMinRSqr = iCircle;
- }
- switch (iMinRSqr)
- {
- case 0:
- mSupport[1] = i;
- break;
- case 1:
- mSupport[0] = i;
- break;
- case 2:
- mNumSupport = 3;
- mSupport[2] = i;
- break;
- case -1:
-
-
-
-
- return std::make_pair(Circle2<ComputeType>(), false);
- }
- return std::make_pair(circle[iMinRSqr], true);
- }
- UpdateResult UpdateSupport3(int i)
- {
-
- int const numType2 = 3;
- int const type2[numType2][3] =
- {
- { 0, 1, 2 },
- { 1, 0, 2 },
- { 2, 0, 1 }
- };
-
- int const numType3 = 3;
- int const type3[numType3][3] =
- {
- { 0, 1, 2 },
- { 0, 2, 1 },
- { 1, 2, 0 }
- };
- Circle2<ComputeType> circle[numType2 + numType3];
- ComputeType minRSqr = (ComputeType)std::numeric_limits<InputType>::max();
- int iCircle = 0, iMinRSqr = -1;
- int k0, k1, k2;
-
- for (int j = 0; j < numType2; ++j, ++iCircle)
- {
- k0 = mSupport[type2[j][0]];
- circle[iCircle] = ExactCircle2(k0, i);
- if (circle[iCircle].radius < minRSqr)
- {
- k1 = mSupport[type2[j][1]];
- k2 = mSupport[type2[j][2]];
- if (Contains(k1, circle[iCircle]) && Contains(k2, circle[iCircle]))
- {
- minRSqr = circle[iCircle].radius;
- iMinRSqr = iCircle;
- }
- }
- }
-
- for (int j = 0; j < numType3; ++j, ++iCircle)
- {
- k0 = mSupport[type3[j][0]];
- k1 = mSupport[type3[j][1]];
- circle[iCircle] = ExactCircle3(k0, k1, i);
- if (circle[iCircle].radius < minRSqr)
- {
- k2 = mSupport[type3[j][2]];
- if (Contains(k2, circle[iCircle]))
- {
- minRSqr = circle[iCircle].radius;
- iMinRSqr = iCircle;
- }
- }
- }
- switch (iMinRSqr)
- {
- case 0:
- mNumSupport = 2;
- mSupport[1] = i;
- break;
- case 1:
- mNumSupport = 2;
- mSupport[0] = i;
- break;
- case 2:
- mNumSupport = 2;
- mSupport[0] = mSupport[2];
- mSupport[1] = i;
- break;
- case 3:
- mSupport[2] = i;
- break;
- case 4:
- mSupport[1] = i;
- break;
- case 5:
- mSupport[0] = i;
- break;
- case -1:
-
-
-
-
- return std::make_pair(Circle2<ComputeType>(), false);
- }
- return std::make_pair(circle[iMinRSqr], true);
- }
-
- bool SupportContains(int j) const
- {
- for (int i = 0; i < mNumSupport; ++i)
- {
- if (j == mSupport[i])
- {
- return true;
- }
- }
- return false;
- }
- int mNumSupport;
- std::array<int, 3> mSupport;
-
-
- std::default_random_engine mDRE;
- std::vector<Vector2<ComputeType>> mComputePoints;
- };
- }
|