123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394 |
- #pragma once
- #include <Mathematics/ETManifoldMesh.h>
- #include <Mathematics/PrimalQuery3.h>
- #include <Mathematics/Line.h>
- #include <Mathematics/Hyperplane.h>
- #include <functional>
- #include <set>
- #include <thread>
- namespace WwiseGTE
- {
- template <typename InputType, typename ComputeType>
- class ConvexHull3
- {
- public:
-
-
-
-
- ConvexHull3(unsigned int numThreads = 1)
- :
- mEpsilon((InputType)0),
- mDimension(0),
- mLine(Vector3<InputType>::Zero(), Vector3<InputType>::Zero()),
- mPlane(Vector3<InputType>::Zero(), (InputType)0),
- mNumPoints(0),
- mNumUniquePoints(0),
- mPoints(nullptr),
- mNumThreads(numThreads)
- {
- }
-
-
-
-
-
- bool operator()(int numPoints, Vector3<InputType> const* points, InputType epsilon)
- {
- mEpsilon = std::max(epsilon, (InputType)0);
- mDimension = 0;
- mLine.origin = Vector3<InputType>::Zero();
- mLine.direction = Vector3<InputType>::Zero();
- mPlane.normal = Vector3<InputType>::Zero();
- mPlane.constant = (InputType)0;
- mNumPoints = numPoints;
- mNumUniquePoints = 0;
- mPoints = points;
- mHullUnordered.clear();
- mHullMesh.Clear();
- int i, j;
- if (mNumPoints < 4)
- {
-
- return false;
- }
- IntrinsicsVector3<InputType> info(mNumPoints, mPoints, mEpsilon);
- if (info.dimension == 0)
- {
-
- return false;
- }
- if (info.dimension == 1)
- {
-
- mDimension = 1;
- mLine = Line3<InputType>(info.origin, info.direction[0]);
- return false;
- }
- if (info.dimension == 2)
- {
-
- mDimension = 2;
- mPlane = Plane3<InputType>(UnitCross(info.direction[0],
- info.direction[1]), info.origin);
- return false;
- }
- mDimension = 3;
-
- mComputePoints.resize(mNumPoints);
- mQuery.Set(mNumPoints, &mComputePoints[0]);
- for (i = 0; i < mNumPoints; ++i)
- {
- for (j = 0; j < 3; ++j)
- {
- mComputePoints[i][j] = points[i][j];
- }
- }
-
-
- if (!info.extremeCCW)
- {
- std::swap(info.extreme[2], info.extreme[3]);
- }
- mHullUnordered.push_back(TriangleKey<true>(info.extreme[1],
- info.extreme[2], info.extreme[3]));
- mHullUnordered.push_back(TriangleKey<true>(info.extreme[0],
- info.extreme[3], info.extreme[2]));
- mHullUnordered.push_back(TriangleKey<true>(info.extreme[0],
- info.extreme[1], info.extreme[3]));
- mHullUnordered.push_back(TriangleKey<true>(info.extreme[0],
- info.extreme[2], info.extreme[1]));
-
-
-
- std::set<Vector3<InputType>> processed;
- for (i = 0; i < 4; ++i)
- {
- processed.insert(points[info.extreme[i]]);
- }
- for (i = 0; i < mNumPoints; ++i)
- {
- if (processed.find(points[i]) == processed.end())
- {
- Update(i);
- processed.insert(points[i]);
- }
- }
- mNumUniquePoints = static_cast<int>(processed.size());
- return true;
- }
-
-
-
-
-
-
-
-
- inline InputType GetEpsilon() const
- {
- return mEpsilon;
- }
- inline int GetDimension() const
- {
- return mDimension;
- }
- inline Line3<InputType> const& GetLine() const
- {
- return mLine;
- }
- inline Plane3<InputType> const& GetPlane() const
- {
- return mPlane;
- }
-
- inline int GetNumPoints() const
- {
- return mNumPoints;
- }
- inline int GetNumUniquePoints() const
- {
- return mNumUniquePoints;
- }
- inline Vector3<InputType> const* GetPoints() const
- {
- return mPoints;
- }
- inline PrimalQuery3<ComputeType> const& GetQuery() const
- {
- return mQuery;
- }
-
- inline std::vector<TriangleKey<true>> const& GetHullUnordered() const
- {
- return mHullUnordered;
- }
- ETManifoldMesh const& GetHullMesh() const
- {
-
- if (mHullMesh.GetTriangles().size() == 0)
- {
- for (auto const& tri : mHullUnordered)
- {
- mHullMesh.Insert(tri.V[0], tri.V[1], tri.V[2]);
- }
- }
- return mHullMesh;
- }
- private:
-
- void Update(int i)
- {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- unsigned int numFaces = static_cast<unsigned int>(mHullUnordered.size());
- std::vector<int> queryResult(numFaces);
- if (mNumThreads > 1 && numFaces >= mNumThreads)
- {
-
- unsigned int numFacesPerThread = numFaces / mNumThreads;
- std::vector<unsigned int> jmin(mNumThreads), jmax(mNumThreads);
- for (unsigned int t = 0; t < mNumThreads; ++t)
- {
- jmin[t] = t * numFacesPerThread;
- jmax[t] = jmin[t] + numFacesPerThread - 1;
- }
- jmax[mNumThreads - 1] = numFaces - 1;
-
- std::vector<std::thread> process(mNumThreads);
- for (unsigned int t = 0; t < mNumThreads; ++t)
- {
- process[t] = std::thread([this, i, t, &jmin, &jmax,
- &queryResult]()
- {
- for (unsigned int j = jmin[t]; j <= jmax[t]; ++j)
- {
- TriangleKey<true> const& tri = mHullUnordered[j];
- queryResult[j] = mQuery.ToPlane(i, tri.V[0], tri.V[1], tri.V[2]);
- }
- });
- }
-
- for (unsigned int t = 0; t < mNumThreads; ++t)
- {
- process[t].join();
- }
- }
- else
- {
- unsigned int j = 0;
- for (auto const& tri : mHullUnordered)
- {
- queryResult[j++] = mQuery.ToPlane(i, tri.V[0], tri.V[1], tri.V[2]);
- }
- }
- std::map<EdgeKey<false>, std::pair<int, int>> terminator;
- std::vector<TriangleKey<true>> backFaces;
- bool existsFrontFacingTriangle = false;
- unsigned int j = 0;
- for (auto const& tri : mHullUnordered)
- {
- if (queryResult[j++] <= 0)
- {
-
-
- backFaces.push_back(tri);
-
-
-
-
-
-
-
-
-
- for (int j0 = 2, j1 = 0; j1 < 3; j0 = j1++)
- {
- int v0 = tri.V[j0], v1 = tri.V[j1];
- EdgeKey<false> edge(v0, v1);
- auto iter = terminator.find(edge);
- if (iter == terminator.end())
- {
-
- terminator.insert(std::make_pair(edge, std::make_pair(v0, v1)));
- }
- else
- {
-
- terminator.erase(edge);
- }
- }
- }
- else
- {
-
-
-
-
- existsFrontFacingTriangle = true;
- }
- }
- if (!existsFrontFacingTriangle)
- {
-
-
- return;
- }
-
-
- mHullUnordered = backFaces;
-
-
- for (auto const& edge : terminator)
- {
- mHullUnordered.push_back(TriangleKey<true>(i, edge.second.second, edge.second.first));
- }
- }
-
-
-
-
-
-
-
-
-
-
- InputType mEpsilon;
- int mDimension;
- Line3<InputType> mLine;
- Plane3<InputType> mPlane;
-
-
- std::vector<Vector3<ComputeType>> mComputePoints;
- PrimalQuery3<ComputeType> mQuery;
- int mNumPoints;
- int mNumUniquePoints;
- Vector3<InputType> const* mPoints;
- std::vector<TriangleKey<true>> mHullUnordered;
- mutable ETManifoldMesh mHullMesh;
- unsigned int mNumThreads;
- };
- }
|