123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649 |
- #pragma once
- #include <Mathematics/OrientedBox.h>
- #include <Mathematics/ConvexHull2.h>
- namespace WwiseGTE
- {
- template <typename InputType, typename ComputeType>
- class MinimumAreaBox2
- {
- public:
-
-
- MinimumAreaBox2()
- :
- mNumPoints(0),
- mPoints(nullptr),
- mSupportIndices{ 0, 0, 0, 0 },
- mArea((InputType)0),
- mZero(0),
- mOne(1),
- mNegOne(-1),
- mHalf((InputType)0.5)
- {
- }
-
-
-
-
-
- OrientedBox2<InputType> operator()(int numPoints,
- Vector2<InputType> const* points,
- bool useRotatingCalipers = !std::is_floating_point<ComputeType>::value)
- {
- mNumPoints = numPoints;
- mPoints = points;
- mHull.clear();
-
- ConvexHull2<InputType, ComputeType> ch2;
- ch2(mNumPoints, mPoints, (InputType)0);
- int dimension = ch2.GetDimension();
- OrientedBox2<InputType> minBox;
- if (dimension == 0)
- {
-
-
- minBox.center = mPoints[0];
- minBox.axis[0] = Vector2<InputType>::Unit(0);
- minBox.axis[1] = Vector2<InputType>::Unit(1);
- minBox.extent[0] = (InputType)0;
- minBox.extent[1] = (InputType)0;
- mHull.resize(1);
- mHull[0] = 0;
- return minBox;
- }
- if (dimension == 1)
- {
-
-
-
-
- Line2<InputType> const& line = ch2.GetLine();
- InputType tmin = (InputType)0, tmax = (InputType)0;
- int imin = 0, imax = 0;
- for (int i = 0; i < mNumPoints; ++i)
- {
- Vector2<InputType> diff = mPoints[i] - line.origin;
- InputType t = Dot(diff, line.direction);
- if (t > tmax)
- {
- tmax = t;
- imax = i;
- }
- else if (t < tmin)
- {
- tmin = t;
- imin = i;
- }
- }
- minBox.center = line.origin + (InputType)0.5 * (tmin + tmax) * line.direction;
- minBox.extent[0] = (InputType)0.5 * (tmax - tmin);
- minBox.extent[1] = (InputType)0;
- minBox.axis[0] = line.direction;
- minBox.axis[1] = -Perp(line.direction);
- mHull.resize(2);
- mHull[0] = imin;
- mHull[1] = imax;
- return minBox;
- }
- mHull = ch2.GetHull();
- Vector2<ComputeType> const* queryPoints = ch2.GetQuery().GetVertices();
- std::vector<Vector2<ComputeType>> computePoints(mHull.size());
- for (size_t i = 0; i < mHull.size(); ++i)
- {
- computePoints[i] = queryPoints[mHull[i]];
- }
- RemoveCollinearPoints(computePoints);
- Box box;
- if (useRotatingCalipers)
- {
- box = ComputeBoxForEdgeOrderN(computePoints);
- }
- else
- {
- box = ComputeBoxForEdgeOrderNSqr(computePoints);
- }
- ConvertTo(box, computePoints, minBox);
- return minBox;
- }
-
-
-
-
-
- OrientedBox2<InputType> operator()(int numPoints,
- Vector2<InputType> const* points, int numIndices, int const* indices,
- bool useRotatingCalipers = !std::is_floating_point<ComputeType>::value)
- {
- mHull.clear();
- OrientedBox2<InputType> minBox;
- if (numPoints < 3 || !points || (indices && numIndices < 3))
- {
- minBox.center = Vector2<InputType>::Zero();
- minBox.axis[0] = Vector2<InputType>::Unit(0);
- minBox.axis[1] = Vector2<InputType>::Unit(1);
- minBox.extent = Vector2<InputType>::Zero();
- return minBox;
- }
- if (indices)
- {
- mHull.resize(numIndices);
- std::copy(indices, indices + numIndices, mHull.begin());
- }
- else
- {
- numIndices = numPoints;
- mHull.resize(numIndices);
- for (int i = 0; i < numIndices; ++i)
- {
- mHull[i] = i;
- }
- }
- std::vector<Vector2<ComputeType>> computePoints(numIndices);
- for (int i = 0; i < numIndices; ++i)
- {
- int h = mHull[i];
- computePoints[i][0] = (ComputeType)points[h][0];
- computePoints[i][1] = (ComputeType)points[h][1];
- }
- RemoveCollinearPoints(computePoints);
- Box box;
- if (useRotatingCalipers)
- {
- box = ComputeBoxForEdgeOrderN(computePoints);
- }
- else
- {
- box = ComputeBoxForEdgeOrderNSqr(computePoints);
- }
- ConvertTo(box, computePoints, minBox);
- return minBox;
- }
-
- inline int GetNumPoints() const
- {
- return mNumPoints;
- }
- inline Vector2<InputType> const* GetPoints() const
- {
- return mPoints;
- }
- inline std::vector<int> const& GetHull() const
- {
- return mHull;
- }
- inline std::array<int, 4> const& GetSupportIndices() const
- {
- return mSupportIndices;
- }
- inline InputType GetArea() const
- {
- return mArea;
- }
- private:
-
-
-
-
-
- struct Box
- {
- Vector2<ComputeType> U[2];
- std::array<int, 4> index;
- ComputeType sqrLenU0, area;
- };
-
-
-
-
- void RemoveCollinearPoints(std::vector<Vector2<ComputeType>>& vertices)
- {
- std::vector<Vector2<ComputeType>> tmpVertices = vertices;
- int const numVertices = static_cast<int>(vertices.size());
- int numNoncollinear = 0;
- Vector2<ComputeType> ePrev = tmpVertices[0] - tmpVertices.back();
- for (int i0 = 0, i1 = 1; i0 < numVertices; ++i0)
- {
- Vector2<ComputeType> eNext = tmpVertices[i1] - tmpVertices[i0];
- ComputeType dp = DotPerp(ePrev, eNext);
- if (dp != mZero)
- {
- vertices[numNoncollinear++] = tmpVertices[i0];
- }
- ePrev = eNext;
- if (++i1 == numVertices)
- {
- i1 = 0;
- }
- }
- vertices.resize(numNoncollinear);
- }
-
- Box ComputeBoxForEdgeOrderNSqr(std::vector<Vector2<ComputeType>> const& vertices)
- {
- Box minBox;
- minBox.area = mNegOne;
- int const numIndices = static_cast<int>(vertices.size());
- for (int i0 = numIndices - 1, i1 = 0; i1 < numIndices; i0 = i1++)
- {
- Box box = SmallestBox(i0, i1, vertices);
- if (minBox.area == mNegOne || box.area < minBox.area)
- {
- minBox = box;
- }
- }
- return minBox;
- }
-
- Box ComputeBoxForEdgeOrderN(std::vector<Vector2<ComputeType>> const& vertices)
- {
-
-
-
-
-
-
- std::vector<bool> visited(vertices.size());
- std::fill(visited.begin(), visited.end(), false);
-
-
-
-
-
-
-
-
- Box minBox = SmallestBox((int)vertices.size() - 1, 0, vertices);
- visited[minBox.index[0]] = true;
-
- Box box = minBox;
- for (size_t i = 0; i < vertices.size(); ++i)
- {
- std::array<std::pair<ComputeType, int>, 4> A;
- int numA;
- if (!ComputeAngles(vertices, box, A, numA))
- {
-
- break;
- }
-
- std::array<int, 4> sort = SortAngles(A, numA);
-
-
- if (!UpdateSupport(A, numA, sort, vertices, visited, box))
- {
-
-
- break;
- }
- if (box.area < minBox.area)
- {
- minBox = box;
- }
- }
- return minBox;
- }
-
- Box SmallestBox(int i0, int i1, std::vector<Vector2<ComputeType>> const& vertices)
- {
- Box box;
- box.U[0] = vertices[i1] - vertices[i0];
- box.U[1] = -Perp(box.U[0]);
- box.index = { i1, i1, i1, i1 };
- box.sqrLenU0 = Dot(box.U[0], box.U[0]);
- Vector2<ComputeType> const& origin = vertices[i1];
- Vector2<ComputeType> support[4];
- for (int j = 0; j < 4; ++j)
- {
- support[j] = { mZero, mZero };
- }
- int i = 0;
- for (auto const& vertex : vertices)
- {
- Vector2<ComputeType> diff = vertex - origin;
- Vector2<ComputeType> v = { Dot(box.U[0], diff), Dot(box.U[1], diff) };
-
-
-
-
-
-
- if (v[0] > support[1][0] ||
- (v[0] == support[1][0] && v[1] > support[1][1]))
- {
-
-
- box.index[1] = i;
- support[1] = v;
- }
- if (v[1] > support[2][1] ||
- (v[1] == support[2][1] && v[0] < support[2][0]))
- {
-
-
- box.index[2] = i;
- support[2] = v;
- }
- if (v[0] < support[3][0] ||
- (v[0] == support[3][0] && v[1] < support[3][1]))
- {
-
-
- box.index[3] = i;
- support[3] = v;
- }
- ++i;
- }
-
-
-
- ComputeType scaledWidth = support[1][0] - support[3][0];
- ComputeType scaledHeight = support[2][1];
- box.area = scaledWidth * scaledHeight / box.sqrLenU0;
- return box;
- }
-
-
-
-
- bool ComputeAngles(std::vector<Vector2<ComputeType>> const& vertices,
- Box const& box, std::array<std::pair<ComputeType, int>, 4>& A, int& numA) const
- {
- int const numVertices = static_cast<int>(vertices.size());
- numA = 0;
- for (int k0 = 3, k1 = 0; k1 < 4; k0 = k1++)
- {
- if (box.index[k0] != box.index[k1])
- {
-
-
- Vector2<ComputeType> D = ((k0 & 2) ? -box.U[k0 & 1] : box.U[k0 & 1]);
- int j0 = box.index[k0], j1 = j0 + 1;
- if (j1 == numVertices)
- {
- j1 = 0;
- }
- Vector2<ComputeType> E = vertices[j1] - vertices[j0];
- ComputeType dp = DotPerp(D, E);
- ComputeType esqrlen = Dot(E, E);
- ComputeType sinThetaSqr = (dp * dp) / esqrlen;
- A[numA++] = std::make_pair(sinThetaSqr, k0);
- }
- }
- return numA > 0;
- }
-
-
-
- std::array<int, 4> SortAngles(std::array<std::pair<ComputeType, int>, 4> const& A, int numA) const
- {
- std::array<int, 4> sort = { 0, 1, 2, 3 };
- if (numA > 1)
- {
- if (numA == 2)
- {
- if (A[sort[0]].first > A[sort[1]].first)
- {
- std::swap(sort[0], sort[1]);
- }
- }
- else if (numA == 3)
- {
- if (A[sort[0]].first > A[sort[1]].first)
- {
- std::swap(sort[0], sort[1]);
- }
- if (A[sort[0]].first > A[sort[2]].first)
- {
- std::swap(sort[0], sort[2]);
- }
- if (A[sort[1]].first > A[sort[2]].first)
- {
- std::swap(sort[1], sort[2]);
- }
- }
- else
- {
- if (A[sort[0]].first > A[sort[1]].first)
- {
- std::swap(sort[0], sort[1]);
- }
- if (A[sort[2]].first > A[sort[3]].first)
- {
- std::swap(sort[2], sort[3]);
- }
- if (A[sort[0]].first > A[sort[2]].first)
- {
- std::swap(sort[0], sort[2]);
- }
- if (A[sort[1]].first > A[sort[3]].first)
- {
- std::swap(sort[1], sort[3]);
- }
- if (A[sort[1]].first > A[sort[2]].first)
- {
- std::swap(sort[1], sort[2]);
- }
- }
- }
- return sort;
- }
- bool UpdateSupport(std::array<std::pair<ComputeType, int>, 4> const& A,
- int numA, std::array<int, 4> const& sort,
- std::vector<Vector2<ComputeType>> const& vertices,
- std::vector<bool>& visited, Box& box)
- {
-
-
- int const numVertices = static_cast<int>(vertices.size());
- auto const& amin = A[sort[0]];
- for (int k = 0; k < numA; ++k)
- {
- auto const& a = A[sort[k]];
- if (a.first == amin.first)
- {
- if (++box.index[a.second] == numVertices)
- {
- box.index[a.second] = 0;
- }
- }
- else
- {
- break;
- }
- }
- int bottom = box.index[amin.second];
- if (visited[bottom])
- {
-
- return false;
- }
- visited[bottom] = true;
-
- std::array<int, 4> nextIndex;
- for (int k = 0; k < 4; ++k)
- {
- nextIndex[k] = box.index[(amin.second + k) % 4];
- }
- box.index = nextIndex;
-
- int j1 = box.index[0], j0 = j1 - 1;
- if (j0 < 0)
- {
- j0 = numVertices - 1;
- }
- box.U[0] = vertices[j1] - vertices[j0];
- box.U[1] = -Perp(box.U[0]);
- box.sqrLenU0 = Dot(box.U[0], box.U[0]);
-
- Vector2<ComputeType> diff[2] =
- {
- vertices[box.index[1]] - vertices[box.index[3]],
- vertices[box.index[2]] - vertices[box.index[0]]
- };
- box.area = Dot(box.U[0], diff[0]) * Dot(box.U[1], diff[1]) / box.sqrLenU0;
- return true;
- }
-
-
-
- void ConvertTo(Box const& minBox,
- std::vector<Vector2<ComputeType>> const& computePoints,
- OrientedBox2<InputType>& itMinBox)
- {
-
- Vector2<ComputeType> sum[2] =
- {
- computePoints[minBox.index[1]] + computePoints[minBox.index[3]],
- computePoints[minBox.index[2]] + computePoints[minBox.index[0]]
- };
- Vector2<ComputeType> difference[2] =
- {
- computePoints[minBox.index[1]] - computePoints[minBox.index[3]],
- computePoints[minBox.index[2]] - computePoints[minBox.index[0]]
- };
- Vector2<ComputeType> center = mHalf * (
- Dot(minBox.U[0], sum[0]) * minBox.U[0] +
- Dot(minBox.U[1], sum[1]) * minBox.U[1]) / minBox.sqrLenU0;
-
-
- Vector2<ComputeType> sqrExtent;
- for (int i = 0; i < 2; ++i)
- {
- sqrExtent[i] = mHalf * Dot(minBox.U[i], difference[i]);
- sqrExtent[i] *= sqrExtent[i];
- sqrExtent[i] /= minBox.sqrLenU0;
- }
- for (int i = 0; i < 2; ++i)
- {
- itMinBox.center[i] = (InputType)center[i];
- itMinBox.extent[i] = std::sqrt((InputType)sqrExtent[i]);
-
-
-
-
- Vector2<ComputeType> const& axis = minBox.U[i];
- ComputeType cmax = std::max(std::fabs(axis[0]), std::fabs(axis[1]));
- ComputeType invCMax = mOne / cmax;
- for (int j = 0; j < 2; ++j)
- {
- itMinBox.axis[i][j] = (InputType)(axis[j] * invCMax);
- }
- Normalize(itMinBox.axis[i]);
- }
- mSupportIndices = minBox.index;
- mArea = (InputType)minBox.area;
- }
-
- int mNumPoints;
- Vector2<InputType> const* mPoints;
-
-
- std::vector<int> mHull;
-
- std::array<int, 4> mSupportIndices;
-
-
-
-
- InputType mArea;
-
-
- ComputeType mZero, mOne, mNegOne, mHalf;
- };
- }
|